diff --git a/headers/private/kernel/elf.h b/headers/private/kernel/elf.h index 6139082ac0..1eab64dd83 100644 --- a/headers/private/kernel/elf.h +++ b/headers/private/kernel/elf.h @@ -26,7 +26,11 @@ image_id load_kernel_add_on(const char *path); status_t unload_kernel_add_on(image_id id); 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); #ifdef __cplusplus diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index 6b7b95169f..152b0d151a 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -11,6 +11,7 @@ SubDir HAIKU_TOP src system kernel ; } UsePrivateHeaders shared ; +UsePrivateHeaders runtime_loader ; AddResources kernel_$(TARGET_ARCH) : kernel.rdef ; diff --git a/src/system/kernel/arch/x86/arch_debug.cpp b/src/system/kernel/arch/x86/arch_debug.cpp index 650c11f784..c0e71e7b1f 100644 --- a/src/system/kernel/arch/x86/arch_debug.cpp +++ b/src/system/kernel/arch/x86/arch_debug.cpp @@ -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 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) diff = 0; - status = elf_debug_lookup_symbol_address(eip, &baseAddress, &symbol, - &image, &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); - } + status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image, + &exactMatch); 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; status_t status; - status = elf_debug_lookup_symbol_address(eip, &baseAddress, &symbol, - &image, &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); - } + status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image, + &exactMatch); kprintf("%08lx %08lx", ebp, eip); diff --git a/src/system/kernel/elf.cpp b/src/system/kernel/elf.cpp index 9f2c198bf6..48a49b1c92 100644 --- a/src/system/kernel/elf.cpp +++ b/src/system/kernel/elf.cpp @@ -19,14 +19,17 @@ #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include #include @@ -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 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 +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 @@ -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 elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entry) {