Added support for userland symbol lookup in "sc" and "call". Having

used it for an hour or so, I really wonder how we could live without it.
:-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23640 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-01-19 16:33:03 +00:00
parent 741e605cee
commit 2477bce504
4 changed files with 255 additions and 15 deletions

View File

@ -26,7 +26,11 @@ image_id load_kernel_add_on(const char *path);
status_t unload_kernel_add_on(image_id id); status_t unload_kernel_add_on(image_id id);
status_t elf_debug_lookup_symbol_address(addr_t address, addr_t *_baseAddress, status_t elf_debug_lookup_symbol_address(addr_t address, addr_t *_baseAddress,
const char **_symbolName, const char **_imageName, bool *_exactMatch); const char **_symbolName, const char **_imageName,
bool *_exactMatch);
status_t elf_debug_lookup_user_symbol_address(struct team* team, addr_t address,
addr_t *_baseAddress, const char **_symbolName,
const char **_imageName, bool *_exactMatch);
status_t elf_init(struct kernel_args *args); status_t elf_init(struct kernel_args *args);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -11,6 +11,7 @@ SubDir HAIKU_TOP src system kernel ;
} }
UsePrivateHeaders shared ; UsePrivateHeaders shared ;
UsePrivateHeaders runtime_loader ;
AddResources kernel_$(TARGET_ARCH) : kernel.rdef ; AddResources kernel_$(TARGET_ARCH) : kernel.rdef ;

View File

@ -75,6 +75,32 @@ error:
} }
static status_t
lookup_symbol(struct thread* thread, addr_t address, addr_t *_baseAddress,
const char **_symbolName, const char **_imageName, bool *_exactMatch)
{
status_t status = B_ENTRY_NOT_FOUND;
if (IS_KERNEL_ADDRESS(address)) {
// a kernel symbol
status = elf_debug_lookup_symbol_address(address, _baseAddress,
_symbolName, _imageName, _exactMatch);
} else if (thread != NULL && thread->team != NULL) {
// try a lookup using the userland runtime loader structures
status = elf_debug_lookup_user_symbol_address(thread->team, address,
_baseAddress, _symbolName, _imageName, _exactMatch);
if (status != B_OK) {
// try to locate the image in the images loaded into user space
status = image_debug_lookup_user_symbol_address(thread->team,
address, _baseAddress, _symbolName, _imageName, _exactMatch);
}
}
return status;
}
static void static void
print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp) print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp)
{ {
@ -90,13 +116,8 @@ print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp)
if (diff & 0x80000000) if (diff & 0x80000000)
diff = 0; diff = 0;
status = elf_debug_lookup_symbol_address(eip, &baseAddress, &symbol, status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
&image, &exactMatch); &exactMatch);
if (status != B_OK) {
// try to locate the image in the images loaded into user space
status = image_debug_lookup_user_symbol_address(thread->team, eip,
&baseAddress, &symbol, &image, &exactMatch);
}
kprintf("%08lx (+%4ld) %08lx", ebp, diff, eip); kprintf("%08lx (+%4ld) %08lx", ebp, diff, eip);
@ -322,13 +343,8 @@ print_call(struct thread *thread, addr_t eip, addr_t ebp, int32 argCount)
bool exactMatch; bool exactMatch;
status_t status; status_t status;
status = elf_debug_lookup_symbol_address(eip, &baseAddress, &symbol, status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
&image, &exactMatch); &exactMatch);
if (status != B_OK) {
// try to locate the image in the images loaded into user space
status = image_debug_lookup_user_symbol_address(thread->team, eip,
&baseAddress, &symbol, &image, &exactMatch);
}
kprintf("%08lx %08lx", ebp, eip); kprintf("%08lx %08lx", ebp, eip);

View File

