linker: add dlvsym(3)
This changes implements dlvsym - dlsym for versioned symbols.
Bug: http://b/22865643
Change-Id: Ic90a60d512104261a1416c43f9100f0d88e3b46f
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 30eea4a..81479d5 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -624,8 +624,10 @@
handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
ASSERT_TRUE(handle == nullptr);
#ifdef __BIONIC__
- // TODO: glibc returns nullptr on dlerror() here. Is it bug?
ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
+#else
+ // TODO: glibc returns nullptr on dlerror() here. Is it bug?
+ ASSERT_TRUE(dlerror() == nullptr);
#endif
handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
@@ -763,14 +765,6 @@
ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
#endif
- // NULL symbol name.
-#if defined(__BIONIC__)
- // glibc marks this parameter non-null and SEGVs if you cheat.
- sym = dlsym(self, nullptr);
- ASSERT_TRUE(sym == nullptr);
- ASSERT_STREQ("dlsym failed: symbol name is null", dlerror());
-#endif
-
// Symbol that doesn't exist.
sym = dlsym(self, "ThisSymbolDoesNotExist");
ASSERT_TRUE(sym == nullptr);
@@ -1054,6 +1048,26 @@
dlclose(handle);
}
+TEST(dlfcn, dlvsym_smoke) {
+ void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ typedef int (*fn_t)();
+
+ {
+ fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "nonversion"));
+ ASSERT_TRUE(fn == nullptr);
+ ASSERT_SUBSTR("undefined symbol: versioned_function, version nonversion", dlerror());
+ }
+
+ {
+ fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "TESTLIB_V2"));
+ ASSERT_TRUE(fn != nullptr) << dlerror();
+ ASSERT_EQ(2, fn());
+ }
+
+ dlclose(handle);
+}
+
// This preempts the implementation from libtest_versioned_lib.so
extern "C" int version_zero_function() {
return 0;