1 /* 2 * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2013, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include "SymbolLookup.h" 8 9 #include <stdlib.h> 10 #include <string.h> 11 #include <unistd.h> 12 13 #include <new> 14 15 #include <runtime_loader.h> 16 #include <syscalls.h> 17 18 #include "Image.h" 19 20 21 #undef TRACE 22 //#define TRACE_DEBUG_SYMBOL_LOOKUP 23 #ifdef TRACE_DEBUG_SYMBOL_LOOKUP 24 # define TRACE(x) printf x 25 #else 26 # define TRACE(x) ; 27 #endif 28 29 30 using namespace BPrivate::Debug; 31 32 33 // PrepareAddress 34 const void * 35 Area::PrepareAddress(const void *address) 36 { 37 TRACE(("Area::PrepareAddress(%p): area: %" B_PRId32 "\n", address, fRemoteID)); 38 39 // clone the area, if not done already 40 if (fLocalID < 0) { 41 fLocalID = clone_area("cloned area", &fLocalAddress, B_ANY_ADDRESS, 42 B_READ_AREA, fRemoteID); 43 if (fLocalID < 0) { 44 TRACE(("Area::PrepareAddress(): Failed to clone area %" B_PRId32 45 ": %s\n", fRemoteID, strerror(fLocalID))); 46 throw Exception(fLocalID); 47 } 48 } 49 50 // translate the address 51 const void *result = (const void*)((addr_t)address - (addr_t)fRemoteAddress 52 + (addr_t)fLocalAddress); 53 54 TRACE(("Area::PrepareAddress(%p) done: %p\n", address, result)); 55 56 return result; 57 } 58 59 60 // #pragma mark - 61 62 // constructor 63 RemoteMemoryAccessor::RemoteMemoryAccessor(team_id team) 64 : fTeam(team), 65 fAreas() 66 { 67 } 68 69 // destructor 70 RemoteMemoryAccessor::~RemoteMemoryAccessor() 71 { 72 // delete the areas 73 while (Area *area = fAreas.Head()) { 74 fAreas.Remove(area); 75 delete area; 76 } 77 } 78 79 // Init 80 status_t 81 RemoteMemoryAccessor::Init() 82 { 83 // If the team is the kernel team, we don't try to clone the areas. Only 84 // SymbolLookup's image file functionality will be available. 85 if (fTeam == B_SYSTEM_TEAM) 86 return B_OK; 87 88 // get a list of the team's areas 89 area_info areaInfo; 90 ssize_t cookie = 0; 91 status_t error; 92 while ((error = get_next_area_info(fTeam, &cookie, &areaInfo)) == B_OK) { 93 TRACE(("area %" B_PRId32 ": address: %p, size: %ld, name: %s\n", 94 areaInfo.area, areaInfo.address, areaInfo.size, areaInfo.name)); 95 96 Area *area = new(std::nothrow) Area(areaInfo.area, areaInfo.address, 97 areaInfo.size); 98 if (!area) 99 return B_NO_MEMORY; 100 101 fAreas.Add(area); 102 } 103 104 if (fAreas.IsEmpty()) 105 return error; 106 107 return B_OK; 108 } 109 110 // PrepareAddress 111 const void * 112 RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress, 113 int32 size) const 114 { 115 TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %" B_PRId32 ")\n", 116 remoteAddress, size)); 117 118 if (!remoteAddress) { 119 TRACE(("RemoteMemoryAccessor::PrepareAddress(): Got null address!\n")); 120 throw Exception(B_BAD_VALUE); 121 } 122 123 return _FindArea(remoteAddress, size).PrepareAddress(remoteAddress); 124 } 125 126 127 const void * 128 RemoteMemoryAccessor::PrepareAddressNoThrow(const void *remoteAddress, 129 int32 size) const 130 { 131 if (remoteAddress == NULL) 132 return NULL; 133 134 Area* area = _FindAreaNoThrow(remoteAddress, size); 135 if (area == NULL) 136 return NULL; 137 138 return area->PrepareAddress(remoteAddress); 139 } 140 141 142 // AreaForLocalAddress 143 Area* 144 RemoteMemoryAccessor::AreaForLocalAddress(const void* address) const 145 { 146 if (address == NULL) 147 return NULL; 148 149 for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) { 150 Area* area = it.Next(); 151 if (area->ContainsLocalAddress(address)) 152 return area; 153 } 154 155 return NULL; 156 } 157 158 159 // _FindArea 160 Area & 161 RemoteMemoryAccessor::_FindArea(const void *address, int32 size) const 162 { 163 TRACE(("RemoteMemoryAccessor::_FindArea(%p, %" B_PRId32 ")\n", address, 164 size)); 165 166 for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) { 167 Area *area = it.Next(); 168 if (area->ContainsAddress(address, size)) 169 return *area; 170 } 171 172 TRACE(("RemoteMemoryAccessor::_FindArea(): No area found for address %p\n", 173 address)); 174 throw Exception(B_ENTRY_NOT_FOUND); 175 } 176 177 178 // _FindAreaNoThrow 179 Area* 180 RemoteMemoryAccessor::_FindAreaNoThrow(const void *address, int32 size) const 181 { 182 for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) { 183 Area *area = it.Next(); 184 if (area->ContainsAddress(address, size)) 185 return area; 186 } 187 188 return NULL; 189 } 190 191 192 // #pragma mark - 193 194 195 class SymbolLookup::LoadedImage : public Image { 196 public: 197 LoadedImage(SymbolLookup* symbolLookup, 198 const image_t* image, int32 symbolCount); 199 virtual ~LoadedImage(); 200 201 virtual const elf_sym* LookupSymbol(addr_t address, 202 addr_t* _baseAddress, 203 const char** _symbolName, 204 size_t *_symbolNameLen, 205 bool *_exactMatch) const; 206 virtual status_t NextSymbol(int32& iterator, 207 const char** _symbolName, 208 size_t* _symbolNameLen, 209 addr_t* _symbolAddress, size_t* _symbolSize, 210 int32* _symbolType) const; 211 212 private: 213 SymbolLookup* fSymbolLookup; 214 const image_t* fImage; 215 int32 fSymbolCount; 216 size_t fTextDelta; 217 }; 218 219 220 // #pragma mark - 221 222 223 // constructor 224 SymbolLookup::SymbolLookup(team_id team, image_id image) 225 : 226 RemoteMemoryAccessor(team), 227 fDebugArea(NULL), 228 fImages(), 229 fImageID(image) 230 { 231 } 232 233 234 // destructor 235 SymbolLookup::~SymbolLookup() 236 { 237 while (Image* image = fImages.RemoveHead()) 238 delete image; 239 } 240 241 242 // Init 243 status_t 244 SymbolLookup::Init() 245 { 246 TRACE(("SymbolLookup::Init()\n")); 247 248 status_t error = RemoteMemoryAccessor::Init(); 249 if (error != B_OK) 250 return error; 251 252 if (fTeam != B_SYSTEM_TEAM) { 253 TRACE(("SymbolLookup::Init(): searching debug area...\n")); 254 255 // find the runtime loader debug area 256 runtime_loader_debug_area *remoteDebugArea = NULL; 257 ssize_t cookie = 0; 258 area_info areaInfo; 259 while (get_next_area_info(fTeam, &cookie, &areaInfo) == B_OK) { 260 if (strcmp(areaInfo.name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0) { 261 remoteDebugArea = (runtime_loader_debug_area*)areaInfo.address; 262 break; 263 } 264 } 265 266 if (remoteDebugArea) { 267 TRACE(("SymbolLookup::Init(): found debug area, translating " 268 "address...\n")); 269 } else { 270 TRACE(("SymbolLookup::Init(): Couldn't find debug area!\n")); 271 } 272 273 // translate the address 274 try { 275 if (remoteDebugArea != NULL) { 276 fDebugArea = &Read(*remoteDebugArea); 277 278 TRACE(("SymbolLookup::Init(): translated debug area is at: %p, " 279 "loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images)); 280 } 281 } catch (Exception& exception) { 282 // we can live without the debug area 283 } 284 } 285 286 image_info imageInfo; 287 if (fImageID < 0) { 288 // create a list of the team's images 289 int32 cookie = 0; 290 while (get_next_image_info(fTeam, &cookie, &imageInfo) == B_OK) { 291 error = _LoadImageInfo(imageInfo); 292 if (error != B_OK) 293 return error; 294 } 295 } else { 296 error = get_image_info(fImageID, &imageInfo); 297 if (error != B_OK) 298 return error; 299 300 error = _LoadImageInfo(imageInfo); 301 if (error != B_OK) 302 return error; 303 } 304 305 return B_OK; 306 } 307 308 309 // LookupSymbolAddress 310 status_t 311 SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress, 312 const char **_symbolName, size_t *_symbolNameLen, const char **_imageName, 313 bool *_exactMatch) const 314 { 315 TRACE(("SymbolLookup::LookupSymbolAddress(%p)\n", (void*)address)); 316 317 Image* image = _FindImageAtAddress(address); 318 if (!image) 319 return B_ENTRY_NOT_FOUND; 320 321 if (_imageName != NULL) 322 *_imageName = image->Name(); 323 324 const elf_sym* symbolFound = image->LookupSymbol(address, _baseAddress, 325 _symbolName, _symbolNameLen, _exactMatch); 326 327 TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: " 328 "%s, exact match: %d\n", symbolFound, image->name, exactMatch)); 329 330 if (symbolFound != NULL) 331 return B_OK; 332 333 // symbol not found -- return the image itself 334 335 if (_baseAddress) 336 *_baseAddress = image->TextAddress(); 337 338 if (_imageName) 339 *_imageName = image->Name(); 340 341 if (_symbolName) 342 *_symbolName = NULL; 343 344 if (_exactMatch) 345 *_exactMatch = false; 346 347 if (_symbolNameLen != NULL) 348 *_symbolNameLen = 0; 349 350 return B_OK; 351 } 352 353 354 // InitSymbolIterator 355 status_t 356 SymbolLookup::InitSymbolIterator(image_id imageID, 357 SymbolIterator& iterator) const 358 { 359 TRACE(("SymbolLookup::InitSymbolIterator(): image ID: %" B_PRId32 "\n", 360 imageID)); 361 362 // find the image 363 iterator.image = _FindImageByID(imageID); 364 365 // If that didn't work, find the loaded image. 366 if (iterator.image == NULL) { 367 TRACE(("SymbolLookup::InitSymbolIterator() done: image not " 368 "found\n")); 369 return B_ENTRY_NOT_FOUND; 370 } 371 372 iterator.currentIndex = -1; 373 374 return B_OK; 375 } 376 377 378 // InitSymbolIterator 379 status_t 380 SymbolLookup::InitSymbolIteratorByAddress(addr_t address, 381 SymbolIterator& iterator) const 382 { 383 TRACE(("SymbolLookup::InitSymbolIteratorByAddress(): base address: %#lx\n", 384 address)); 385 386 // find the image 387 iterator.image = _FindImageAtAddress(address); 388 if (iterator.image == NULL) { 389 TRACE(("SymbolLookup::InitSymbolIteratorByAddress() done: image " 390 "not found\n")); 391 return B_ENTRY_NOT_FOUND; 392 } 393 394 iterator.currentIndex = -1; 395 396 return B_OK; 397 } 398 399 400 // NextSymbol 401 status_t 402 SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName, 403 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize, 404 int32* _symbolType) const 405 { 406 return iterator.image->NextSymbol(iterator.currentIndex, _symbolName, 407 _symbolNameLen, _symbolAddress, _symbolSize, _symbolType); 408 } 409 410 411 // GetSymbol 412 status_t 413 SymbolLookup::GetSymbol(image_id imageID, const char* name, int32 symbolType, 414 void** _symbolLocation, size_t* _symbolSize, int32* _symbolType) const 415 { 416 Image* image = _FindImageByID(imageID); 417 if (image == NULL) 418 return B_ENTRY_NOT_FOUND; 419 420 return image->GetSymbol(name, symbolType, _symbolLocation, _symbolSize, 421 _symbolType); 422 } 423 424 425 // _FindLoadedImageAtAddress 426 const image_t * 427 SymbolLookup::_FindLoadedImageAtAddress(addr_t address) const 428 { 429 TRACE(("SymbolLookup::_FindLoadedImageAtAddress(%p)\n", (void*)address)); 430 431 if (fDebugArea == NULL) 432 return NULL; 433 434 // iterate through the loaded images 435 for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head)); 436 image; 437 image = &Read(*image->next)) { 438 if (image->regions[0].vmstart <= address 439 && address < image->regions[0].vmstart + image->regions[0].size) { 440 return image; 441 } 442 } 443 444 return NULL; 445 } 446 447 448 // _FindLoadedImageByID 449 const image_t* 450 SymbolLookup::_FindLoadedImageByID(image_id id) const 451 { 452 if (fDebugArea == NULL) 453 return NULL; 454 455 // iterate through the images 456 for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head)); 457 image; 458 image = &Read(*image->next)) { 459 if (image->id == id) 460 return image; 461 } 462 463 return NULL; 464 } 465 466 467 // _FindImageAtAddress 468 Image* 469 SymbolLookup::_FindImageAtAddress(addr_t address) const 470 { 471 DoublyLinkedList<Image>::ConstIterator it = fImages.GetIterator(); 472 while (Image* image = it.Next()) { 473 addr_t textAddress = image->TextAddress(); 474 if (address >= textAddress && address < textAddress + image->TextSize()) 475 return image; 476 } 477 478 return NULL; 479 } 480 481 482 // _FindImageByID 483 Image* 484 SymbolLookup::_FindImageByID(image_id id) const 485 { 486 DoublyLinkedList<Image>::ConstIterator it = fImages.GetIterator(); 487 while (Image* image = it.Next()) { 488 if (image->ID() == id) 489 return image; 490 } 491 492 return NULL; 493 } 494 495 496 // _SymbolNameLen 497 size_t 498 SymbolLookup::_SymbolNameLen(const char* address) const 499 { 500 Area* area = AreaForLocalAddress(address); 501 if (area == NULL) 502 return 0; 503 504 return strnlen(address, (addr_t)area->LocalAddress() + area->Size() 505 - (addr_t)address); 506 } 507 508 509 status_t 510 SymbolLookup::_LoadImageInfo(const image_info& imageInfo) 511 { 512 status_t error = B_OK; 513 514 Image* image; 515 if (fTeam == B_SYSTEM_TEAM) { 516 // kernel image 517 KernelImage* kernelImage = new(std::nothrow) KernelImage; 518 if (kernelImage == NULL) 519 return B_NO_MEMORY; 520 521 error = kernelImage->Init(imageInfo); 522 image = kernelImage; 523 } else if (!strcmp("commpage", imageInfo.name)) { 524 // commpage image 525 CommPageImage* commPageImage = new(std::nothrow) CommPageImage; 526 if (commPageImage == NULL) 527 return B_NO_MEMORY; 528 529 error = commPageImage->Init(imageInfo); 530 image = commPageImage; 531 } else { 532 // userland image -- try to load an image file 533 ImageFile* imageFile = new(std::nothrow) ImageFile; 534 if (imageFile == NULL) 535 return B_NO_MEMORY; 536 537 error = imageFile->Init(imageInfo); 538 image = imageFile; 539 } 540 541 if (error != B_OK) { 542 // initialization error -- fall back to the loaded image 543 delete image; 544 545 const image_t* loadedImage = _FindLoadedImageByID(imageInfo.id); 546 if (loadedImage == NULL) 547 return B_OK; 548 549 image = new(std::nothrow) LoadedImage(this, loadedImage, 550 Read(loadedImage->symhash[1])); 551 if (image == NULL) 552 return B_NO_MEMORY; 553 554 } 555 556 fImages.Add(image); 557 558 return B_OK; 559 } 560 561 // #pragma mark - LoadedImage 562 563 564 SymbolLookup::LoadedImage::LoadedImage(SymbolLookup* symbolLookup, 565 const image_t* image, int32 symbolCount) 566 : 567 fSymbolLookup(symbolLookup), 568 fImage(image), 569 fSymbolCount(symbolCount), 570 fTextDelta(image->regions[0].delta) 571 { 572 // init info 573 fInfo.id = fImage->id; 574 fInfo.type = fImage->type; 575 fInfo.sequence = 0; 576 fInfo.init_order = 0; 577 fInfo.init_routine = (void (*)())fImage->init_routine; 578 fInfo.term_routine = (void (*)())fImage->term_routine; 579 fInfo.device = -1; 580 fInfo.node = -1; 581 strlcpy(fInfo.name, fImage->path, sizeof(fInfo.name)); 582 fInfo.text = (void*)fImage->regions[0].vmstart; 583 fInfo.data = (void*)fImage->regions[1].vmstart; 584 fInfo.text_size = fImage->regions[0].vmsize; 585 fInfo.data_size = fImage->regions[1].vmsize; 586 } 587 588 589 SymbolLookup::LoadedImage::~LoadedImage() 590 { 591 } 592 593 594 const elf_sym* 595 SymbolLookup::LoadedImage::LookupSymbol(addr_t address, addr_t* _baseAddress, 596 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const 597 { 598 TRACE(("LoadedImage::LookupSymbol(): found image: ID: %" B_PRId32 ", text: " 599 "address: %p, size: %ld\n", fImage->id, 600 (void*)fImage->regions[0].vmstart, fImage->regions[0].size)); 601 602 // search the image for the symbol 603 const elf_sym *symbolFound = NULL; 604 addr_t deltaFound = INT_MAX; 605 bool exactMatch = false; 606 const char *symbolName = NULL; 607 608 int32 symbolCount = fSymbolLookup->Read(fImage->symhash[1]); 609 const elf_region_t *textRegion = fImage->regions; // local 610 611 for (int32 i = 0; i < symbolCount; i++) { 612 const elf_sym *symbol = &fSymbolLookup->Read(fImage->syms[i]); 613 614 // The symbol table contains not only symbols referring to functions 615 // and data symbols within the shared object, but also referenced 616 // symbols of other shared objects, as well as section and file 617 // references. We ignore everything but function and data symbols 618 // that have an st_value != 0 (0 seems to be an indication for a 619 // symbol defined elsewhere -- couldn't verify that in the specs 620 // though). 621 if ((symbol->Type() != STT_FUNC && symbol->Type() != STT_OBJECT) 622 || symbol->st_value == 0 623 || symbol->st_value + symbol->st_size + textRegion->delta 624 > textRegion->vmstart + textRegion->size) { 625 continue; 626 } 627 628 // skip symbols starting after the given address 629 addr_t symbolAddress = symbol->st_value + textRegion->delta; 630 631 if (symbolAddress > address) 632 continue; 633 addr_t symbolDelta = address - symbolAddress; 634 635 if (!symbolFound || symbolDelta < deltaFound) { 636 symbolName = (const char*)fSymbolLookup->PrepareAddressNoThrow( 637 SYMNAME(fImage, symbol), 1); 638 if (symbolName == NULL) 639 continue; 640 641 deltaFound = symbolDelta; 642 symbolFound = symbol; 643 644 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) { 645 // exact match 646 exactMatch = true; 647 break; 648 } 649 } 650 } 651 652 TRACE(("LoadedImage::LookupSymbol(): done: symbol: %p, image name: " 653 "%s, exact match: %d\n", symbolFound, fImage->name, exactMatch)); 654 655 if (symbolFound != NULL) { 656 if (_baseAddress) 657 *_baseAddress = symbolFound->st_value + textRegion->delta; 658 if (_symbolName) 659 *_symbolName = symbolName; 660 if (_exactMatch) 661 *_exactMatch = exactMatch; 662 if (_symbolNameLen != NULL) 663 *_symbolNameLen = fSymbolLookup->_SymbolNameLen(symbolName); 664 } 665 666 return symbolFound; 667 } 668 669 670 status_t 671 SymbolLookup::LoadedImage::NextSymbol(int32& iterator, const char** _symbolName, 672 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize, 673 int32* _symbolType) const 674 { 675 while (true) { 676 if (++iterator >= fSymbolCount) 677 return B_ENTRY_NOT_FOUND; 678 679 const elf_sym* symbol 680 = &fSymbolLookup->Read(fImage->syms[iterator]); 681 if ((symbol->Type() != STT_FUNC && symbol->Type() != STT_OBJECT) 682 || symbol->st_value == 0) { 683 continue; 684 } 685 686 *_symbolName = (const char*)fSymbolLookup->PrepareAddressNoThrow( 687 SYMNAME(fImage, symbol), 1); 688 *_symbolNameLen = fSymbolLookup->_SymbolNameLen(*_symbolName); 689 *_symbolAddress = symbol->st_value + fTextDelta; 690 *_symbolSize = symbol->st_size; 691 *_symbolType = symbol->Type() == STT_FUNC ? B_SYMBOL_TYPE_TEXT 692 : B_SYMBOL_TYPE_DATA; 693 694 return B_OK; 695 } 696 } 697