From 8839d592bce4b8ffebdb440ed50085fbf397975b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 22 Sep 2008 11:13:38 +0000 Subject: [PATCH] Added syscall _kern_read_kernel_image_symbols() for reading a kernel image's symbol and string tables. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27687 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/elf.h | 4 ++ headers/private/system/syscalls.h | 5 ++ src/system/kernel/elf.cpp | 101 ++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) diff --git a/headers/private/kernel/elf.h b/headers/private/kernel/elf.h index 3dee0dd275..9adf6cbbe1 100644 --- a/headers/private/kernel/elf.h +++ b/headers/private/kernel/elf.h @@ -34,6 +34,10 @@ status_t elf_debug_lookup_user_symbol_address(struct team* team, addr_t address, status_t elf_get_image_info_for_address(addr_t address, image_info* info); status_t elf_init(struct kernel_args *args); +status_t _user_read_kernel_image_symbols(image_id id, + struct Elf32_Sym* symbolTable, int32* _symbolCount, + char* stringTable, size_t* _stringTableSize, addr_t* _imageDelta); + #ifdef __cplusplus } #endif diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index 923259b8b3..cf8b3de8f4 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -20,6 +20,7 @@ extern "C" { #endif struct dirent; +struct Elf32_Sym; struct fd_info; struct fd_set; struct fs_info; @@ -188,6 +189,10 @@ extern void _kern_image_relocated(image_id id); extern void _kern_loading_app_failed(status_t error); extern status_t _kern_get_image_info(image_id id, image_info *info, size_t size); extern status_t _kern_get_next_image_info(team_id team, int32 *cookie, image_info *info, size_t size); +extern status_t _kern_read_kernel_image_symbols(image_id id, + struct Elf32_Sym* symbolTable, int32* _symbolCount, + char* stringTable, size_t* _stringTableSize, + addr_t* _imageDelta); // VFS functions extern dev_t _kern_mount(const char *path, const char *device, diff --git a/src/system/kernel/elf.cpp b/src/system/kernel/elf.cpp index b8e24eeb1d..e100d2317e 100644 --- a/src/system/kernel/elf.cpp +++ b/src/system/kernel/elf.cpp @@ -1878,3 +1878,104 @@ elf_init(kernel_args *args) return B_OK; } + +// #pragma mark - + + +/*! Reads the symbol and string table for the kernel image with the given ID. + \a _symbolCount and \a _stringTableSize are both in- and output parameters. + When called they call the size of the buffers given by \a symbolTable and + \a stringTable respectively. When the function returns successfully, they + will contain the actual sizes (which can be greater than the original ones). + The function will copy as much as possible into the buffers. For only + getting the required buffer sizes, it can be invoked with \c NULL buffers. + On success \a _imageDelta will contain the offset to be added to the symbol + values in the table to get the actual symbol addresses. +*/ +status_t +_user_read_kernel_image_symbols(image_id id, struct Elf32_Sym* symbolTable, + int32* _symbolCount, char* stringTable, size_t* _stringTableSize, + addr_t* _imageDelta) +{ + // check params + if (_symbolCount == NULL || _stringTableSize == NULL) + return B_BAD_VALUE; + if (!IS_USER_ADDRESS(_symbolCount) || !IS_USER_ADDRESS(_stringTableSize) + || _imageDelta != NULL && !IS_USER_ADDRESS(_imageDelta) + || symbolTable != NULL && !IS_USER_ADDRESS(symbolTable) + || stringTable != NULL && !IS_USER_ADDRESS(stringTable)) { + return B_BAD_ADDRESS; + } + + // get buffer sizes + int32 maxSymbolCount; + size_t maxStringTableSize; + if (user_memcpy(&maxSymbolCount, _symbolCount, sizeof(maxSymbolCount)) + != B_OK + || user_memcpy(&maxStringTableSize, _stringTableSize, + sizeof(maxStringTableSize)) != B_OK) { + return B_BAD_ADDRESS; + } + + // find the image + MutexLocker _(sImageMutex); + struct elf_image_info* image = find_image(id); + if (image == NULL) + return B_ENTRY_NOT_FOUND; + + // get the tables and infos + addr_t imageDelta = image->text_region.delta; + const Elf32_Sym* symbols; + int32 symbolCount; + const char* strings; + + if (image->debug_symbols != NULL) { + symbols = image->debug_symbols; + symbolCount = image->num_debug_symbols; + strings = image->debug_string_table; + } else { + symbols = image->syms; + symbolCount = image->symhash[1]; + strings = image->strtab; + } + + // The string table size isn't stored in the elf_image_info structure. Find + // out by iterating through all symbols. + size_t stringTableSize = 0; + for (int32 i = 0; i < symbolCount; i++) { + size_t index = symbols[i].st_name; + if (index > stringTableSize) + stringTableSize = index; + } + stringTableSize += strlen(strings + stringTableSize) + 1; + // add size of the last string + + // copy symbol table + int32 symbolsToCopy = min_c(symbolCount, maxSymbolCount); + if (symbolTable != NULL && symbolsToCopy > 0) { + if (user_memcpy(symbolTable, symbols, sizeof(Elf32_Sym) * symbolsToCopy) + != B_OK) { + return B_BAD_ADDRESS; + } + } + + // copy string table + size_t stringsToCopy = min_c(stringTableSize, maxStringTableSize); + if (stringTable != NULL && stringsToCopy > 0) { + if (user_memcpy(stringTable, strings, stringsToCopy) + != B_OK) { + return B_BAD_ADDRESS; + } + } + + // copy sizes + if (user_memcpy(_symbolCount, &symbolCount, sizeof(symbolCount)) != B_OK + || user_memcpy(_stringTableSize, &stringTableSize, + sizeof(stringTableSize)) != B_OK + || _imageDelta != NULL && user_memcpy(_imageDelta, &imageDelta, + sizeof(imageDelta)) != B_OK) { + return B_BAD_ADDRESS; + } + + return B_OK; +}