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.
7 #include "SymbolLookup.h"
15 #include <runtime_loader.h>
22 //#define TRACE_DEBUG_SYMBOL_LOOKUP
23 #ifdef TRACE_DEBUG_SYMBOL_LOOKUP
24 # define TRACE(x) printf x
30 using namespace BPrivate::Debug
;
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
41 fLocalID
= clone_area("cloned area", &fLocalAddress
, B_ANY_ADDRESS
,
42 B_READ_AREA
, fRemoteID
);
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
));
63 RemoteMemoryAccessor::RemoteMemoryAccessor(team_id team
)
70 RemoteMemoryAccessor::~RemoteMemoryAccessor()
73 while (Area
*area
= fAreas
.Head()) {
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
)
88 // get a list of the team's areas
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
,
104 if (fAreas
.IsEmpty())
112 RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress
,
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
);
128 RemoteMemoryAccessor::PrepareAddressNoThrow(const void *remoteAddress
,
131 if (remoteAddress
== NULL
)
134 Area
* area
= _FindAreaNoThrow(remoteAddress
, size
);
138 return area
->PrepareAddress(remoteAddress
);
142 // AreaForLocalAddress
144 RemoteMemoryAccessor::AreaForLocalAddress(const void* address
) const
149 for (AreaList::ConstIterator it
= fAreas
.GetIterator(); it
.HasNext();) {
150 Area
* area
= it
.Next();
151 if (area
->ContainsLocalAddress(address
))
161 RemoteMemoryAccessor::_FindArea(const void *address
, int32 size
) const
163 TRACE(("RemoteMemoryAccessor::_FindArea(%p, %" B_PRId32
")\n", address
,
166 for (AreaList::ConstIterator it
= fAreas
.GetIterator(); it
.HasNext();) {
167 Area
*area
= it
.Next();
168 if (area
->ContainsAddress(address
, size
))
172 TRACE(("RemoteMemoryAccessor::_FindArea(): No area found for address %p\n",
174 throw Exception(B_ENTRY_NOT_FOUND
);
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
))
195 class SymbolLookup::LoadedImage
: public Image
{
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;
213 SymbolLookup
* fSymbolLookup
;
214 const image_t
* fImage
;
224 SymbolLookup::SymbolLookup(team_id team
, image_id image
)
226 RemoteMemoryAccessor(team
),
235 SymbolLookup::~SymbolLookup()
237 while (Image
* image
= fImages
.RemoveHead())
246 TRACE(("SymbolLookup::Init()\n"));
248 status_t error
= RemoteMemoryAccessor::Init();
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
;
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
;
266 if (remoteDebugArea
) {
267 TRACE(("SymbolLookup::Init(): found debug area, translating "
270 TRACE(("SymbolLookup::Init(): Couldn't find debug area!\n"));
273 // translate the address
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
;
288 // create a list of the team's images
290 while (get_next_image_info(fTeam
, &cookie
, &imageInfo
) == B_OK
) {
291 error
= _LoadImageInfo(imageInfo
);
296 error
= get_image_info(fImageID
, &imageInfo
);
300 error
= _LoadImageInfo(imageInfo
);
309 // LookupSymbolAddress
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
);
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
)
333 // symbol not found -- return the image itself
336 *_baseAddress
= image
->TextAddress();
339 *_imageName
= image
->Name();
345 *_exactMatch
= false;
347 if (_symbolNameLen
!= NULL
)
354 // InitSymbolIterator
356 SymbolLookup::InitSymbolIterator(image_id imageID
,
357 SymbolIterator
& iterator
) const
359 TRACE(("SymbolLookup::InitSymbolIterator(): image ID: %" B_PRId32
"\n",
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 "
369 return B_ENTRY_NOT_FOUND
;
372 iterator
.currentIndex
= -1;
378 // InitSymbolIterator
380 SymbolLookup::InitSymbolIteratorByAddress(addr_t address
,
381 SymbolIterator
& iterator
) const
383 TRACE(("SymbolLookup::InitSymbolIteratorByAddress(): base address: %#lx\n",
387 iterator
.image
= _FindImageAtAddress(address
);
388 if (iterator
.image
== NULL
) {
389 TRACE(("SymbolLookup::InitSymbolIteratorByAddress() done: image "
391 return B_ENTRY_NOT_FOUND
;
394 iterator
.currentIndex
= -1;
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
);
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
);
418 return B_ENTRY_NOT_FOUND
;
420 return image
->GetSymbol(name
, symbolType
, _symbolLocation
, _symbolSize
,
425 // _FindLoadedImageAtAddress
427 SymbolLookup::_FindLoadedImageAtAddress(addr_t address
) const
429 TRACE(("SymbolLookup::_FindLoadedImageAtAddress(%p)\n", (void*)address
));
431 if (fDebugArea
== NULL
)
434 // iterate through the loaded images
435 for (const image_t
*image
= &Read(*Read(fDebugArea
->loaded_images
->head
));
437 image
= &Read(*image
->next
)) {
438 if (image
->regions
[0].vmstart
<= address
439 && address
< image
->regions
[0].vmstart
+ image
->regions
[0].size
) {
448 // _FindLoadedImageByID
450 SymbolLookup::_FindLoadedImageByID(image_id id
) const
452 if (fDebugArea
== NULL
)
455 // iterate through the images
456 for (const image_t
*image
= &Read(*Read(fDebugArea
->loaded_images
->head
));
458 image
= &Read(*image
->next
)) {
467 // _FindImageAtAddress
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())
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
)
498 SymbolLookup::_SymbolNameLen(const char* address
) const
500 Area
* area
= AreaForLocalAddress(address
);
504 return strnlen(address
, (addr_t
)area
->LocalAddress() + area
->Size()
510 SymbolLookup::_LoadImageInfo(const image_info
& imageInfo
)
512 status_t error
= B_OK
;
515 if (fTeam
== B_SYSTEM_TEAM
) {
517 KernelImage
* kernelImage
= new(std::nothrow
) KernelImage
;
518 if (kernelImage
== NULL
)
521 error
= kernelImage
->Init(imageInfo
);
523 } else if (!strcmp("commpage", imageInfo
.name
)) {
525 CommPageImage
* commPageImage
= new(std::nothrow
) CommPageImage
;
526 if (commPageImage
== NULL
)
529 error
= commPageImage
->Init(imageInfo
);
530 image
= commPageImage
;
532 // userland image -- try to load an image file
533 ImageFile
* imageFile
= new(std::nothrow
) ImageFile
;
534 if (imageFile
== NULL
)
537 error
= imageFile
->Init(imageInfo
);
542 // initialization error -- fall back to the loaded image
545 const image_t
* loadedImage
= _FindLoadedImageByID(imageInfo
.id
);
546 if (loadedImage
== NULL
)
549 image
= new(std::nothrow
) LoadedImage(this, loadedImage
,
550 Read(loadedImage
->symhash
[1]));
561 // #pragma mark - LoadedImage
564 SymbolLookup::LoadedImage::LoadedImage(SymbolLookup
* symbolLookup
,
565 const image_t
* image
, int32 symbolCount
)
567 fSymbolLookup(symbolLookup
),
569 fSymbolCount(symbolCount
),
570 fTextDelta(image
->regions
[0].delta
)
573 fInfo
.id
= fImage
->id
;
574 fInfo
.type
= fImage
->type
;
576 fInfo
.init_order
= 0;
577 fInfo
.init_routine
= (void (*)())fImage
->init_routine
;
578 fInfo
.term_routine
= (void (*)())fImage
->term_routine
;
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()
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
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
) {
628 // skip symbols starting after the given address
629 addr_t symbolAddress
= symbol
->st_value
+ textRegion
->delta
;
631 if (symbolAddress
> address
)
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
)
641 deltaFound
= symbolDelta
;
642 symbolFound
= symbol
;
644 if (symbolDelta
>= 0 && symbolDelta
< symbol
->st_size
) {
652 TRACE(("LoadedImage::LookupSymbol(): done: symbol: %p, image name: "
653 "%s, exact match: %d\n", symbolFound
, fImage
->name
, exactMatch
));
655 if (symbolFound
!= NULL
) {
657 *_baseAddress
= symbolFound
->st_value
+ textRegion
->delta
;
659 *_symbolName
= symbolName
;
661 *_exactMatch
= exactMatch
;
662 if (_symbolNameLen
!= NULL
)
663 *_symbolNameLen
= fSymbolLookup
->_SymbolNameLen(symbolName
);
671 SymbolLookup::LoadedImage::NextSymbol(int32
& iterator
, const char** _symbolName
,
672 size_t* _symbolNameLen
, addr_t
* _symbolAddress
, size_t* _symbolSize
,
673 int32
* _symbolType
) const
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) {
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
;