mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:38:11 +00:00
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.
This commit is contained in:
parent
f82aa87d14
commit
89a38b72b7
5 changed files with 73 additions and 0 deletions
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue