BPicture: Fix archive constructor.
[haiku.git] / src / kits / debug / SymbolLookup.cpp
blob53f41d78ad702226194da6f881571e437a975911
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 */
7 #include "SymbolLookup.h"
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
13 #include <new>
15 #include <runtime_loader.h>
16 #include <syscalls.h>
18 #include "Image.h"
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
30 using namespace BPrivate::Debug;
33 // PrepareAddress
34 const void *
35 Area::PrepareAddress(const void *address)
37 TRACE(("Area::PrepareAddress(%p): area: %" B_PRId32 "\n", address, fRemoteID));
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);
50 // translate the address
51 const void *result = (const void*)((addr_t)address - (addr_t)fRemoteAddress
52 + (addr_t)fLocalAddress);
54 TRACE(("Area::PrepareAddress(%p) done: %p\n", address, result));
56 return result;
60 // #pragma mark -
62 // constructor
63 RemoteMemoryAccessor::RemoteMemoryAccessor(team_id team)
64 : fTeam(team),
65 fAreas()
69 // destructor
70 RemoteMemoryAccessor::~RemoteMemoryAccessor()
72 // delete the areas
73 while (Area *area = fAreas.Head()) {
74 fAreas.Remove(area);
75 delete area;
79 // Init
80 status_t
81 RemoteMemoryAccessor::Init()
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;
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));
96 Area *area = new(std::nothrow) Area(areaInfo.area, areaInfo.address,
97 areaInfo.size);
98 if (!area)
99 return B_NO_MEMORY;
101 fAreas.Add(area);
104 if (fAreas.IsEmpty())
105 return error;
107 return B_OK;
110 // PrepareAddress
111 const void *
112 RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress,
113 int32 size) const
115 TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %" B_PRId32 ")\n",
116 remoteAddress, size));
118 if (!remoteAddress) {
119 TRACE(("RemoteMemoryAccessor::PrepareAddress(): Got null address!\n"));
120 throw Exception(B_BAD_VALUE);
123 return _FindArea(remoteAddress, size).PrepareAddress(remoteAddress);
127 const void *
128 RemoteMemoryAccessor::PrepareAddressNoThrow(const void *remoteAddress,
129 int32 size) const
131 if (remoteAddress == NULL)
132 return NULL;
134 Area* area = _FindAreaNoThrow(remoteAddress, size);
135 if (area == NULL)
136 return NULL;
138 return area->PrepareAddress(remoteAddress);
142 // AreaForLocalAddress
143 Area*
144 RemoteMemoryAccessor::AreaForLocalAddress(const void* address) const
146 if (address == NULL)
147 return NULL;
149 for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
150 Area* area = it.Next();
151 if (area->ContainsLocalAddress(address))
152 return area;
155 return NULL;
159 // _FindArea
160 Area &
161 RemoteMemoryAccessor::_FindArea(const void *address, int32 size) const
163 TRACE(("RemoteMemoryAccessor::_FindArea(%p, %" B_PRId32 ")\n", address,
164 size));
166 for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
167 Area *area = it.Next();
168 if (area->ContainsAddress(address, size))
169 return *area;
172 TRACE(("RemoteMemoryAccessor::_FindArea(): No area found for address %p\n",
173 address));
174 throw Exception(B_ENTRY_NOT_FOUND);
178 // _FindAreaNoThrow
179 Area*
180 RemoteMemoryAccessor::_FindAreaNoThrow(const void *address, int32 size) const
182 for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
183 Area *area = it.Next();
184 if (area->ContainsAddress(address, size))
185 return area;
188 return NULL;
192 // #pragma mark -
195 class SymbolLookup::LoadedImage : public Image {
196 public:
197 LoadedImage(SymbolLookup* symbolLookup,
198 const image_t* image, int32 symbolCount);
199 virtual ~LoadedImage();
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;
212 private:
213 SymbolLookup* fSymbolLookup;
214 const image_t* fImage;
215 int32 fSymbolCount;
216 size_t fTextDelta;
220 // #pragma mark -
223 // constructor
224 SymbolLookup::SymbolLookup(team_id team, image_id image)
226 RemoteMemoryAccessor(team),
227 fDebugArea(NULL),
228 fImages(),
229 fImageID(image)
234 // destructor
235 SymbolLookup::~SymbolLookup()
237 while (Image* image = fImages.RemoveHead())
238 delete image;
242 // Init
243 status_t
244 SymbolLookup::Init()
246 TRACE(("SymbolLookup::Init()\n"));
248 status_t error = RemoteMemoryAccessor::Init();
249 if (error != B_OK)
250 return error;
252 if (fTeam != B_SYSTEM_TEAM) {
253 TRACE(("SymbolLookup::Init(): searching debug area...\n"));
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;
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"));
273 // translate the address
274 try {
275 if (remoteDebugArea != NULL) {
276 fDebugArea = &Read(*remoteDebugArea);
278 TRACE(("SymbolLookup::Init(): translated debug area is at: %p, "
279 "loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images));
281 } catch (Exception exception) {
282 // we can live without the debug area
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;
295 } else {
296 error = get_image_info(fImageID, &imageInfo);
297 if (error != B_OK)
298 return error;
300 error = _LoadImageInfo(imageInfo);
301 if (error != B_OK)
302 return error;
305 return B_OK;
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
315 TRACE(("SymbolLookup::LookupSymbolAddress(%p)\n", (void*)address));
317 Image* image = _FindImageAtAddress(address);
318 if (!image)
319 return B_ENTRY_NOT_FOUND;
321 if (_imageName != NULL)
322 *_imageName = image->Name();
324 const elf_sym* symbolFound = image->LookupSymbol(address, _baseAddress,
325 _symbolName, _symbolNameLen, _exactMatch);
327 TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: "
328 "%s, exact match: %d\n", symbolFound, image->name, exactMatch));
330 if (symbolFound != NULL)
331 return B_OK;
333 // symbol not found -- return the image itself
335 if (_baseAddress)
336 *_baseAddress = image->TextAddress();
338 if (_imageName)
339 *_imageName = image->Name();
341 if (_symbolName)
342 *_symbolName = NULL;
344 if (_exactMatch)
345 *_exactMatch = false;
347 if (_symbolNameLen != NULL)
348 *_symbolNameLen = 0;
350 return B_OK;
354 // InitSymbolIterator
355 status_t
356 SymbolLookup::InitSymbolIterator(image_id imageID,
357 SymbolIterator& iterator) const
359 TRACE(("SymbolLookup::InitSymbolIterator(): image ID: %" B_PRId32 "\n",
360 imageID));
362 // find the image
363 iterator.image = _FindImageByID(imageID);
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;
372 iterator.currentIndex = -1;
374 return B_OK;
378 // InitSymbolIterator
379 status_t
380 SymbolLookup::InitSymbolIteratorByAddress(addr_t address,
381 SymbolIterator& iterator) const
383 TRACE(("SymbolLookup::InitSymbolIteratorByAddress(): base address: %#lx\n",
384 address));
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;
394 iterator.currentIndex = -1;
396 return B_OK;
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
406 return iterator.image->NextSymbol(iterator.currentIndex, _symbolName,
407 _symbolNameLen, _symbolAddress, _symbolSize, _symbolType);
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
416 Image* image = _FindImageByID(imageID);
417 if (image == NULL)
418 return B_ENTRY_NOT_FOUND;
420 return image->GetSymbol(name, symbolType, _symbolLocation, _symbolSize,
421 _symbolType);
425 // _FindLoadedImageAtAddress
426 const image_t *
427 SymbolLookup::_FindLoadedImageAtAddress(addr_t address) const
429 TRACE(("SymbolLookup::_FindLoadedImageAtAddress(%p)\n", (void*)address));
431 if (fDebugArea == NULL)
432 return NULL;
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;
444 return NULL;
448 // _FindLoadedImageByID
449 const image_t*
450 SymbolLookup::_FindLoadedImageByID(image_id id) const
452 if (fDebugArea == NULL)
453 return NULL;
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;
463 return NULL;
467 // _FindImageAtAddress
468 Image*
469 SymbolLookup::_FindImageAtAddress(addr_t address) const
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;
478 return NULL;
482 // _FindImageByID
483 Image*
484 SymbolLookup::_FindImageByID(image_id id) const
486 DoublyLinkedList<Image>::ConstIterator it = fImages.GetIterator();
487 while (Image* image = it.Next()) {
488 if (image->ID() == id)
489 return image;
492 return NULL;
496 // _SymbolNameLen
497 size_t
498 SymbolLookup::_SymbolNameLen(const char* address) const
500 Area* area = AreaForLocalAddress(address);
501 if (area == NULL)
502 return 0;
504 return strnlen(address, (addr_t)area->LocalAddress() + area->Size()
505 - (addr_t)address);
509 status_t
510 SymbolLookup::_LoadImageInfo(const image_info& imageInfo)
512 status_t error = B_OK;
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;
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;
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;
537 error = imageFile->Init(imageInfo);
538 image = imageFile;
541 if (error != B_OK) {
542 // initialization error -- fall back to the loaded image
543 delete image;
545 const image_t* loadedImage = _FindLoadedImageByID(imageInfo.id);
546 if (loadedImage == NULL)
547 return B_OK;
549 image = new(std::nothrow) LoadedImage(this, loadedImage,
550 Read(loadedImage->symhash[1]));
551 if (image == NULL)
552 return B_NO_MEMORY;
556 fImages.Add(image);
558 return B_OK;
561 // #pragma mark - LoadedImage
564 SymbolLookup::LoadedImage::LoadedImage(SymbolLookup* symbolLookup,
565 const image_t* image, int32 symbolCount)
567 fSymbolLookup(symbolLookup),
568 fImage(image),
569 fSymbolCount(symbolCount),
570 fTextDelta(image->regions[0].delta)
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;
589 SymbolLookup::LoadedImage::~LoadedImage()
594 const elf_sym*
595 SymbolLookup::LoadedImage::LookupSymbol(addr_t address, addr_t* _baseAddress,
596 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const
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));
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;
608 int32 symbolCount = fSymbolLookup->Read(fImage->symhash[1]);
609 const elf_region_t *textRegion = fImage->regions; // local
611 for (int32 i = 0; i < symbolCount; i++) {
612 const elf_sym *symbol = &fSymbolLookup->Read(fImage->syms[i]);
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;
628 // skip symbols starting after the given address
629 addr_t symbolAddress = symbol->st_value + textRegion->delta;
631 if (symbolAddress > address)
632 continue;
633 addr_t symbolDelta = address - symbolAddress;
635 if (!symbolFound || symbolDelta < deltaFound) {
636 symbolName = (const char*)fSymbolLookup->PrepareAddressNoThrow(
637 SYMNAME(fImage, symbol), 1);
638 if (symbolName == NULL)
639 continue;
641 deltaFound = symbolDelta;
642 symbolFound = symbol;
644 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) {
645 // exact match
646 exactMatch = true;
647 break;
652 TRACE(("LoadedImage::LookupSymbol(): done: symbol: %p, image name: "
653 "%s, exact match: %d\n", symbolFound, fImage->name, exactMatch));
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);
666 return symbolFound;
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
675 while (true) {
676 if (++iterator >= fSymbolCount)
677 return B_ENTRY_NOT_FOUND;
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;
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;
694 return B_OK;