core/elf.cc | 33 +++++++++++++++++++++++++++++++++
include/osv/elf.hh | 1 +
libc/dlfcn.cc | 4 ++--
tests/tst-dlfcn.cc | 2 +-
4 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/core/elf.cc b/core/elf.cc
index 26a25c43..69dbd7ed 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -41,6 +41,7 @@
TRACEPOINT(trace_elf_load, "%s", const char *);
TRACEPOINT(trace_elf_unload, "%s", const char *);
TRACEPOINT(trace_elf_lookup, "%s", const char *);
+TRACEPOINT(trace_elf_lookup_next, "%s", const char *);
TRACEPOINT(trace_elf_lookup_addr, "%p", const void *);
extern void* elf_start;
@@ -1532,6 +1533,38 @@ symbol_module program::lookup(const char* name, object* seeker)
return ret;
}
+symbol_module program::lookup_next(const char* name, const void* retaddr)
+{
+ trace_elf_lookup_next(name);
+ symbol_module ret(nullptr,nullptr);
+ if (retaddr == nullptr) {
+ return ret;
+ }
+ with_modules([&](const elf::program::modules_list &ml)
+ {
+ auto start = ml.objects.end();
+ for (auto it = ml.objects.begin(), end = ml.objects.end(); it != end; ++it) {
+ auto module = *it;
+ if (module->contains_addr(retaddr)) {
+ start = it;
+ break;
+ }
+ }
+ if (start == ml.objects.end()) {
+ return;
+ }
+ start = ++start;
+ for (auto it = start, end = ml.objects.end(); it != end; ++it) {
+ auto module = *it;
+ if (auto sym = module->lookup_symbol(name, false)) {
+ ret = symbol_module(sym, module);
+ break;
+ }
+ }
+ });
+ return ret;
+}
+
void* program::do_lookup_function(const char* name)
{
auto sym = lookup(name, nullptr);
diff --git a/include/osv/elf.hh b/include/osv/elf.hh
index 8cd7b37a..edcec7ff 100644
--- a/include/osv/elf.hh
+++ b/include/osv/elf.hh
@@ -584,6 +584,7 @@ public:
void set_search_path(std::initializer_list<std::string> path);
symbol_module lookup(const char* symbol, object* seeker);
+ symbol_module lookup_next(const char* name, const void* retaddr);
template <typename T>
T* lookup_function(const char* symbol);
diff --git a/libc/dlfcn.cc b/libc/dlfcn.cc
index e3a4a577..108a78ed 100644
--- a/libc/dlfcn.cc
+++ b/libc/dlfcn.cc
@@ -70,8 +70,8 @@ void* dlsym(void* handle, const char* name)
if ((program == handle) || (handle == RTLD_DEFAULT)) {
sym = program->lookup(name, nullptr);
} else if (handle == RTLD_NEXT) {
- // FIXME: implement
- abort();
+ auto retaddr = __builtin_extract_return_addr(__builtin_return_address(0));
+ sym = program->lookup_next(name, retaddr);
} else {
auto obj = *reinterpret_cast<std::shared_ptr<elf::object>*>(handle);
sym = obj->lookup_symbol_deep(name);
diff --git a/tests/tst-dlfcn.cc b/tests/tst-dlfcn.cc
index 6d91fb93..6188236f 100644
--- a/tests/tst-dlfcn.cc
+++ b/tests/tst-dlfcn.cc
@@ -12,7 +12,7 @@
#include <boost/test/unit_test.hpp>
namespace utf = boost::unit_test;
-const bool rtld_next = false;
+const bool rtld_next = true;
const bool deep_lookup = true;
static bool called = false;
--
2.17.1