* 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:
+410
-39
@@ -5,15 +5,31 @@
|
|||||||
|
|
||||||
#include "SymbolLookup.h"
|
#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 <new>
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <runtime_loader.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 std::nothrow;
|
||||||
using namespace BPrivate;
|
using namespace BPrivate;
|
||||||
|
|
||||||
|
|
||||||
// PrepareAddress
|
// PrepareAddress
|
||||||
const void *
|
const void *
|
||||||
Area::PrepareAddress(const void *address)
|
Area::PrepareAddress(const void *address)
|
||||||
@@ -89,7 +105,8 @@ RemoteMemoryAccessor::Init()
|
|||||||
|
|
||||||
// PrepareAddress
|
// PrepareAddress
|
||||||
const void *
|
const void *
|
||||||
RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress, int32 size)
|
RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress,
|
||||||
|
int32 size) const
|
||||||
{
|
{
|
||||||
TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %ld)\n", remoteAddress,
|
TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %ld)\n", remoteAddress,
|
||||||
size));
|
size));
|
||||||
@@ -102,13 +119,46 @@ RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress, int32 size)
|
|||||||
return _FindArea(remoteAddress, size).PrepareAddress(remoteAddress);
|
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
|
// _FindArea
|
||||||
Area &
|
Area &
|
||||||
RemoteMemoryAccessor::_FindArea(const void *address, int32 size)
|
RemoteMemoryAccessor::_FindArea(const void *address, int32 size) const
|
||||||
{
|
{
|
||||||
TRACE(("RemoteMemoryAccessor::_FindArea(%p, %ld)\n", address, size));
|
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();
|
Area *area = it.Next();
|
||||||
if (area->ContainsAddress(address, size))
|
if (area->ContainsAddress(address, size))
|
||||||
return *area;
|
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 -
|
// #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
|
// constructor
|
||||||
SymbolLookup::SymbolLookup(team_id team)
|
SymbolLookup::SymbolLookup(team_id team)
|
||||||
: RemoteMemoryAccessor(team),
|
:
|
||||||
fDebugArea(NULL)
|
RemoteMemoryAccessor(team),
|
||||||
|
fDebugArea(NULL),
|
||||||
|
fImageFiles()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
SymbolLookup::~SymbolLookup()
|
SymbolLookup::~SymbolLookup()
|
||||||
{
|
{
|
||||||
|
while (ImageFile* imageFile = fImageFiles.RemoveHead())
|
||||||
|
delete imageFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
status_t
|
status_t
|
||||||
SymbolLookup::Init()
|
SymbolLookup::Init()
|
||||||
@@ -170,29 +454,47 @@ SymbolLookup::Init()
|
|||||||
|
|
||||||
TRACE(("SymbolLookup::Init(): translated debug area is at: %p, "
|
TRACE(("SymbolLookup::Init(): translated debug area is at: %p, "
|
||||||
"loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images));
|
"loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images));
|
||||||
|
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
return exception.Error();
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// LookupSymbolAddress
|
// LookupSymbolAddress
|
||||||
status_t
|
status_t
|
||||||
SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
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));
|
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
|
// get the image for the address
|
||||||
const image_t *image = _FindImageAtAddress(address);
|
const image_t *image = _FindImageAtAddress(address);
|
||||||
if (!image)
|
if (!image)
|
||||||
@@ -206,19 +508,13 @@ SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
|||||||
const struct Elf32_Sym *symbolFound = NULL;
|
const struct Elf32_Sym *symbolFound = NULL;
|
||||||
addr_t deltaFound = INT_MAX;
|
addr_t deltaFound = INT_MAX;
|
||||||
bool exactMatch = false;
|
bool exactMatch = false;
|
||||||
const char *symbolName = NULL; // remote
|
const char *symbolName = NULL;
|
||||||
|
|
||||||
int32 hashTabSize = Read(image->symhash[0]);
|
int32 symbolCount = Read(image->symhash[1]);
|
||||||
const uint32 *hashBuckets = image->symhash + 2; // remote
|
|
||||||
const uint32 *hashChains = image->symhash + 2 + hashTabSize; // remote
|
|
||||||
const elf_region_t *textRegion = image->regions; // local
|
const elf_region_t *textRegion = image->regions; // local
|
||||||
|
|
||||||
for (int32 i = 0; i < hashTabSize; i++) {
|
for (int32 i = 0; i < symbolCount; i++) {
|
||||||
for (int32 j = Read(hashBuckets[i]);
|
const struct Elf32_Sym *symbol = &Read(image->syms[i]);
|
||||||
j != STN_UNDEF;
|
|
||||||
j = Read(hashChains[j])) {
|
|
||||||
|
|
||||||
const struct Elf32_Sym *symbol = &Read(image->syms[j]);
|
|
||||||
|
|
||||||
// The symbol table contains not only symbols referring to functions
|
// The symbol table contains not only symbols referring to functions
|
||||||
// and data symbols within the shared object, but also referenced
|
// and data symbols within the shared object, but also referenced
|
||||||
@@ -243,9 +539,13 @@ SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
|||||||
addr_t symbolDelta = address - symbolAddress;
|
addr_t symbolDelta = address - symbolAddress;
|
||||||
|
|
||||||
if (!symbolFound || symbolDelta < deltaFound) {
|
if (!symbolFound || symbolDelta < deltaFound) {
|
||||||
|
symbolName = (const char*)PrepareAddressNoThrow(SYMNAME(image,
|
||||||
|
symbol), 1);
|
||||||
|
if (symbolName == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
deltaFound = symbolDelta;
|
deltaFound = symbolDelta;
|
||||||
symbolFound = symbol;
|
symbolFound = symbol;
|
||||||
symbolName = SYMNAME(image, symbol);
|
|
||||||
|
|
||||||
if (symbolDelta >= 0 && symbolDelta < symbol->st_size) {
|
if (symbolDelta >= 0 && symbolDelta < symbol->st_size) {
|
||||||
// exact match
|
// exact match
|
||||||
@@ -254,7 +554,6 @@ SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: "
|
TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: "
|
||||||
"%s, exact match: %d\n", symbolFound, image->name, exactMatch));
|
"%s, exact match: %d\n", symbolFound, image->name, exactMatch));
|
||||||
@@ -275,26 +574,37 @@ SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
|||||||
if (_exactMatch)
|
if (_exactMatch)
|
||||||
*_exactMatch = exactMatch;
|
*_exactMatch = exactMatch;
|
||||||
|
|
||||||
|
if (_symbolNameLen != NULL)
|
||||||
|
*_symbolNameLen = _SymbolNameLen(symbolName);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// InitSymbolIterator
|
// InitSymbolIterator
|
||||||
status_t
|
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));
|
TRACE(("SymbolLookup::InitSymbolIterator(): image ID: %ld\n", imageID));
|
||||||
|
|
||||||
// find the image
|
// 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);
|
const image_t* image = _FindImageByID(imageID);
|
||||||
if (image == NULL) {
|
if (image == NULL) {
|
||||||
TRACE(("SymbolLookup::InitSymbolIterator() done: image not found\n"));
|
TRACE(("SymbolLookup::InitSymbolIterator() done: image not "
|
||||||
|
"found\n"));
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator.image = image;
|
iterator.image = image;
|
||||||
iterator.symbolCount = Read(image->symhash[1]);
|
iterator.symbolCount = Read(image->symhash[1]);
|
||||||
iterator.textDelta = image->regions->delta;
|
iterator.textDelta = image->regions->delta;
|
||||||
|
}
|
||||||
|
|
||||||
iterator.currentIndex = -1;
|
iterator.currentIndex = -1;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -304,22 +614,28 @@ SymbolLookup::InitSymbolIterator(image_id imageID, SymbolIterator& iterator)
|
|||||||
// InitSymbolIterator
|
// InitSymbolIterator
|
||||||
status_t
|
status_t
|
||||||
SymbolLookup::InitSymbolIteratorByAddress(addr_t address,
|
SymbolLookup::InitSymbolIteratorByAddress(addr_t address,
|
||||||
SymbolIterator& iterator)
|
SymbolIterator& iterator) const
|
||||||
{
|
{
|
||||||
TRACE(("SymbolLookup::InitSymbolIteratorByAddress(): base address: %#lx\n",
|
TRACE(("SymbolLookup::InitSymbolIteratorByAddress(): base address: %#lx\n",
|
||||||
address));
|
address));
|
||||||
|
|
||||||
// find the image
|
// 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);
|
const image_t *image = _FindImageAtAddress(address);
|
||||||
if (image == NULL) {
|
if (image == NULL) {
|
||||||
TRACE(("SymbolLookup::InitSymbolIteratorByAddress() done: image not "
|
TRACE(("SymbolLookup::InitSymbolIteratorByAddress() done: image "
|
||||||
"found\n"));
|
"not found\n"));
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator.image = image;
|
iterator.image = image;
|
||||||
iterator.symbolCount = Read(image->symhash[1]);
|
iterator.symbolCount = Read(image->symhash[1]);
|
||||||
iterator.textDelta = image->regions->delta;
|
iterator.textDelta = image->regions->delta;
|
||||||
|
}
|
||||||
|
|
||||||
iterator.currentIndex = -1;
|
iterator.currentIndex = -1;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -329,8 +645,17 @@ SymbolLookup::InitSymbolIteratorByAddress(addr_t address,
|
|||||||
// NextSymbol
|
// NextSymbol
|
||||||
status_t
|
status_t
|
||||||
SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName,
|
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;
|
const image_t* image = iterator.image;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -345,7 +670,9 @@ SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
*_symbolName = SYMNAME(image, symbol);
|
*_symbolName = (const char*)PrepareAddressNoThrow(SYMNAME(image,
|
||||||
|
symbol), 1);
|
||||||
|
*_symbolNameLen = _SymbolNameLen(*_symbolName);
|
||||||
*_symbolAddress = symbol->st_value + iterator.textDelta;
|
*_symbolAddress = symbol->st_value + iterator.textDelta;
|
||||||
*_symbolSize = symbol->st_size;
|
*_symbolSize = symbol->st_size;
|
||||||
*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
|
*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
|
||||||
@@ -358,7 +685,7 @@ SymbolLookup::NextSymbol(SymbolIterator& iterator, const char** _symbolName,
|
|||||||
|
|
||||||
// _FindImageAtAddress
|
// _FindImageAtAddress
|
||||||
const image_t *
|
const image_t *
|
||||||
SymbolLookup::_FindImageAtAddress(addr_t address)
|
SymbolLookup::_FindImageAtAddress(addr_t address) const
|
||||||
{
|
{
|
||||||
TRACE(("SymbolLookup::_FindImageAtAddress(%p)\n", (void*)address));
|
TRACE(("SymbolLookup::_FindImageAtAddress(%p)\n", (void*)address));
|
||||||
|
|
||||||
@@ -378,7 +705,7 @@ SymbolLookup::_FindImageAtAddress(addr_t address)
|
|||||||
|
|
||||||
// _FindImageByID
|
// _FindImageByID
|
||||||
const image_t*
|
const image_t*
|
||||||
SymbolLookup::_FindImageByID(image_id id)
|
SymbolLookup::_FindImageByID(image_id id) const
|
||||||
{
|
{
|
||||||
// iterate through the images
|
// iterate through the images
|
||||||
for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head));
|
for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head));
|
||||||
@@ -390,3 +717,47 @@ SymbolLookup::_FindImageByID(image_id id)
|
|||||||
|
|
||||||
return NULL;
|
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>
|
#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 image_t;
|
||||||
struct runtime_loader_debug_area;
|
struct runtime_loader_debug_area;
|
||||||
|
struct Elf32_Sym;
|
||||||
|
|
||||||
|
|
||||||
namespace BPrivate {
|
namespace BPrivate {
|
||||||
@@ -76,6 +69,12 @@ public:
|
|||||||
&& (addr_t)address + size <= (addr_t)fRemoteAddress + fSize);
|
&& (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);
|
const void *PrepareAddress(const void *address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -95,9 +94,12 @@ public:
|
|||||||
|
|
||||||
status_t Init();
|
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 *remoteAddress = &remoteData;
|
||||||
const void *localAddress = PrepareAddress(remoteAddress,
|
const void *localAddress = PrepareAddress(remoteAddress,
|
||||||
@@ -105,8 +107,11 @@ public:
|
|||||||
return *(const Type*)localAddress;
|
return *(const Type*)localAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Area* AreaForLocalAddress(const void* address) const;
|
||||||
|
|
||||||
private:
|
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;
|
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
|
// SymbolIterator
|
||||||
struct SymbolIterator {
|
struct SymbolIterator {
|
||||||
const image_t* image;
|
const image_t* image;
|
||||||
|
const ImageFile* imageFile;
|
||||||
int32 symbolCount;
|
int32 symbolCount;
|
||||||
size_t textDelta;
|
size_t textDelta;
|
||||||
int32 currentIndex;
|
int32 currentIndex;
|
||||||
@@ -136,19 +174,27 @@ public:
|
|||||||
status_t Init();
|
status_t Init();
|
||||||
|
|
||||||
status_t LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
|
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,
|
status_t InitSymbolIteratorByAddress(addr_t address,
|
||||||
SymbolIterator& iterator);
|
SymbolIterator& iterator) const;
|
||||||
status_t NextSymbol(SymbolIterator& iterator, const char** _symbolName,
|
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:
|
private:
|
||||||
const image_t *_FindImageAtAddress(addr_t address);
|
const image_t *_FindImageAtAddress(addr_t address) const;
|
||||||
const image_t *_FindImageByID(image_id id);
|
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;
|
const runtime_loader_debug_area *fDebugArea;
|
||||||
|
DoublyLinkedList<ImageFile> fImageFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace BPrivate
|
} // namespace BPrivate
|
||||||
|
|||||||
@@ -321,10 +321,12 @@ debug_lookup_symbol_address(debug_symbol_lookup_context *lookupContext,
|
|||||||
// find the symbol
|
// find the symbol
|
||||||
addr_t _baseAddress;
|
addr_t _baseAddress;
|
||||||
const char *_symbolName;
|
const char *_symbolName;
|
||||||
|
size_t _symbolNameLen;
|
||||||
const char *_imageName;
|
const char *_imageName;
|
||||||
try {
|
try {
|
||||||
status_t error = lookup->LookupSymbolAddress((addr_t)address,
|
status_t error = lookup->LookupSymbolAddress((addr_t)address,
|
||||||
&_baseAddress, &_symbolName, &_imageName, exactMatch);
|
&_baseAddress, &_symbolName, &_symbolNameLen, &_imageName,
|
||||||
|
exactMatch);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
} catch (BPrivate::Exception exception) {
|
} catch (BPrivate::Exception exception) {
|
||||||
@@ -336,15 +338,9 @@ debug_lookup_symbol_address(debug_symbol_lookup_context *lookupContext,
|
|||||||
*baseAddress = (void*)_baseAddress;
|
*baseAddress = (void*)_baseAddress;
|
||||||
|
|
||||||
if (symbolName && symbolNameSize > 0) {
|
if (symbolName && symbolNameSize > 0) {
|
||||||
// _symbolName is a remote address: We read the string from the
|
if (_symbolName && _symbolNameLen > 0) {
|
||||||
// remote memory. The reason for not using the cloned area is that
|
strlcpy(symbolName, _symbolName,
|
||||||
// we don't trust that the data therein is valid (i.e. null-terminated)
|
min_c((size_t)symbolNameSize, _symbolNameLen + 1));
|
||||||
// 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;
|
|
||||||
} else
|
} else
|
||||||
symbolName[0] = '\0';
|
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;
|
debug_symbol_lookup_context* lookupContext = iterator->lookup_context;
|
||||||
|
|
||||||
const char* symbolName;
|
const char* symbolName;
|
||||||
|
size_t symbolNameLen;
|
||||||
addr_t symbolLocation;
|
addr_t symbolLocation;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
status_t error = lookupContext->lookup->NextSymbol(
|
status_t error = lookupContext->lookup->NextSymbol(*iterator,
|
||||||
*iterator, &symbolName, &symbolLocation, _symbolSize, _symbolType);
|
&symbolName, &symbolNameLen, &symbolLocation, _symbolSize,
|
||||||
|
_symbolType);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
} catch (BPrivate::Exception exception) {
|
} catch (BPrivate::Exception exception) {
|
||||||
@@ -443,15 +441,9 @@ debug_next_image_symbol(debug_symbol_iterator* iterator, char* nameBuffer,
|
|||||||
|
|
||||||
*_symbolLocation = (void*)symbolLocation;
|
*_symbolLocation = (void*)symbolLocation;
|
||||||
|
|
||||||
// symbolName is a remote address: We read the string from the
|
if (symbolName != NULL && symbolNameLen > 0) {
|
||||||
// remote memory. The reason for not using the cloned area is that
|
strlcpy(nameBuffer, symbolName,
|
||||||
// we don't trust that the data therein is valid (i.e. null-terminated)
|
min_c(nameBufferLength, symbolNameLen + 1));
|
||||||
// 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;
|
|
||||||
} else
|
} else
|
||||||
nameBuffer[0] = '\0';
|
nameBuffer[0] = '\0';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user