* SymbolLookup: Implemented loading the symbol tables from the shared
object files. Thus static functions will be found, too. * debug_lookup_symbol_address() and debug_next_image_symbol() no longer need to read the symbol name via the debugger API, since the respective SymbolLookup methods compute the length of the symbol name that can safely be accessed locally, now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27628 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+448
-77
@@ -5,15 +5,31 @@
|
||||
|
||||
#include "SymbolLookup.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <string.h>
|
||||
#include <runtime_loader.h>
|
||||
|
||||
|
||||
#undef TRACE
|
||||
//#define TRACE_DEBUG_SYMBOL_LOOKUP
|
||||
#ifdef TRACE_DEBUG_SYMBOL_LOOKUP
|
||||
# define TRACE(x) printf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
using std::nothrow;
|
||||
using namespace BPrivate;
|
||||
|
||||
|
||||
// PrepareAddress
|
||||
const void *
|
||||
Area::PrepareAddress(const void *address)
|
||||
@@ -89,7 +105,8 @@ RemoteMemoryAccessor::Init()
|
||||
|
||||
// PrepareAddress
|
||||
const void *
|
||||
RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress, int32 size)
|
||||
RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress,
|
||||
int32 size) const
|
||||
{
|
||||
TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %ld)\n", remoteAddress,
|
||||
size));
|
||||
@@ -102,13 +119,46 @@ RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress, int32 size)
|
||||
return _FindArea(remoteAddress, size).PrepareAddress(remoteAddress);
|
||||
}
|
||||
|
||||
|
||||
const void *
|
||||
RemoteMemoryAccessor::PrepareAddressNoThrow(const void *remoteAddress,
|
||||
int32 size) const
|
||||
{
|
||||
if (remoteAddress == NULL)
|
||||
return NULL;
|
||||
|
||||
Area* area = _FindAreaNoThrow(remoteAddress, size);
|
||||
if (area == NULL)
|
||||
return NULL;
|
||||
|
||||
return area->PrepareAddress(remoteAddress);
|
||||
}
|
||||
|
||||
|
||||
// AreaForLocalAddress
|
||||
Area*
|
||||
RemoteMemoryAccessor::AreaForLocalAddress(const void* address) const
|
||||
{
|
||||
if (address == NULL)
|
||||
return NULL;
|
||||
|
||||
for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
|
||||
Area* area = it.Next();
|
||||
if (area->ContainsLocalAddress(address))
|
||||
return area;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// _FindArea
|
||||
Area &
|
||||
RemoteMemoryAccessor::_FindArea(const void *address, int32 size)
|
||||
RemoteMemoryAccessor::_FindArea(const void *address, int32 size) const
|
||||
{
|
||||
TRACE(("RemoteMemoryAccessor::_FindArea(%p, %ld)\n", address, size));
|
||||
|
||||
for (AreaList::Iterator it = fAreas.GetIterator(); it.HasNext();) {
|
||||
for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
|
||||
Area *area = it.Next();
|
||||
if (area->ContainsAddress(address, size))
|
||||
return *area;
|
||||
@@ -120,20 +170,254 @@ RemoteMemoryAccessor::_FindArea(const void *address, int32 size)
|
||||
}
|
||||
|
||||
|
||||
// _FindAreaNoThrow
|
||||
Area*
|
||||
RemoteMemoryAccessor::_FindAreaNoThrow(const void *address, int32 size) const
|
||||
{
|
||||
for (AreaList::ConstIterator it = fAreas.GetIterator(); it.HasNext();) {
|
||||
Area *area = it.Next();
|
||||
if (area->ContainsAddress(address, size))
|
||||
return area;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
ImageFile::ImageFile(const image_info& info)
|
||||
:
|
||||
fInfo(info),
|
||||
fFD(-1),
|
||||
fFileSize(0),
|
||||
fMappedFile((uint8*)MAP_FAILED),
|
||||
fLoadDelta(0),
|
||||
fSymbolTable(NULL),
|
||||
fStringTable(NULL),
|
||||
fSymbolCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ImageFile::~ImageFile()
|
||||
{
|
||||
if (fMappedFile != MAP_FAILED)
|
||||
munmap(fMappedFile, fFileSize);
|
||||
|
||||
if (fFD >= 0)
|
||||
close(fFD);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFile::Load()
|
||||
{
|
||||
// open and stat() the file
|
||||
fFD = open(fInfo.name, O_RDONLY);
|
||||
if (fFD < 0)
|
||||
return errno;
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fFD, &st) < 0)
|
||||
return errno;
|
||||
|
||||
fFileSize = st.st_size;
|
||||
if (fFileSize < sizeof(Elf32_Ehdr))
|
||||
return B_NOT_AN_EXECUTABLE;
|
||||
|
||||
// map it
|
||||
fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_SHARED, fFD, 0);
|
||||
if (fMappedFile == MAP_FAILED)
|
||||
return errno;
|
||||
|
||||
// examine the elf header
|
||||
Elf32_Ehdr* elfHeader = (Elf32_Ehdr*)fMappedFile;
|
||||
if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0)
|
||||
return B_NOT_AN_EXECUTABLE;
|
||||
|
||||
if (elfHeader->e_ident[4] != ELFCLASS32)
|
||||
return B_NOT_AN_EXECUTABLE;
|
||||
|
||||
// verify the location of the program headers
|
||||
int32 programHeaderCount = elfHeader->e_phnum;
|
||||
if (elfHeader->e_phoff < sizeof(Elf32_Ehdr)
|
||||
|| elfHeader->e_phentsize < sizeof(Elf32_Phdr)
|
||||
|| elfHeader->e_phoff + programHeaderCount * elfHeader->e_phentsize
|
||||
> fFileSize) {
|
||||
return B_NOT_AN_EXECUTABLE;
|
||||
}
|
||||
|
||||
Elf32_Phdr* programHeaders
|
||||
= (Elf32_Phdr*)(fMappedFile + elfHeader->e_phoff);
|
||||
|
||||
// verify the location of the section headers
|
||||
int32 sectionCount = elfHeader->e_shnum;
|
||||
if (elfHeader->e_shoff < sizeof(Elf32_Ehdr)
|
||||
|| elfHeader->e_shentsize < sizeof(Elf32_Shdr)
|
||||
|| elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize
|
||||
> fFileSize) {
|
||||
return B_NOT_AN_EXECUTABLE;
|
||||
}
|
||||
|
||||
Elf32_Shdr* sectionHeaders
|
||||
= (Elf32_Shdr*)(fMappedFile + elfHeader->e_shoff);
|
||||
|
||||
// find the first segment -- we need its relative offset
|
||||
for (int32 i = 0; i < programHeaderCount; i++) {
|
||||
Elf32_Phdr* header = (Elf32_Phdr*)
|
||||
((uint8*)programHeaders + i * elfHeader->e_phentsize);
|
||||
if (header->p_type == PT_LOAD) {
|
||||
fLoadDelta = (addr_t)fInfo.text - header->p_vaddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// find the symbol table
|
||||
for (int32 i = 0; i < elfHeader->e_shnum; i++) {
|
||||
Elf32_Shdr* sectionHeader = (Elf32_Shdr*)
|
||||
((uint8*)sectionHeaders + i * elfHeader->e_shentsize);
|
||||
|
||||
if (sectionHeader->sh_type == SHT_SYMTAB) {
|
||||
Elf32_Shdr& stringHeader = *(Elf32_Shdr*)
|
||||
((uint8*)sectionHeaders
|
||||
+ sectionHeader->sh_link * elfHeader->e_shentsize);
|
||||
|
||||
if (stringHeader.sh_type != SHT_STRTAB)
|
||||
return B_BAD_DATA;
|
||||
|
||||
if (sectionHeader->sh_offset + sectionHeader->sh_size > fFileSize
|
||||
|| stringHeader.sh_offset + stringHeader.sh_size > fFileSize) {
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
fSymbolTable
|
||||
= (const Elf32_Sym*)(fMappedFile + sectionHeader->sh_offset);
|
||||
fStringTable = (const char*)(fMappedFile + stringHeader.sh_offset);
|
||||
fSymbolCount = sectionHeader->sh_size / sizeof(Elf32_Sym);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
|
||||
const Elf32_Sym*
|
||||
ImageFile::LookupSymbol(addr_t address, addr_t* _baseAddress,
|
||||
const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const
|
||||
{
|
||||
const Elf32_Sym* symbolFound = NULL;
|
||||
const char* symbolName = NULL;
|
||||
bool exactMatch = false;
|
||||
addr_t deltaFound = ~(addr_t)0;
|
||||
|
||||
for (int32 i = 0; i < fSymbolCount; i++) {
|
||||
const Elf32_Sym* symbol = &fSymbolTable[i];
|
||||
|
||||
if (symbol->st_value == 0
|
||||
|| symbol->st_size >= (size_t)fInfo.text_size + fInfo.data_size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addr_t symbolAddress = symbol->st_value + fLoadDelta;
|
||||
if (symbolAddress > address)
|
||||
continue;
|
||||
|
||||
addr_t symbolDelta = address - symbolAddress;
|
||||
if (symbolDelta >= 0 && symbolDelta < symbol->st_size)
|
||||
exactMatch = true;
|
||||
|
||||
if (exactMatch || symbolDelta < deltaFound) {
|
||||
deltaFound = symbolDelta;
|
||||
symbolFound = symbol;
|
||||
symbolName = fStringTable + symbol->st_name;
|
||||
|
||||
if (exactMatch)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (symbolFound != NULL) {
|
||||
if (_baseAddress != NULL)
|
||||
*_baseAddress = symbolFound->st_value + fLoadDelta;
|
||||
if (_symbolName != NULL)
|
||||
*_symbolName = symbolName;
|
||||
if (_exactMatch != NULL)
|
||||
*_exactMatch = exactMatch;
|
||||
if (_symbolNameLen != NULL)
|
||||
*_symbolNameLen = _SymbolNameLen(symbolName);
|
||||
}
|
||||
|
||||
return symbolFound;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFile::NextSymbol(int32& iterator, const char** _symbolName,
|
||||
size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
|
||||
int32* _symbolType) const
|
||||
{
|
||||
while (true) {
|
||||
if (++iterator >= fSymbolCount)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
const Elf32_Sym* symbol = &fSymbolTable[iterator];
|
||||
|
||||
if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
|
||||
&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
|
||||
|| symbol->st_value == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*_symbolName = fStringTable + symbol->st_name;
|
||||
*_symbolNameLen = _SymbolNameLen(*_symbolName);
|
||||
*_symbolAddress = symbol->st_value + fLoadDelta;
|
||||
*_symbolSize = symbol->st_size;
|
||||
*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
|
||||
? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ImageFile::_SymbolNameLen(const char* symbolName) const
|
||||
{
|
||||
if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable
|
||||
|| (addr_t)symbolName >= (addr_t)fMappedFile + fFileSize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return strnlen(symbolName,
|
||||
(addr_t)fMappedFile + fFileSize - (addr_t)symbolName);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
// constructor
|
||||
SymbolLookup::SymbolLookup(team_id team)
|
||||
: RemoteMemoryAccessor(team),
|
||||
fDebugArea(NULL)
|
||||
:
|
||||
RemoteMemoryAccessor(team),
|
||||
fDebugArea(NULL),
|
||||
fImageFiles()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// destructor
|
||||
SymbolLookup::~SymbolLookup()
|
||||
{
|
||||
while (ImageFile* imageFile = fImageFiles.RemoveHead())
|
||||
delete imageFile;
|
||||
}
|
||||
|
||||
|
||||
// Init
|
||||
status_t
|
||||
SymbolLookup::Init()
|
||||
@@ -170,29 +454,47 @@ SymbolLookup::Init()
|
||||
|
||||
TRACE(("SymbolLookup::Init(): translated debug area is at: %p, "
|
||||
"loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images));
|
||||
|
||||
} catch (Exception exception) {
|
||||
return exception.Error();
|
||||
}
|
||||
|
||||
// create a list of the team's images
|
||||
image_info imageInfo;
|
||||
cookie = 0;
|
||||
while (get_next_image_info(fTeam, &cookie, &imageInfo) == B_OK) {
|
||||
ImageFile* imageFile = new(std::nothrow) ImageFile(imageInfo);
|
||||
if (imageFile == NULL)
|
||||
break;
|
||||
|
||||
if (imageFile->Load() != B_OK)
|
||||
delete imageFile;
|
||||
|
||||
fImageFiles.Add(imageFile);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// LookupSymbolAddress
|
||||
status_t
|
||||
SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
||||
const char **_symbolName, const char **_imageName, bool *_exactMatch)
|
||||
const char **_symbolName, size_t *_symbolNameLen, const char **_imageName,
|
||||
bool *_exactMatch) const
|
||||
{
|
||||
// Note, that this function doesn't find all symbols that we would like
|
||||
// to find. E.g. static functions do not appear in the symbol table
|
||||
// as function symbols, but as sections without name and size. The .symtab
|
||||
// section together with the .strtab section, which apparently differ from
|
||||
// the tables referred to by the .dynamic section, also contain proper names
|
||||
// and sizes for those symbols. Therefore, to get completely satisfying
|
||||
// results, we would need to read those tables from the shared object.
|
||||
|
||||
TRACE(("SymbolLookup::LookupSymbolAddress(%p)\n", (void*)address));
|
||||
|
||||
// Try the loaded image file first -- it also contains static symbols.
|
||||
ImageFile* imageFile = _FindImageFileAtAddress(address);
|
||||
if (imageFile != NULL) {
|
||||
if (_imageName != NULL)
|
||||
*_imageName = imageFile->Info().name;
|
||||
const Elf32_Sym* symbol = imageFile->LookupSymbol(address, _baseAddress,
|
||||
_symbolName, _symbolNameLen, _exactMatch);
|
||||
if (symbol != NULL)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// get the image for the address
|
||||
const image_t *image = _FindImageAtAddress(address);
|
||||
if (!image)
|
||||
@@ -206,52 +508,49 @@ SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
||||
const struct Elf32_Sym *symbolFound = NULL;
|
||||
addr_t deltaFound = INT_MAX;
|
||||
bool exactMatch = false;
|
||||
const char *symbolName = NULL; // remote
|
||||
const char *symbolName = NULL;
|
||||
|
||||
int32 hashTabSize = Read(image->symhash[0]);
|
||||
const uint32 *hashBuckets = image->symhash + 2; // remote
|
||||
const uint32 *hashChains = image->symhash + 2 + hashTabSize; // remote
|
||||
int32 symbolCount = Read(image->symhash[1]);
|
||||
const elf_region_t *textRegion = image->regions; // local
|
||||
|
||||
for (int32 i = 0; i < hashTabSize; i++) {
|
||||
for (int32 j = Read(hashBuckets[i]);
|
||||
j != STN_UNDEF;
|
||||
j = Read(hashChains[j])) {
|
||||
for (int32 i = 0; i < symbolCount; i++) {
|
||||
const struct Elf32_Sym *symbol = &Read(image->syms[i]);
|
||||
|
||||
const struct Elf32_Sym *symbol = &Read(image->syms[j]);
|
||||
// The symbol table contains not only symbols referring to functions
|
||||
// and data symbols within the shared object, but also referenced
|
||||
// symbols of other shared objects, as well as section and file
|
||||
// references. We ignore everything but function and data symbols
|
||||
// that have an st_value != 0 (0 seems to be an indication for a
|
||||
// symbol defined elsewhere -- couldn't verify that in the specs
|
||||
// though).
|
||||
if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
|
||||
&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
|
||||
|| symbol->st_value == 0
|
||||
|| symbol->st_value + symbol->st_size + textRegion->delta
|
||||
> textRegion->vmstart + textRegion->size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The symbol table contains not only symbols referring to functions
|
||||
// and data symbols within the shared object, but also referenced
|
||||
// symbols of other shared objects, as well as section and file
|
||||
// references. We ignore everything but function and data symbols
|
||||
// that have an st_value != 0 (0 seems to be an indication for a
|
||||
// symbol defined elsewhere -- couldn't verify that in the specs
|
||||
// though).
|
||||
if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
|
||||
&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
|
||||
|| symbol->st_value == 0
|
||||
|| symbol->st_value + symbol->st_size + textRegion->delta
|
||||
> textRegion->vmstart + textRegion->size) {
|
||||
// skip symbols starting after the given address
|
||||
addr_t symbolAddress = symbol->st_value + textRegion->delta;
|
||||
|
||||
if (symbolAddress > address)
|
||||
continue;
|
||||
addr_t symbolDelta = address - symbolAddress;
|
||||
|
||||
if (!symbolFound || symbolDelta < deltaFound) {
|
||||
symbolName = (const char*)PrepareAddressNoThrow(SYMNAME(image,
|
||||
symbol), 1);
|
||||
if (symbolName == NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip symbols starting after the given address
|
||||
addr_t symbolAddress = symbol->st_value + textRegion->delta;
|
||||
deltaFound = symbolDelta;
|
||||
symbolFound = symbol;
|
||||
|
||||
if (symbolAddress > address)
|
||||
continue;
|
||||
addr_t symbolDelta = address - symbolAddress;
|
||||
|
||||
if (!symbolFound || symbolDelta < deltaFound) {
|
||||
deltaFound = symbolDelta;
|
||||
symbolFound = symbol;
|
||||
symbolName = SYMNAME(image, symbol);
|
||||
|
||||
if (symbolDelta >= 0 && symbolDelta < symbol->st_size) {
|
||||
// exact match
|
||||
exactMatch = true;
|
||||
break;
|
||||
}
|
||||
if (symbolDelta >= 0 && symbolDelta < symbol->st_size) {
|
||||
// exact match
|
||||
exactMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,26 +574,37 @@ SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
||||
if (_exactMatch)
|
||||
*_exactMatch = exactMatch;
|
||||
|
||||
if (_symbolNameLen != NULL)
|
||||
*_symbolNameLen = _SymbolNameLen(symbolName);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// InitSymbolIterator
|
||||
status_t
|
||||
SymbolLookup::InitSymbolIterator(image_id imageID, SymbolIterator& iterator)
|
||||
SymbolLookup::InitSymbolIterator(image_id imageID,
|
||||
SymbolIterator& iterator) const
|
||||
{
|
||||
TRACE(("SymbolLookup::InitSymbolIterator(): image ID: %ld\n", imageID));
|
||||
|
||||
// find the image
|
||||
const image_t* image = _FindImageByID(imageID);
|
||||
if (image == NULL) {
|
||||
TRACE(("SymbolLookup::InitSymbolIterator() done: image not found\n"));
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
// find the image file
|
||||
iterator.imageFile = _FindImageFileByID(imageID);
|
||||
|
||||
// If that didn't work, find the image.
|
||||
if (iterator.imageFile == NULL) {
|
||||
const image_t* image = _FindImageByID(imageID);
|
||||
if (image == NULL) {
|
||||
TRACE(("SymbolLookup::InitSymbolIterator() done: image not "
|
||||
"found\n"));
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
iterator.image = image;
|
||||
iterator.symbolCount = Read(image->symhash[1]);
|
||||
iterator.textDelta = image->regions->delta;
|
||||
}
|
||||
|
||||
iterator.image = image;
|
||||
iterator.symbolCount = Read(image->symhash[1]);
|
||||
iterator.textDelta = image->regions->delta;
|
||||
iterator.currentIndex = -1;
|
||||
|
||||
return B_OK;
|
||||
@@ -304,22 +614,28 @@ SymbolLookup::InitSymbolIterator(image_id imageID, SymbolIterator& iterator)
|
||||
// InitSymbolIterator
|
||||
status_t
|
||||
SymbolLookup::InitSymbolIteratorByAddress(addr_t address,
|
||||
SymbolIterator& iterator)
|
||||
SymbolIterator& iterator) const
|
||||
{
|
||||
TRACE(("SymbolLookup::InitSymbolIteratorByAddress(): base address: %#lx\n",
|
||||
address));
|
||||
|
||||
// find the image
|
||||
const image_t *image = _FindImageAtAddress(address);
|
||||
if (image == NULL) {
|
||||
TRACE(("SymbolLookup::InitSymbolIteratorByAddress() done: image not "
|
||||
"found\n"));
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
// find the image file
|
||||
iterator.imageFile = _FindImageFileAtAddress(address);
|
||||
|
||||
// If that didn't work, find the image.
|
||||
if (iterator.imageFile == NULL) {
|
||||
const image_t *image = _FindImageAtAddress(address);
|
||||
if (image == NULL) {
|
||||
TRACE(("SymbolLookup::InitSymbolIteratorByAddress() done: image "
|
||||
"not found\n"));
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
iterator.image = image;
|
||||
iterator.symbolCount = Read(image->symhash[1]);
|
||||
iterator.textDelta = image->regions->delta;
|
||||
}
|
||||
|
||||
iterator.image = image;
|
||||
iterator.symbolCount = Read(image->symhash[1]);
|
||||
iterator.textDelta = image->regions->delta;
|
||||
iterator.currentIndex = -1;
|
||||
|
||||
return B_OK;
|
||||
@@ -329,8 +645,17 @@ SymbolLookup::InitSymbolIteratorByAddress(addr_t address,
|
||||
// NextSymbol
|
||||
status_t
|
||||
SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName,
|
||||
addr_t* _symbolAddress, size_t* _symbolSize, int32* _symbolType)
|
||||
size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
|
||||
int32* _symbolType) const
|
||||
{
|
||||
// If we have an image file, get the next symbol from it.
|
||||
const ImageFile* imageFile = iterator.imageFile;
|
||||
if (imageFile != NULL) {
|
||||
return imageFile->NextSymbol(iterator.currentIndex, _symbolName,
|
||||
_symbolNameLen, _symbolAddress, _symbolSize, _symbolType);
|
||||
}
|
||||
|
||||
// Otherwise we've to fall be to iterating through the image.
|
||||
const image_t* image = iterator.image;
|
||||
|
||||
while (true) {
|
||||
@@ -345,7 +670,9 @@ SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName,
|
||||
continue;
|
||||
}
|
||||
|
||||
*_symbolName = SYMNAME(image, symbol);
|
||||
*_symbolName = (const char*)PrepareAddressNoThrow(SYMNAME(image,
|
||||
symbol), 1);
|
||||
*_symbolNameLen = _SymbolNameLen(*_symbolName);
|
||||
*_symbolAddress = symbol->st_value + iterator.textDelta;
|
||||
*_symbolSize = symbol->st_size;
|
||||
*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
|
||||
@@ -358,7 +685,7 @@ SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName,
|
||||
|
||||
// _FindImageAtAddress
|
||||
const image_t *
|
||||
SymbolLookup::_FindImageAtAddress(addr_t address)
|
||||
SymbolLookup::_FindImageAtAddress(addr_t address) const
|
||||
{
|
||||
TRACE(("SymbolLookup::_FindImageAtAddress(%p)\n", (void*)address));
|
||||
|
||||
@@ -378,7 +705,7 @@ SymbolLookup::_FindImageAtAddress(addr_t address)
|
||||
|
||||
// _FindImageByID
|
||||
const image_t*
|
||||
SymbolLookup::_FindImageByID(image_id id)
|
||||
SymbolLookup::_FindImageByID(image_id id) const
|
||||
{
|
||||
// iterate through the images
|
||||
for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head));
|
||||
@@ -390,3 +717,47 @@ SymbolLookup::_FindImageByID(image_id id)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// _FindImageFileAtAddress
|
||||
ImageFile*
|
||||
SymbolLookup::_FindImageFileAtAddress(addr_t address) const
|
||||
{
|
||||
DoublyLinkedList<ImageFile>::ConstIterator it = fImageFiles.GetIterator();
|
||||
while (ImageFile* imageFile = it.Next()) {
|
||||
const image_info& info = imageFile->Info();
|
||||
if (address >= (addr_t)info.text
|
||||
&& address < (addr_t)info.text + info.text_size) {
|
||||
return imageFile;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// _FindImageFileByID
|
||||
ImageFile*
|
||||
SymbolLookup::_FindImageFileByID(image_id id) const
|
||||
{
|
||||
DoublyLinkedList<ImageFile>::ConstIterator it = fImageFiles.GetIterator();
|
||||
while (ImageFile* imageFile = it.Next()) {
|
||||
if (imageFile->Info().id == id)
|
||||
return imageFile;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// _SymbolNameLen
|
||||
size_t
|
||||
SymbolLookup::_SymbolNameLen(const char* address) const
|
||||
{
|
||||
Area* area = AreaForLocalAddress(address);
|
||||
if (area == NULL)
|
||||
return 0;
|
||||
|
||||
return strnlen(address, (addr_t)area->LocalAddress() + area->Size()
|
||||
- (addr_t)address);
|
||||
}
|
||||
|
||||
@@ -14,16 +14,9 @@
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
//#define TRACE_DEBUG_SYMBOL_LOOKUP
|
||||
#ifdef TRACE_DEBUG_SYMBOL_LOOKUP
|
||||
# define TRACE(x) printf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
struct image_t;
|
||||
struct runtime_loader_debug_area;
|
||||
struct Elf32_Sym;
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
@@ -76,6 +69,12 @@ public:
|
||||
&& (addr_t)address + size <= (addr_t)fRemoteAddress + fSize);
|
||||
}
|
||||
|
||||
bool ContainsLocalAddress(const void* address) const
|
||||
{
|
||||
return (addr_t)address >= (addr_t)fLocalAddress
|
||||
&& (addr_t)address < (addr_t)fLocalAddress + fSize;
|
||||
}
|
||||
|
||||
const void *PrepareAddress(const void *address);
|
||||
|
||||
private:
|
||||
@@ -95,9 +94,12 @@ public:
|
||||
|
||||
status_t Init();
|
||||
|
||||
const void *PrepareAddress(const void *remoteAddress, int32 size);
|
||||
const void *PrepareAddress(const void *remoteAddress, int32 size) const;
|
||||
const void *PrepareAddressNoThrow(const void *remoteAddress,
|
||||
int32 size) const;
|
||||
|
||||
template<typename Type> inline const Type &Read(const Type &remoteData)
|
||||
template<typename Type> inline const Type &Read(
|
||||
const Type &remoteData) const
|
||||
{
|
||||
const void *remoteAddress = &remoteData;
|
||||
const void *localAddress = PrepareAddress(remoteAddress,
|
||||
@@ -105,8 +107,11 @@ public:
|
||||
return *(const Type*)localAddress;
|
||||
}
|
||||
|
||||
Area* AreaForLocalAddress(const void* address) const;
|
||||
|
||||
private:
|
||||
Area &_FindArea(const void *address, int32 size);
|
||||
Area &_FindArea(const void *address, int32 size) const;
|
||||
Area* _FindAreaNoThrow(const void *address, int32 size) const;
|
||||
|
||||
typedef DoublyLinkedList<Area> AreaList;
|
||||
|
||||
@@ -118,9 +123,42 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// ImageFile
|
||||
class ImageFile : public DoublyLinkedListLinkImpl<ImageFile> {
|
||||
public:
|
||||
ImageFile(const image_info& info);
|
||||
~ImageFile();
|
||||
|
||||
const image_info& Info() const { return fInfo; }
|
||||
|
||||
status_t Load();
|
||||
|
||||
const Elf32_Sym* LookupSymbol(addr_t address, addr_t* _baseAddress,
|
||||
const char** _symbolName, size_t *_symbolNameLen,
|
||||
bool *_exactMatch) const;
|
||||
status_t NextSymbol(int32& iterator, const char** _symbolName,
|
||||
size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
|
||||
int32* _symbolType) const;
|
||||
|
||||
private:
|
||||
size_t _SymbolNameLen(const char* symbolName) const;
|
||||
|
||||
private:
|
||||
image_info fInfo;
|
||||
int fFD;
|
||||
off_t fFileSize;
|
||||
uint8* fMappedFile;
|
||||
addr_t fLoadDelta;
|
||||
const Elf32_Sym* fSymbolTable;
|
||||
const char* fStringTable;
|
||||
int32 fSymbolCount;
|
||||
};
|
||||
|
||||
|
||||
// SymbolIterator
|
||||
struct SymbolIterator {
|
||||
const image_t* image;
|
||||
const ImageFile* imageFile;
|
||||
int32 symbolCount;
|
||||
size_t textDelta;
|
||||
int32 currentIndex;
|
||||
@@ -136,19 +174,27 @@ public:
|
||||
status_t Init();
|
||||
|
||||
status_t LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
||||
const char **_symbolName, const char **_imageName, bool *_exactMatch);
|
||||
const char **_symbolName, size_t *_symbolNameLen,
|
||||
const char **_imageName, bool *_exactMatch) const;
|
||||
|
||||
status_t InitSymbolIterator(image_id imageID, SymbolIterator& iterator);
|
||||
status_t InitSymbolIterator(image_id imageID,
|
||||
SymbolIterator& iterator) const;
|
||||
status_t InitSymbolIteratorByAddress(addr_t address,
|
||||
SymbolIterator& iterator);
|
||||
SymbolIterator& iterator) const;
|
||||
status_t NextSymbol(SymbolIterator& iterator, const char** _symbolName,
|
||||
addr_t* _symbolAddress, size_t* _symbolSize, int32* _symbolType);
|
||||
size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
|
||||
int32* _symbolType) const;
|
||||
|
||||
private:
|
||||
const image_t *_FindImageAtAddress(addr_t address);
|
||||
const image_t *_FindImageByID(image_id id);
|
||||
const image_t *_FindImageAtAddress(addr_t address) const;
|
||||
const image_t *_FindImageByID(image_id id) const;
|
||||
ImageFile* _FindImageFileAtAddress(addr_t address) const;
|
||||
ImageFile* _FindImageFileByID(image_id id) const;
|
||||
size_t _SymbolNameLen(const char* address) const;
|
||||
|
||||
private:
|
||||
const runtime_loader_debug_area *fDebugArea;
|
||||
DoublyLinkedList<ImageFile> fImageFiles;
|
||||
};
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
@@ -321,10 +321,12 @@ debug_lookup_symbol_address(debug_symbol_lookup_context *lookupContext,
|
||||
// find the symbol
|
||||
addr_t _baseAddress;
|
||||
const char *_symbolName;
|
||||
size_t _symbolNameLen;
|
||||
const char *_imageName;
|
||||
try {
|
||||
status_t error = lookup->LookupSymbolAddress((addr_t)address,
|
||||
&_baseAddress, &_symbolName, &_imageName, exactMatch);
|
||||
&_baseAddress, &_symbolName, &_symbolNameLen, &_imageName,
|
||||
exactMatch);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
} catch (BPrivate::Exception exception) {
|
||||
@@ -336,15 +338,9 @@ debug_lookup_symbol_address(debug_symbol_lookup_context *lookupContext,
|
||||
*baseAddress = (void*)_baseAddress;
|
||||
|
||||
if (symbolName && symbolNameSize > 0) {
|
||||
// _symbolName is a remote address: We read the string from the
|
||||
// remote memory. The reason for not using the cloned area is that
|
||||
// we don't trust that the data therein is valid (i.e. null-terminated)
|
||||
// and thus strlcpy() could segfault when hitting the cloned area end.
|
||||
if (_symbolName) {
|
||||
ssize_t sizeRead = debug_read_string(&lookupContext->context,
|
||||
_symbolName, symbolName, symbolNameSize);
|
||||
if (sizeRead < 0)
|
||||
return sizeRead;
|
||||
if (_symbolName && _symbolNameLen > 0) {
|
||||
strlcpy(symbolName, _symbolName,
|
||||
min_c((size_t)symbolNameSize, _symbolNameLen + 1));
|
||||
} else
|
||||
symbolName[0] = '\0';
|
||||
}
|
||||
@@ -430,11 +426,13 @@ debug_next_image_symbol(debug_symbol_iterator* iterator, char* nameBuffer,
|
||||
debug_symbol_lookup_context* lookupContext = iterator->lookup_context;
|
||||
|
||||
const char* symbolName;
|
||||
size_t symbolNameLen;
|
||||
addr_t symbolLocation;
|
||||
|
||||
try {
|
||||
status_t error = lookupContext->lookup->NextSymbol(
|
||||
*iterator, &symbolName, &symbolLocation, _symbolSize, _symbolType);
|
||||
status_t error = lookupContext->lookup->NextSymbol(*iterator,
|
||||
&symbolName, &symbolNameLen, &symbolLocation, _symbolSize,
|
||||
_symbolType);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
} catch (BPrivate::Exception exception) {
|
||||
@@ -443,15 +441,9 @@ debug_next_image_symbol(debug_symbol_iterator* iterator, char* nameBuffer,
|
||||
|
||||
*_symbolLocation = (void*)symbolLocation;
|
||||
|
||||
// symbolName is a remote address: We read the string from the
|
||||
// remote memory. The reason for not using the cloned area is that
|
||||
// we don't trust that the data therein is valid (i.e. null-terminated)
|
||||
// and thus strlcpy() could segfault when hitting the cloned area end.
|
||||
if (symbolName != NULL) {
|
||||
ssize_t sizeRead = debug_read_string(&lookupContext->context,
|
||||
symbolName, nameBuffer, nameBufferLength);
|
||||
if (sizeRead < 0)
|
||||
return sizeRead;
|
||||
if (symbolName != NULL && symbolNameLen > 0) {
|
||||
strlcpy(nameBuffer, symbolName,
|
||||
min_c(nameBufferLength, symbolNameLen + 1));
|
||||
} else
|
||||
nameBuffer[0] = '\0';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user