Skip to content

Commit

Permalink
LibC+LibELF: Implement dladdr()
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
gunnarbeutner authored and awesomekling committed Jun 6, 2021
1 parent f82aa87 commit 89a38b7
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions Userland/Libraries/LibC/dlfcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
DlCloseFunction __dlclose;
DlOpenFunction __dlopen;
DlSymFunction __dlsym;
DlAddrFunction __dladdr;
12 changes: 12 additions & 0 deletions Userland/Libraries/LibDl/dlfcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,15 @@ void* dlsym(void* handle, const char* symbol_name)
}
return result.value();
}

int dladdr(void* addr, Dl_info* info)
{
auto result = __dladdr(addr, info);
if (result.is_error()) {
// FIXME: According to the man page glibc does _not_ make the error
// available via dlerror(), however we do. Does this break anything?
store_error(result.error().text);
return 0;
}
return 1;
}
8 changes: 8 additions & 0 deletions Userland/Libraries/LibDl/dlfcn.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ __BEGIN_DECLS
#define RTLD_GLOBAL 8
#define RTLD_LOCAL 16

typedef struct __Dl_info {
const char* dli_fname;
void* dli_fbase;
const char* dli_sname;
void* dli_saddr;
} Dl_info;

int dlclose(void*);
char* dlerror();
void* dlopen(const char*, int);
void* dlsym(void*, const char*);
int dladdr(void*, Dl_info*);

__END_DECLS
5 changes: 5 additions & 0 deletions Userland/Libraries/LibDl/dlfcn_integration.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@ struct DlErrorMessage {
String text;
};

struct __Dl_info;
typedef struct __Dl_info Dl_info;

typedef Result<void, DlErrorMessage> (*DlCloseFunction)(void*);
typedef Result<void*, DlErrorMessage> (*DlOpenFunction)(const char*, int);
typedef Result<void*, DlErrorMessage> (*DlSymFunction)(void*, const char*);
typedef Result<void, DlErrorMessage> (*DlAddrFunction)(void*, Dl_info*);

extern "C" {
extern DlCloseFunction __dlclose;
extern DlOpenFunction __dlopen;
extern DlSymFunction __dlsym;
extern DlAddrFunction __dladdr;
}
47 changes: 47 additions & 0 deletions Userland/Libraries/LibELF/DynamicLinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 89a38b7

Please sign in to comment.