Fix dladdr behaviour

* If dladdr can't find an exact match, it returns the nearest symbol
  less than the given address.
* If no suitable symbol can be found, but the address is within a
  loaded library, dladdr returns the library name and base address.

Signed-off-by: Ingo Weinhold <[email protected]>
This commit is contained in:
Hamish Morrison
2012-04-05 12:32:31 +02:00
committed by Ingo Weinhold
parent 71cfb0c8d0
commit 43e7b1c2b0
5 changed files with 55 additions and 41 deletions
@@ -36,8 +36,9 @@ struct rld_export {
status_t (*get_nth_image_symbol)(image_id imageID, int32 num, status_t (*get_nth_image_symbol)(image_id imageID, int32 num,
char *symbolName, int32 *nameLength, int32 *symbolType, char *symbolName, int32 *nameLength, int32 *symbolType,
void **_location); void **_location);
status_t (*get_symbol_at_address)(void* address, image_id* _imageID, status_t (*get_nearest_symbol_at_address)(void* address,
char* nameBuffer, int32* _nameLength, int32* _type, void** _location); image_id* _imageID, char** _imagePath, char** _symbolName,
int32* _type, void** _location);
status_t (*test_executable)(const char *path, char *interpreter); status_t (*test_executable)(const char *path, char *interpreter);
status_t (*get_next_image_dependency)(image_id id, uint32 *cookie, status_t (*get_next_image_dependency)(image_id id, uint32 *cookie,
const char **_name); const char **_name);
+7 -9
View File
@@ -74,15 +74,14 @@ dlerror(void)
int int
dladdr(void *address, Dl_info *info) dladdr(void *address, Dl_info *info)
{ {
static char sImageName[MAXPATHLEN];
static char sSymbolName[NAME_MAX];
image_id image; image_id image;
int32 nameLength = sizeof(sSymbolName); char* imagePath;
char* symbolName;
void* location; void* location;
image_info imageInfo; image_info imageInfo;
sStatus = __gRuntimeLoader->get_symbol_at_address(address, &image,
sSymbolName, &nameLength, NULL, &location); sStatus = __gRuntimeLoader->get_nearest_symbol_at_address(address, &image,
&imagePath, &symbolName, NULL, &location);
if (sStatus != B_OK) if (sStatus != B_OK)
return 0; return 0;
@@ -90,10 +89,9 @@ dladdr(void *address, Dl_info *info)
if (sStatus != B_OK) if (sStatus != B_OK)
return 0; return 0;
strlcpy(sImageName, imageInfo.name, MAXPATHLEN); info->dli_fname = imagePath;
info->dli_fname = sImageName;
info->dli_fbase = imageInfo.text; info->dli_fbase = imageInfo.text;
info->dli_sname = sSymbolName; info->dli_sname = symbolName;
info->dli_saddr = location; info->dli_saddr = location;
return 1; return 1;
+40 -25
View File
@@ -710,8 +710,8 @@ out:
status_t status_t
get_symbol_at_address(void* address, image_id* _imageID, char* nameBuffer, get_nearest_symbol_at_address(void* address, image_id* _imageID,
int32* _nameLength, int32* _type, void** _location) char** _imagePath, char** _symbolName, int32* _type, void** _location)
{ {
rld_lock(); rld_lock();
@@ -721,42 +721,57 @@ get_symbol_at_address(void* address, image_id* _imageID, char* nameBuffer,
return B_BAD_VALUE; return B_BAD_VALUE;
} }
for (uint32 i = 0; i < HASHTABSIZE(image); i++) { struct Elf32_Sym* foundSymbol = NULL;
addr_t foundLocation = (addr_t)NULL;
bool found = false;
for (uint32 i = 0; i < HASHTABSIZE(image) && !found; i++) {
for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF; for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF;
j = HASHCHAINS(image)[j]) { j = HASHCHAINS(image)[j]) {
struct Elf32_Sym *symbol = &image->syms[j]; struct Elf32_Sym *symbol = &image->syms[j];
addr_t location = symbol->st_value + image->regions[0].delta; addr_t location = symbol->st_value + image->regions[0].delta;
if (location <= (addr_t)address if (location <= (addr_t)address && location >= foundLocation) {
&& location - 1 + symbol->st_size >= (addr_t)address) { foundSymbol = symbol;
const char* symbolName = SYMNAME(image, symbol); foundLocation = location;
strlcpy(nameBuffer, symbolName, *_nameLength);
*_nameLength = strlen(symbolName);
int32 type; // jump out if we have an exact match
if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) if (foundLocation == (addr_t)address) {
type = B_SYMBOL_TYPE_TEXT; found = true;
else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) break;
type = B_SYMBOL_TYPE_DATA; }
else }
type = B_SYMBOL_TYPE_ANY; }
// TODO: check with the return types of that BeOS function }
if (_imageID != NULL) if (_imageID != NULL)
*_imageID = image->id; *_imageID = image->id;
if (_type != NULL) if (_imagePath != NULL)
*_type = type; *_imagePath = image->path;
if (foundSymbol != NULL) {
*_symbolName = SYMNAME(image, foundSymbol);
if (_type != NULL) {
if (ELF32_ST_TYPE(foundSymbol->st_info) == STT_FUNC)
*_type = B_SYMBOL_TYPE_TEXT;
else if (ELF32_ST_TYPE(foundSymbol->st_info) == STT_OBJECT)
*_type = B_SYMBOL_TYPE_DATA;
else
*_type = B_SYMBOL_TYPE_ANY;
// TODO: check with the return types of that BeOS function
}
if (_location != NULL) if (_location != NULL)
*_location = (void*)location; *_location = (void*)foundLocation;
} else {
*_symbolName = NULL;
if (_location != NULL)
*_location = NULL;
}
rld_unlock(); rld_unlock();
return B_OK; return B_OK;
}
}
}
rld_unlock();
return B_BAD_VALUE;
} }
+1 -1
View File
@@ -51,7 +51,7 @@ struct rld_export gRuntimeLoader = {
get_symbol, get_symbol,
get_library_symbol, get_library_symbol,
get_nth_symbol, get_nth_symbol,
get_symbol_at_address, get_nearest_symbol_at_address,
test_executable, test_executable,
get_next_image_dependency, get_next_image_dependency,
@@ -65,8 +65,8 @@ image_id load_library(char const* path, uint32 flags, bool addOn,
status_t unload_library(void* handle, image_id imageID, bool addOn); status_t unload_library(void* handle, image_id imageID, bool addOn);
status_t get_nth_symbol(image_id imageID, int32 num, char* nameBuffer, status_t get_nth_symbol(image_id imageID, int32 num, char* nameBuffer,
int32* _nameLength, int32* _type, void** _location); int32* _nameLength, int32* _type, void** _location);
status_t get_symbol_at_address(void* address, image_id* _imageID, status_t get_nearest_symbol_at_address(void* address, image_id* _imageID,
char* nameBuffer, int32* _nameLength, int32* _type, void** _location); char** _imagePath, char** _symbolName, int32* _type, void** _location);
status_t get_symbol(image_id imageID, char const* symbolName, int32 symbolType, status_t get_symbol(image_id imageID, char const* symbolName, int32 symbolType,
bool recursive, image_id* _inImage, void** _location); bool recursive, image_id* _inImage, void** _location);
status_t get_library_symbol(void* handle, void* caller, const char* symbolName, status_t get_library_symbol(void* handle, void* caller, const char* symbolName,