summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibELF/DynamicLinker.cpp
diff options
context:
space:
mode:
authorGunnar Beutner <gbeutner@serenityos.org>2021-06-06 17:40:11 +0200
committerAndreas Kling <kling@serenityos.org>2021-06-06 22:16:11 +0200
commit89a38b72b7181b103aa524e8abd3fe98c8c75864 (patch)
tree3b71cde96160281d7d3c26468d53f88377d4760a /Userland/Libraries/LibELF/DynamicLinker.cpp
parentf82aa87d141a27271a3494fb734b5a9fc3ee4930 (diff)
downloadserenity-89a38b72b7181b103aa524e8abd3fe98c8c75864.zip
LibC+LibELF: Implement dladdr()
This implements the dladdr() function which lets the caller look up the symbol name, symbol address as well as library name and library base address for an arbitrary address.
Diffstat (limited to 'Userland/Libraries/LibELF/DynamicLinker.cpp')
-rw-r--r--Userland/Libraries/LibELF/DynamicLinker.cpp47
1 files changed, 47 insertions, 0 deletions
diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp
index 43d2d0cb6b..bafb7029c5 100644
--- a/Userland/Libraries/LibELF/DynamicLinker.cpp
+++ b/Userland/Libraries/LibELF/DynamicLinker.cpp
@@ -54,6 +54,7 @@ static bool s_do_breakpoint_trap_before_entry { false };
static Result<void, DlErrorMessage> __dlclose(void* handle);
static Result<void*, DlErrorMessage> __dlopen(const char* filename, int flags);
static Result<void*, DlErrorMessage> __dlsym(void* handle, const char* symbol_name);
+static Result<void, DlErrorMessage> __dladdr(void* addr, Dl_info* info);
Optional<DynamicObject::SymbolLookupResult> DynamicLinker::lookup_global_symbol(const StringView& name)
{
@@ -237,6 +238,10 @@ static void initialize_libc(DynamicObject& libc)
VERIFY(res.has_value());
*((DlSymFunction*)res.value().address.as_ptr()) = __dlsym;
+ res = libc.lookup_symbol("__dladdr"sv);
+ VERIFY(res.has_value());
+ *((DlAddrFunction*)res.value().address.as_ptr()) = __dladdr;
+
res = libc.lookup_symbol("__libc_init"sv);
VERIFY(res.has_value());
typedef void libc_init_func();
@@ -430,6 +435,48 @@ static Result<void*, DlErrorMessage> __dlsym(void* handle, const char* symbol_na
return symbol.value().address.as_ptr();
}
+static Result<void, DlErrorMessage> __dladdr(void* addr, Dl_info* info)
+{
+ VirtualAddress user_addr { addr };
+ __pthread_mutex_lock(&s_loader_lock);
+ ScopeGuard unlock_guard = [] { __pthread_mutex_unlock(&s_loader_lock); };
+
+ RefPtr<DynamicObject> best_matching_library;
+ VirtualAddress best_library_offset;
+ for (auto& lib : s_global_objects) {
+ if (user_addr < lib.value->base_address())
+ continue;
+ auto offset = user_addr - lib.value->base_address();
+ if (!best_matching_library || offset < best_library_offset) {
+ best_matching_library = lib.value;
+ best_library_offset = offset;
+ }
+ }
+
+ if (!best_matching_library) {
+ return DlErrorMessage { "No library found which contains the specified address" };
+ }
+
+ Optional<DynamicObject::Symbol> best_matching_symbol;
+ best_matching_library->for_each_symbol([&](auto const& symbol) {
+ if (user_addr < symbol.address() || user_addr > symbol.address().offset(symbol.size()))
+ return;
+ best_matching_symbol = symbol;
+ });
+
+ info->dli_fbase = best_matching_library->base_address().as_ptr();
+ // This works because we don't support unloading objects.
+ info->dli_fname = best_matching_library->filename().characters();
+ if (best_matching_symbol.has_value()) {
+ info->dli_saddr = best_matching_symbol.value().address().as_ptr();
+ info->dli_sname = best_matching_symbol.value().raw_name();
+ } else {
+ info->dli_saddr = nullptr;
+ info->dli_sname = nullptr;
+ }
+ return {};
+}
+
static void read_environment_variables()
{
for (char** env = s_envp; *env; ++env) {