From b952ec392c7b93c7448c6a943eca6bca76f2803e Mon Sep 17 00:00:00 2001
From: Hamish Morrison <hamish@lavabit.com>
Date: Sun, 25 Mar 2012 15:43:40 +0000
Subject: [PATCH] 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.
---
headers/private/runtime_loader/runtime_loader.h | 5 +-
src/system/libroot/posix/dlfcn.c | 17 ++---
src/system/runtime_loader/elf.cpp | 65 ++++++++++++--------
src/system/runtime_loader/export.cpp | 2 +-
src/system/runtime_loader/runtime_loader_private.h | 4 +-
5 files changed, 52 insertions(+), 41 deletions(-)
diff --git a/headers/private/runtime_loader/runtime_loader.h b/headers/private/runtime_loader/runtime_loader.h
index 05a2d74..6b0b922 100644
a
|
b
|
struct rld_export {
|
36 | 36 | status_t (*get_nth_image_symbol)(image_id imageID, int32 num, |
37 | 37 | char *symbolName, int32 *nameLength, int32 *symbolType, |
38 | 38 | void **_location); |
39 | | status_t (*get_symbol_at_address)(void* address, image_id* _imageID, |
40 | | char* nameBuffer, int32* _nameLength, int32* _type, void** _location); |
| 39 | status_t (*get_nearest_symbol_at_address)(void* address, |
| 40 | image_id* _imageID, char** _imagePath, char** _symName, int32* _type, |
| 41 | void** _location); |
41 | 42 | status_t (*test_executable)(const char *path, char *interpreter); |
42 | 43 | status_t (*get_next_image_dependency)(image_id id, uint32 *cookie, |
43 | 44 | const char **_name); |
diff --git a/src/system/libroot/posix/dlfcn.c b/src/system/libroot/posix/dlfcn.c
index 837eb3a..15d9ff7 100644
a
|
b
|
dlerror(void)
|
74 | 74 | int |
75 | 75 | dladdr(void *address, Dl_info *info) |
76 | 76 | { |
77 | | static char sImageName[MAXPATHLEN]; |
78 | | static char sSymbolName[NAME_MAX]; |
79 | | |
80 | 77 | image_id image; |
81 | | int32 nameLength = sizeof(sSymbolName); |
| 78 | char* imagePath; |
| 79 | char* symName; |
82 | 80 | void* location; |
83 | 81 | image_info imageInfo; |
84 | | sStatus = __gRuntimeLoader->get_symbol_at_address(address, &image, |
85 | | sSymbolName, &nameLength, NULL, &location); |
| 82 | |
| 83 | sStatus = __gRuntimeLoader->get_nearest_symbol_at_address(address, &image, |
| 84 | &imagePath, &symName, NULL, &location); |
86 | 85 | if (sStatus != B_OK) |
87 | 86 | return 0; |
88 | 87 | |
… |
… |
dladdr(void *address, Dl_info *info)
|
90 | 89 | if (sStatus != B_OK) |
91 | 90 | return 0; |
92 | 91 | |
93 | | strlcpy(sImageName, imageInfo.name, MAXPATHLEN); |
94 | | info->dli_fname = sImageName; |
| 92 | info->dli_fname = imagePath; |
95 | 93 | info->dli_fbase = imageInfo.text; |
96 | | info->dli_sname = sSymbolName; |
| 94 | info->dli_sname = symName; |
97 | 95 | info->dli_saddr = location; |
98 | | |
99 | 96 | return 1; |
100 | 97 | } |
101 | 98 | |
diff --git a/src/system/runtime_loader/elf.cpp b/src/system/runtime_loader/elf.cpp
index 7423149..dff0bc1 100644
a
|
b
|
out:
|
710 | 710 | |
711 | 711 | |
712 | 712 | status_t |
713 | | get_symbol_at_address(void* address, image_id* _imageID, char* nameBuffer, |
714 | | int32* _nameLength, int32* _type, void** _location) |
| 713 | get_nearest_symbol_at_address(void* address, image_id* _imageID, |
| 714 | char** _imagePath, char** _symName, int32* _type, void** _location) |
715 | 715 | { |
716 | 716 | rld_lock(); |
717 | 717 | |
… |
… |
get_symbol_at_address(void* address, image_id* _imageID, char* nameBuffer,
|
721 | 721 | return B_BAD_VALUE; |
722 | 722 | } |
723 | 723 | |
| 724 | struct Elf32_Sym* foundSym = NULL; |
| 725 | addr_t foundLocation = (addr_t)NULL; |
| 726 | |
724 | 727 | for (uint32 i = 0; i < HASHTABSIZE(image); i++) { |
725 | 728 | for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF; |
726 | 729 | j = HASHCHAINS(image)[j]) { |
727 | 730 | struct Elf32_Sym *symbol = &image->syms[j]; |
728 | 731 | addr_t location = symbol->st_value + image->regions[0].delta; |
729 | 732 | |
730 | | if (location <= (addr_t)address |
731 | | && location - 1 + symbol->st_size >= (addr_t)address) { |
732 | | const char* symbolName = SYMNAME(image, symbol); |
733 | | strlcpy(nameBuffer, symbolName, *_nameLength); |
734 | | *_nameLength = strlen(symbolName); |
735 | | |
736 | | int32 type; |
737 | | if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) |
738 | | type = B_SYMBOL_TYPE_TEXT; |
739 | | else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) |
740 | | type = B_SYMBOL_TYPE_DATA; |
741 | | else |
742 | | type = B_SYMBOL_TYPE_ANY; |
743 | | // TODO: check with the return types of that BeOS function |
744 | | |
745 | | if (_imageID != NULL) |
746 | | *_imageID = image->id; |
747 | | if (_type != NULL) |
748 | | *_type = type; |
749 | | if (_location != NULL) |
750 | | *_location = (void*)location; |
| 733 | if (location <= (addr_t)address && location >= foundLocation) { |
| 734 | foundSym = symbol; |
| 735 | foundLocation = location; |
751 | 736 | |
752 | | rld_unlock(); |
753 | | return B_OK; |
| 737 | // jump out if we have an exact match |
| 738 | if (foundLocation == (addr_t)address) |
| 739 | goto out; |
754 | 740 | } |
755 | 741 | } |
756 | 742 | } |
757 | 743 | |
| 744 | out: |
| 745 | if (_imageID != NULL) |
| 746 | *_imageID = image->id; |
| 747 | if (_imagePath != NULL) |
| 748 | *_imagePath = image->path; |
| 749 | |
| 750 | if (foundSym != NULL) { |
| 751 | *_symName = SYMNAME(image, foundSym); |
| 752 | |
| 753 | if (_type != NULL) { |
| 754 | if (ELF32_ST_TYPE(foundSym->st_info) == STT_FUNC) |
| 755 | *_type = B_SYMBOL_TYPE_TEXT; |
| 756 | else if (ELF32_ST_TYPE(foundSym->st_info) == STT_OBJECT) |
| 757 | *_type = B_SYMBOL_TYPE_DATA; |
| 758 | else |
| 759 | *_type = B_SYMBOL_TYPE_ANY; |
| 760 | // TODO: check with the return types of that BeOS function |
| 761 | } |
| 762 | |
| 763 | if (_location != NULL) |
| 764 | *_location = (void*)foundLocation; |
| 765 | } else { |
| 766 | *_symName = NULL; |
| 767 | if (_location != NULL) |
| 768 | *_location = NULL; |
| 769 | } |
| 770 | |
758 | 771 | rld_unlock(); |
759 | | return B_BAD_VALUE; |
| 772 | return B_OK; |
760 | 773 | } |
761 | 774 | |
762 | 775 | |
diff --git a/src/system/runtime_loader/export.cpp b/src/system/runtime_loader/export.cpp
index 00d44ac..62275c5 100644
a
|
b
|
struct rld_export gRuntimeLoader = {
|
51 | 51 | get_symbol, |
52 | 52 | get_library_symbol, |
53 | 53 | get_nth_symbol, |
54 | | get_symbol_at_address, |
| 54 | get_nearest_symbol_at_address, |
55 | 55 | test_executable, |
56 | 56 | get_next_image_dependency, |
57 | 57 | |
diff --git a/src/system/runtime_loader/runtime_loader_private.h b/src/system/runtime_loader/runtime_loader_private.h
index 76a1de7..23b9de1 100644
a
|
b
|
image_id load_library(char const* path, uint32 flags, bool addOn,
|
65 | 65 | status_t unload_library(void* handle, image_id imageID, bool addOn); |
66 | 66 | status_t get_nth_symbol(image_id imageID, int32 num, char* nameBuffer, |
67 | 67 | int32* _nameLength, int32* _type, void** _location); |
68 | | status_t get_symbol_at_address(void* address, image_id* _imageID, |
69 | | char* nameBuffer, int32* _nameLength, int32* _type, void** _location); |
| 68 | status_t get_nearest_symbol_at_address(void* address, image_id* _imageID, |
| 69 | char** _imagePath, char** _symName, int32* _type, void** _location); |
70 | 70 | status_t get_symbol(image_id imageID, char const* symbolName, int32 symbolType, |
71 | 71 | bool recursive, image_id* _inImage, void** _location); |
72 | 72 | status_t get_library_symbol(void* handle, void* caller, const char* symbolName, |