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