@ -19,14 +19,17 @@
#include <ctype.h> #include <ctype.h>
#include <debug.h> #include <debug.h>
#include <kernel.h>
#include <kimage.h> #include <kimage.h>
#include <syscalls.h> #include <syscalls.h>
#include <team.h> #include <team.h>
#include <thread.h> #include <thread.h>
#include <runtime_loader.h>
#include <util/khash.h> #include <util/khash.h>
#include <vfs.h> #include <vfs.h>
#include <vm.h> #include <vm.h>
#include <vm_address_space.h> #include <vm_address_space.h>
#include <vm_types.h>
#include <arch/cpu.h> #include <arch/cpu.h>
#include <arch/elf.h> #include <arch/elf.h>
@ -861,6 +864,207 @@ error1:
} }
// #pragma mark - userland symbol lookup
class UserSymbolLookup {
public:
static UserSymbolLookup& Default()
{
return sLookup;
}
status_t Init(struct team* team)
{
// find the runtime loader debug area
vm_area* area = team->address_space->areas;
while (area != NULL) {
if (strcmp(area->name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0)
break;
area = area->address_space_next;
}
if (area == NULL)
return B_ERROR;
// copy the runtime loader data structure
if (!_Read((runtime_loader_debug_area*)area->base, fDebugArea))
return B_BAD_ADDRESS;
return B_OK;
}
status_t LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
const char **_symbolName, const char **_imageName, bool *_exactMatch)
{
// 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.
// get the image for the address
image_t image;
status_t error = _FindImageAtAddress(address, image);
if (error != B_OK)
return error;
strlcpy(fImageName, image.name, sizeof(fImageName));
// symbol hash table size
uint32 hashTabSize;
if (!_Read(image.symhash, hashTabSize))
return B_BAD_ADDRESS;
// remote pointers to hash buckets and chains
const uint32* hashBuckets = image.symhash + 2;
const uint32* hashChains = image.symhash + 2 + hashTabSize;
const elf_region_t& textRegion = image.regions[0];
// search the image for the symbol
Elf32_Sym symbolFound;
addr_t deltaFound = INT_MAX;
bool exactMatch = false;
for (uint32 i = 0; i < hashTabSize; i++) {
uint32 bucket;
if (!_Read(&hashBuckets[i], bucket))
return B_BAD_ADDRESS;
for (uint32 j = bucket; j != STN_UNDEF;
_Read(&hashChains[j], j) ? 0 : j = STN_UNDEF) {
Elf32_Sym symbol;
if (!_Read(image.syms + j, symbol))
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) {
continue;
}
// 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 (symbolDelta < deltaFound) {
deltaFound = symbolDelta;
symbolFound = symbol;
if (symbolDelta >= 0 && symbolDelta < symbol.st_size) {
// exact match
exactMatch = true;
break;
}
}
}
}
if (_imageName)
*_imageName = fImageName;
if (_symbolName) {
*_symbolName = NULL;
if (deltaFound < INT_MAX) {
if (_ReadString(image, symbolFound.st_name, fSymbolName,
sizeof(fSymbolName))) {
*_symbolName = fSymbolName;
} else {
// we can't get its name, so forget the symbol
deltaFound = INT_MAX;
}
}
}
if (_baseAddress) {
if (deltaFound < INT_MAX)
*_baseAddress = symbolFound.st_value + textRegion.delta;
else
*_baseAddress = textRegion.vmstart;
}
if (_exactMatch)
*_exactMatch = exactMatch;
return B_OK;
}
status_t _FindImageAtAddress(addr_t address, image_t& image)
{
image_queue_t imageQueue;
if (!_Read(fDebugArea.loaded_images, imageQueue))
return B_BAD_ADDRESS;
image_t* imageAddress = imageQueue.head;
while (imageAddress != NULL) {
if (!_Read(imageAddress, image))
return B_BAD_ADDRESS;
if (image.regions[0].vmstart <= address
&& address < image.regions[0].vmstart + image.regions[0].size) {
return B_OK;
}
imageAddress = image.next;
}
return B_ENTRY_NOT_FOUND;
}
bool _ReadString(const image_t& image, uint32 offset, char* buffer,
size_t bufferSize)
{
const char* address = image.strtab + offset;
if (!IS_USER_ADDRESS(address))
return false;
return user_strlcpy(buffer, address, bufferSize) >= 0;
}
template<typename T> bool _Read(const T* address, T& data);
// gcc 2.95.3 doesn't like it defined in-place
private:
runtime_loader_debug_area fDebugArea;
char fImageName[B_OS_NAME_LENGTH];
char fSymbolName[256];
static UserSymbolLookup sLookup;
};
template<typename T>
bool
UserSymbolLookup::_Read(const T* address, T& data)
{
if (!IS_USER_ADDRESS(address))
return false;
return user_memcpy(&data, address, sizeof(T)) == B_OK;
}
UserSymbolLookup UserSymbolLookup::sLookup;
// doesn't need construction, but has an Init() method
// #pragma mark - public kernel API // #pragma mark - public kernel API
@ -1031,6 +1235,21 @@ symbol_found:
} }
status_t
elf_debug_lookup_user_symbol_address(struct team* team, addr_t address,
addr_t *_baseAddress, const char **_symbolName, const char **_imageName,
bool *_exactMatch)
{
UserSymbolLookup& lookup = UserSymbolLookup::Default();
status_t error = lookup.Init(team);
if (error != B_OK)
return error;
return lookup.LookupSymbolAddress(address, _baseAddress, _symbolName,
_imageName, _exactMatch);
}
status_t status_t
elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entry) elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entry)
{ {