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: %ld\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 %ld: %s\n", 44 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 int32 cookie = 0; 90 status_t error; 91 while ((error = get_next_area_info(fTeam, &cookie, &areaInfo)) == B_OK) { 92 TRACE(("area %ld: address: %p, size: %ld, name: %s\n", areaInfo.area, 93 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, %ld)\n", remoteAddress, 115 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, %ld)\n", address, size)); 163 164 for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) { 165 Area *area = it.Next(); 166 if (area->ContainsAddress(address, size)) 167 return *area; 168 } 169 170 TRACE(("RemoteMemoryAccessor::_FindArea(): No area found for address %p\n", 171 address)); 172 throw Exception(B_ENTRY_NOT_FOUND); 173 } 174 175 176 // _FindAreaNoThrow 177 Area* 178 RemoteMemoryAccessor::_FindAreaNoThrow(const void *address, int32 size) const 179 { 180 for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) { 181 Area *area = it.Next(); 182 if (area->ContainsAddress(address, size)) 183 return area; 184 } 185 186 return NULL; 187 } 188 189 190 // #pragma mark - 191 192 193 class SymbolLookup::LoadedImage : public Image { 194 public: 195 LoadedImage(SymbolLookup* symbolLookup, 196 const image_t* image, int32 symbolCount); 197 virtual ~LoadedImage(); 198 199 virtual const Elf32_Sym* LookupSymbol(addr_t address, 200 addr_t* _baseAddress, 201 const char** _symbolName, 202 size_t *_symbolNameLen, 203 bool *_exactMatch) const; 204 virtual status_t NextSymbol(int32& iterator, 205 const char** _symbolName, 206 size_t* _symbolNameLen, 207 addr_t* _symbolAddress, size_t* _symbolSize, 208 int32* _symbolType) const; 209 210 private: 211 SymbolLookup* fSymbolLookup; 212 const image_t* fImage; 213 int32 fSymbolCount; 214 size_t fTextDelta; 215 }; 216 217 218 // #pragma mark - 219 220 221 // constructor 222 SymbolLookup::SymbolLookup(team_id team) 223 : 224 RemoteMemoryAccessor(team), 225 fDebugArea(NULL), 226 fImages() 227 { 228 } 229 230 231 // destructor 232 SymbolLookup::~SymbolLookup() 233 { 234 while (Image* image = fImages.RemoveHead()) 235 delete image; 236 } 237 238 239 // Init 240 status_t 241 SymbolLookup::Init() 242 { 243 TRACE(("SymbolLookup::Init()\n")); 244 245 status_t error = RemoteMemoryAccessor::Init(); 246 if (error != B_OK) 247 return error; 248 249 if (fTeam != B_SYSTEM_TEAM) { 250 TRACE(("SymbolLookup::Init(): searching debug area...\n")); 251 252 // find the runtime loader debug area 253 runtime_loader_debug_area *remoteDebugArea = NULL; 254 int32 cookie = 0; 255 area_info areaInfo; 256 while (get_next_area_info(fTeam, &cookie, &areaInfo) == B_OK) { 257 if (strcmp(areaInfo.name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0) { 258 remoteDebugArea = (runtime_loader_debug_area*)areaInfo.address; 259 break; 260 } 261 } 262 263 if (remoteDebugArea) { 264 TRACE(("SymbolLookup::Init(): found debug area, translating " 265 "address...\n")); 266 } else { 267 TRACE(("SymbolLookup::Init(): Couldn't find debug area!\n")); 268 } 269 270 // translate the address 271 try { 272 if (remoteDebugArea != NULL) { 273 fDebugArea = &Read(*remoteDebugArea); 274 275 TRACE(("SymbolLookup::Init(): translated debug area is at: %p, " 276 "loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images)); 277 } 278 } catch (Exception exception) { 279 // we can live without the debug area 280 } 281 } 282 283 // create a list of the team's images 284 image_info imageInfo; 285 int32 cookie = 0; 286 while (get_next_image_info(fTeam, &cookie, &imageInfo) == B_OK) { 287 Image* image; 288 289 if (fTeam == B_SYSTEM_TEAM) { 290 // kernel image 291 KernelImage* kernelImage = new(std::nothrow) KernelImage; 292 if (kernelImage == NULL) 293 return B_NO_MEMORY; 294 295 error = kernelImage->Init(imageInfo); 296 image = kernelImage; 297 } else { 298 // userland image -- try to load an image file 299 ImageFile* imageFile = new(std::nothrow) ImageFile; 300 if (imageFile == NULL) 301 return B_NO_MEMORY; 302 303 error = imageFile->Init(imageInfo); 304 image = imageFile; 305 } 306 307 if (error != B_OK) { 308 // initialization error -- fall back to the loaded image 309 delete image; 310 311 const image_t* loadedImage = _FindLoadedImageByID(imageInfo.id); 312 if (loadedImage == NULL) 313 continue; 314 315 image = new(std::nothrow) LoadedImage(this, loadedImage, 316 Read(loadedImage->symhash[1])); 317 if (image == NULL) 318 return B_NO_MEMORY; 319 } 320 321 fImages.Add(image); 322 } 323 324 return B_OK; 325 } 326 327 328 // LookupSymbolAddress 329 status_t 330 SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress, 331 const char **_symbolName, size_t *_symbolNameLen, const char **_imageName, 332 bool *_exactMatch) const 333 { 334 TRACE(("SymbolLookup::LookupSymbolAddress(%p)\n", (void*)address)); 335 336 Image* image = _FindImageAtAddress(address); 337 if (!image) 338 return B_ENTRY_NOT_FOUND; 339 340 if (_imageName != NULL) 341 *_imageName = image->Name(); 342 343 const Elf32_Sym* symbolFound = image->LookupSymbol(address, _baseAddress, 344 _symbolName, _symbolNameLen, _exactMatch); 345 346 TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: " 347 "%s, exact match: %d\n", symbolFound, image->name, exactMatch)); 348 349 if (symbolFound != NULL) 350 return B_OK; 351 352 // symbol not found -- return the image itself 353 354 if (_baseAddress) 355 *_baseAddress = image->TextAddress(); 356 357 if (_imageName) 358 *_imageName = image->Name(); 359 360 if (_symbolName) 361 *_symbolName = NULL; 362 363 if (_exactMatch) 364 *_exactMatch = false; 365 366 if (_symbolNameLen != NULL) 367 *_symbolNameLen = 0; 368 369 return B_OK; 370 } 371 372 373 // InitSymbolIterator 374 status_t 375 SymbolLookup::InitSymbolIterator(image_id imageID, 376 SymbolIterator& iterator) const 377 { 378 TRACE(("SymbolLookup::InitSymbolIterator(): image ID: %ld\n", imageID)); 379 380 // find the image 381 iterator.image = _FindImageByID(imageID); 382 383 // If that didn't work, find the loaded image. 384 if (iterator.image == NULL) { 385 TRACE(("SymbolLookup::InitSymbolIterator() done: image not " 386 "found\n")); 387 return B_ENTRY_NOT_FOUND; 388 } 389 390 iterator.currentIndex = -1; 391 392 return B_OK; 393 } 394 395 396 // InitSymbolIterator 397 status_t 398 SymbolLookup::InitSymbolIteratorByAddress(addr_t address, 399 SymbolIterator& iterator) const 400 { 401 TRACE(("SymbolLookup::InitSymbolIteratorByAddress(): base address: %#lx\n", 402 address)); 403 404 // find the image 405 iterator.image = _FindImageAtAddress(address); 406 if (iterator.image == NULL) { 407 TRACE(("SymbolLookup::InitSymbolIteratorByAddress() done: image " 408 "not found\n")); 409 return B_ENTRY_NOT_FOUND; 410 } 411 412 iterator.currentIndex = -1; 413 414 return B_OK; 415 } 416 417 418 // NextSymbol 419 status_t 420 SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName, 421 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize, 422 int32* _symbolType) const 423 { 424 return iterator.image->NextSymbol(iterator.currentIndex, _symbolName, 425 _symbolNameLen, _symbolAddress, _symbolSize, _symbolType); 426 } 427 428 429 // GetSymbol 430 status_t 431 SymbolLookup::GetSymbol(image_id imageID, const char* name, int32 symbolType, 432 void** _symbolLocation, size_t* _symbolSize, int32* _symbolType) const 433 { 434 Image* image = _FindImageByID(imageID); 435 if (image == NULL) 436 return B_ENTRY_NOT_FOUND; 437 438 return image->GetSymbol(name, symbolType, _symbolLocation, _symbolSize, 439 _symbolType); 440 } 441 442 443 // _FindLoadedImageAtAddress 444 const image_t * 445 SymbolLookup::_FindLoadedImageAtAddress(addr_t address) const 446 { 447 TRACE(("SymbolLookup::_FindLoadedImageAtAddress(%p)\n", (void*)address)); 448 449 if (fDebugArea == NULL) 450 return NULL; 451 452 // iterate through the loaded images 453 for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head)); 454 image; 455 image = &Read(*image->next)) { 456 if (image->regions[0].vmstart <= address 457 && address < image->regions[0].vmstart + image->regions[0].size) { 458 return image; 459 } 460 } 461 462 return NULL; 463 } 464 465 466 // _FindLoadedImageByID 467 const image_t* 468 SymbolLookup::_FindLoadedImageByID(image_id id) const 469 { 470 if (fDebugArea == NULL) 471 return NULL; 472 473 // iterate through the images 474 for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head)); 475 image; 476 image = &Read(*image->next)) { 477 if (image->id == id) 478 return image; 479 } 480 481 return NULL; 482 } 483 484 485 // _FindImageAtAddress 486 Image* 487 SymbolLookup::_FindImageAtAddress(addr_t address) const 488 { 489 DoublyLinkedList<Image>::ConstIterator it = fImages.GetIterator(); 490 while (Image* image = it.Next()) { 491 addr_t textAddress = image->TextAddress(); 492 if (address >= textAddress && address < textAddress + image->TextSize()) 493 return image; 494 } 495 496 return NULL; 497 } 498 499 500 // _FindImageByID 501 Image* 502 SymbolLookup::_FindImageByID(image_id id) const 503 { 504 DoublyLinkedList<Image>::ConstIterator it = fImages.GetIterator(); 505 while (Image* image = it.Next()) { 506 if (image->ID() == id) 507 return image; 508 } 509 510 return NULL; 511 } 512 513 514 // _SymbolNameLen 515 size_t 516 SymbolLookup::_SymbolNameLen(const char* address) const 517 { 518 Area* area = AreaForLocalAddress(address); 519 if (area == NULL) 520 return 0; 521 522 return strnlen(address, (addr_t)area->LocalAddress() + area->Size() 523 - (addr_t)address); 524 } 525 526 527 // #pragma mark - LoadedImage 528 529 530 SymbolLookup::LoadedImage::LoadedImage(SymbolLookup* symbolLookup, 531 const image_t* image, int32 symbolCount) 532 : 533 fSymbolLookup(symbolLookup), 534 fImage(image), 535 fSymbolCount(symbolCount), 536 fTextDelta(image->regions[0].delta) 537 { 538 // init info 539 fInfo.id = fImage->id; 540 fInfo.type = fImage->type; 541 fInfo.sequence = 0; 542 fInfo.init_order = 0; 543 fInfo.init_routine = (void (*)())fImage->init_routine; 544 fInfo.term_routine = (void (*)())fImage->term_routine; 545 fInfo.device = -1; 546 fInfo.node = -1; 547 strlcpy(fInfo.name, fImage->path, sizeof(fInfo.name)); 548 fInfo.text = (void*)fImage->regions[0].vmstart; 549 fInfo.data = (void*)fImage->regions[1].vmstart; 550 fInfo.text_size = fImage->regions[0].vmsize; 551 fInfo.data_size = fImage->regions[1].vmsize; 552 } 553 554 555 SymbolLookup::LoadedImage::~LoadedImage() 556 { 557 } 558 559 560 const Elf32_Sym* 561 SymbolLookup::LoadedImage::LookupSymbol(addr_t address, addr_t* _baseAddress, 562 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const 563 { 564 TRACE(("LoadedImage::LookupSymbol(): found image: ID: %ld, text: " 565 "address: %p, size: %ld\n", fImage->id, 566 (void*)fImage->regions[0].vmstart, fImage->regions[0].size)); 567 568 // search the image for the symbol 569 const struct Elf32_Sym *symbolFound = NULL; 570 addr_t deltaFound = INT_MAX; 571 bool exactMatch = false; 572 const char *symbolName = NULL; 573 574 int32 symbolCount = fSymbolLookup->Read(fImage->symhash[1]); 575 const elf_region_t *textRegion = fImage->regions; // local 576 577 for (int32 i = 0; i < symbolCount; i++) { 578 const struct Elf32_Sym *symbol = &fSymbolLookup->Read(fImage->syms[i]); 579 580 // The symbol table contains not only symbols referring to functions 581 // and data symbols within the shared object, but also referenced 582 // symbols of other shared objects, as well as section and file 583 // references. We ignore everything but function and data symbols 584 // that have an st_value != 0 (0 seems to be an indication for a 585 // symbol defined elsewhere -- couldn't verify that in the specs 586 // though). 587 if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC 588 && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT) 589 || symbol->st_value == 0 590 || symbol->st_value + symbol->st_size + textRegion->delta 591 > textRegion->vmstart + textRegion->size) { 592 continue; 593 } 594 595 // skip symbols starting after the given address 596 addr_t symbolAddress = symbol->st_value + textRegion->delta; 597 598 if (symbolAddress > address) 599 continue; 600 addr_t symbolDelta = address - symbolAddress; 601 602 if (!symbolFound || symbolDelta < deltaFound) { 603 symbolName = (const char*)fSymbolLookup->PrepareAddressNoThrow( 604 SYMNAME(fImage, symbol), 1); 605 if (symbolName == NULL) 606 continue; 607 608 deltaFound = symbolDelta; 609 symbolFound = symbol; 610 611 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) { 612 // exact match 613 exactMatch = true; 614 break; 615 } 616 } 617 } 618 619 TRACE(("LoadedImage::LookupSymbol(): done: symbol: %p, image name: " 620 "%s, exact match: %d\n", symbolFound, fImage->name, exactMatch)); 621 622 if (symbolFound != NULL) { 623 if (_baseAddress) 624 *_baseAddress = symbolFound->st_value + textRegion->delta; 625 if (_symbolName) 626 *_symbolName = symbolName; 627 if (_exactMatch) 628 *_exactMatch = exactMatch; 629 if (_symbolNameLen != NULL) 630 *_symbolNameLen = fSymbolLookup->_SymbolNameLen(symbolName); 631 } 632 633 return symbolFound; 634 } 635 636 637 status_t 638 SymbolLookup::LoadedImage::NextSymbol(int32& iterator, const char** _symbolName, 639 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize, 640 int32* _symbolType) const 641 { 642 while (true) { 643 if (++iterator >= fSymbolCount) 644 return B_ENTRY_NOT_FOUND; 645 646 const struct Elf32_Sym* symbol 647 = &fSymbolLookup->Read(fImage->syms[iterator]); 648 if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC 649 && ELF32_ST_TYPE(symbol->st_info) != 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 = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC 660 ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 661 662 return B_OK; 663 } 664 } 665