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:
parent
741e605cee
commit
2477bce504
@ -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
|
||||||
|
@ -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 ;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user