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 // _FindLoadedImageAtAddress 430 const image_t * 431 SymbolLookup::_FindLoadedImageAtAddress(addr_t address) const 432 { 433 TRACE(("SymbolLookup::_FindLoadedImageAtAddress(%p)\n", (void*)address)); 434 435 if (fDebugArea == NULL) 436 return NULL; 437 438 // iterate through the loaded images 439 for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head)); 440 image; 441 image = &Read(*image->next)) { 442 if (image->regions[0].vmstart <= address 443 && address < image->regions[0].vmstart + image->regions[0].size) { 444 return image; 445 } 446 } 447 448 return NULL; 449 } 450 451 452 // _FindLoadedImageByID 453 const image_t* 454 SymbolLookup::_FindLoadedImageByID(image_id id) const 455 { 456 if (fDebugArea == NULL) 457 return NULL; 458 459 // iterate through the images 460 for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head)); 461 image; 462 image = &Read(*image->next)) { 463 if (image->id == id) 464 return image; 465 } 466 467 return NULL; 468 } 469 470 471 // _FindImageAtAddress 472 Image* 473 SymbolLookup::_FindImageAtAddress(addr_t address) const 474 { 475 DoublyLinkedList<Image>::ConstIterator it = fImages.GetIterator(); 476 while (Image* image = it.Next()) { 477 addr_t textAddress = image->TextAddress(); 478 if (address >= textAddress && address < textAddress + image->TextSize()) 479 return image; 480 } 481 482 return NULL; 483 } 484 485 486 // _FindImageByID 487 Image* 488 SymbolLookup::_FindImageByID(image_id id) const 489 { 490 DoublyLinkedList<Image>::ConstIterator it = fImages.GetIterator(); 491 while (Image* image = it.Next()) { 492 if (image->ID() == id) 493 return image; 494 } 495 496 return NULL; 497 } 498 499 500 // _SymbolNameLen 501 size_t 502 SymbolLookup::_SymbolNameLen(const char* address) const 503 { 504 Area* area = AreaForLocalAddress(address); 505 if (area == NULL) 506 return 0; 507 508 return strnlen(address, (addr_t)area->LocalAddress() + area->Size() 509 - (addr_t)address); 510 } 511 512 513 // #pragma mark - LoadedImage 514 515 516 SymbolLookup::LoadedImage::LoadedImage(SymbolLookup* symbolLookup, 517 const image_t* image, int32 symbolCount) 518 : 519 fSymbolLookup(symbolLookup), 520 fImage(image), 521 fSymbolCount(symbolCount), 522 fTextDelta(image->regions[0].delta) 523 { 524 // init info 525 fInfo.id = fImage->id; 526 fInfo.type = fImage->type; 527 fInfo.sequence = 0; 528 fInfo.init_order = 0; 529 fInfo.init_routine = (void (*)())fImage->init_routine; 530 fInfo.term_routine = (void (*)())fImage->term_routine; 531 fInfo.device = -1; 532 fInfo.node = -1; 533 strlcpy(fInfo.name, fImage->path, sizeof(fInfo.name)); 534 fInfo.text = (void*)fImage->regions[0].vmstart; 535 fInfo.data = (void*)fImage->regions[1].vmstart; 536 fInfo.text_size = fImage->regions[0].vmsize; 537 fInfo.data_size = fImage->regions[1].vmsize; 538 } 539 540 541 SymbolLookup::LoadedImage::~LoadedImage() 542 { 543 } 544 545 546 const Elf32_Sym* 547 SymbolLookup::LoadedImage::LookupSymbol(addr_t address, addr_t* _baseAddress, 548 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const 549 { 550 TRACE(("LoadedImage::LookupSymbol(): found image: ID: %ld, text: " 551 "address: %p, size: %ld\n", fImage->id, 552 (void*)fImage->regions[0].vmstart, fImage->regions[0].size)); 553 554 // search the image for the symbol 555 const struct Elf32_Sym *symbolFound = NULL; 556 addr_t deltaFound = INT_MAX; 557 bool exactMatch = false; 558 const char *symbolName = NULL; 559 560 int32 symbolCount = fSymbolLookup->Read(fImage->symhash[1]); 561 const elf_region_t *textRegion = fImage->regions; // local 562 563 for (int32 i = 0; i < symbolCount; i++) { 564 const struct Elf32_Sym *symbol = &fSymbolLookup->Read(fImage->syms[i]); 565 566 // The symbol table contains not only symbols referring to functions 567 // and data symbols within the shared object, but also referenced 568 // symbols of other shared objects, as well as section and file 569 // references. We ignore everything but function and data symbols 570 // that have an st_value != 0 (0 seems to be an indication for a 571 // symbol defined elsewhere -- couldn't verify that in the specs 572 // though). 573 if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC 574 && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT) 575 || symbol->st_value == 0 576 || symbol->st_value + symbol->st_size + textRegion->delta 577 > textRegion->vmstart + textRegion->size) { 578 continue; 579 } 580 581 // skip symbols starting after the given address 582 addr_t symbolAddress = symbol->st_value + textRegion->delta; 583 584 if (symbolAddress > address) 585 continue; 586 addr_t symbolDelta = address - symbolAddress; 587 588 if (!symbolFound || symbolDelta < deltaFound) { 589 symbolName = (const char*)fSymbolLookup->PrepareAddressNoThrow( 590 SYMNAME(fImage, symbol), 1); 591 if (symbolName == NULL) 592 continue; 593 594 deltaFound = symbolDelta; 595 symbolFound = symbol; 596 597 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) { 598 // exact match 599 exactMatch = true; 600 break; 601 } 602 } 603 } 604 605 TRACE(("LoadedImage::LookupSymbol(): done: symbol: %p, image name: " 606 "%s, exact match: %d\n", symbolFound, fImage->name, exactMatch)); 607 608 if (symbolFound != NULL) { 609 if (_baseAddress) 610 *_baseAddress = symbolFound->st_value + textRegion->delta; 611 if (_symbolName) 612 *_symbolName = symbolName; 613 if (_exactMatch) 614 *_exactMatch = exactMatch; 615 if (_symbolNameLen != NULL) 616 *_symbolNameLen = fSymbolLookup->_SymbolNameLen(symbolName); 617 } 618 619 return symbolFound; 620 } 621 622 623 status_t 624 SymbolLookup::LoadedImage::NextSymbol(int32& iterator, const char** _symbolName, 625 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize, 626 int32* _symbolType) const 627 { 628 while (true) { 629 if (++iterator >= fSymbolCount) 630 return B_ENTRY_NOT_FOUND; 631 632 const struct Elf32_Sym* symbol 633 = &fSymbolLookup->Read(fImage->syms[iterator]); 634 if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC 635 && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT) 636 || symbol->st_value == 0) { 637 continue; 638 } 639 640 *_symbolName = (const char*)fSymbolLookup->PrepareAddressNoThrow( 641 SYMNAME(fImage, symbol), 1); 642 *_symbolNameLen = fSymbolLookup->_SymbolNameLen(*_symbolName); 643 *_symbolAddress = symbol->st_value + fTextDelta; 644 *_symbolSize = symbol->st_size; 645 *_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC 646 ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 647 648 return B_OK; 649 } 650 } 651