From f61f8fb2675e29c221a470ed7212826581681dea Mon Sep 17 00:00:00 2001
From: Hamish Morrison <hamish@lavabit.com>
Date: Sat, 31 Mar 2012 17:47:08 +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 | 16 ++---
src/system/runtime_loader/elf.cpp | 69 ++++++++++++--------
src/system/runtime_loader/export.cpp | 2 +-
src/system/runtime_loader/runtime_loader_private.h | 4 +-
5 files changed, 55 insertions(+), 41 deletions(-)
diff --git a/headers/private/runtime_loader/runtime_loader.h b/headers/private/runtime_loader/runtime_loader.h
index 05a2d74..132a674 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** _symbolName, |
| 41 | int32* _type, 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..d85c649 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* symbolName; |
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, &symbolName, 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 = symbolName; |
97 | 95 | info->dli_saddr = location; |
98 | 96 | |
99 | 97 | return 1; |
diff --git a/src/system/runtime_loader/elf.cpp b/src/system/runtime_loader/elf.cpp
index 7423149..ed8822d 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** _symbolName, 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 | | for (uint32 i = 0; i < HASHTABSIZE(image); i++) { |
| 724 | struct Elf32_Sym* foundSymbol = NULL; |
| 725 | addr_t foundLocation = (addr_t)NULL; |
| 726 | |
| 727 | bool found = false; |
| 728 | for (uint32 i = 0; i < HASHTABSIZE(image) && found == false; i++) { |
725 | 729 | for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF; |
726 | 730 | j = HASHCHAINS(image)[j]) { |
727 | 731 | struct Elf32_Sym *symbol = &image->syms[j]; |
728 | 732 | addr_t location = symbol->st_value + image->regions[0].delta; |
729 | 733 | |
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; |
| 734 | if (location <= (addr_t)address && location >= foundLocation) { |
| 735 | foundSymbol = symbol; |
| 736 | foundLocation = location; |
751 | 737 | |
752 | | rld_unlock(); |
753 | | return B_OK; |
| 738 | // jump out if we have an exact match |
| 739 | if (foundLocation == (addr_t)address) { |
| 740 | found = true; |
| 741 | break; |
| 742 | } |
754 | 743 | } |
755 | 744 | } |
756 | 745 | } |
757 | 746 | |
| 747 | if (_imageID != NULL) |
| 748 | *_imageID = image->id; |
| 749 | if (_imagePath != NULL) |
| 750 | *_imagePath = image->path; |
| 751 | |
| 752 | if (foundSymbol != NULL) { |
| 753 | *_symbolName = SYMNAME(image, foundSymbol); |
| 754 | |
| 755 | if (_type != NULL) { |
| 756 | if (ELF32_ST_TYPE(foundSymbol->st_info) == STT_FUNC) |
| 757 | *_type = B_SYMBOL_TYPE_TEXT; |
| 758 | else if (ELF32_ST_TYPE(foundSymbol->st_info) == STT_OBJECT) |
| 759 | *_type = B_SYMBOL_TYPE_DATA; |
| 760 | else |
| 761 | *_type = B_SYMBOL_TYPE_ANY; |
| 762 | // TODO: check with the return types of that BeOS function |
| 763 | } |
| 764 | |
| 765 | if (_location != NULL) |
| 766 | *_location = (void*)foundLocation; |
| 767 | } else { |
| 768 | *_symbolName = NULL; |
| 769 | if (_location != NULL) |
| 770 | *_location = NULL; |
| 771 | } |
| 772 | |
758 | 773 | rld_unlock(); |
759 | | return B_BAD_VALUE; |
| 774 | return B_OK; |
760 | 775 | } |
761 | 776 | |
762 | 777 | |
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..3ac2d0d 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** _symbolName, 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, |