extern android_namespace_t* g_anonymous_namespace;
-void* dlsym(void* handle, const char* symbol) {
- void* caller_addr = __builtin_return_address(0);
+void* dlsym_impl(void* handle, const char* symbol, const char* version, void* caller_addr) {
ScopedPthreadMutexLocker locker(&g_dl_mutex);
void* result;
- if (!do_dlsym(handle, symbol, nullptr, caller_addr, &result)) {
+ if (!do_dlsym(handle, symbol, version, caller_addr, &result)) {
__bionic_format_dlerror(linker_get_error_buffer(), nullptr);
return nullptr;
}
return result;
}
+void* dlsym(void* handle, const char* symbol) {
+ void* caller_addr = __builtin_return_address(0);
+ return dlsym_impl(handle, symbol, nullptr, caller_addr);
+}
+
+void* dlvsym(void* handle, const char* symbol, const char* version) {
+ void* caller_addr = __builtin_return_address(0);
+ return dlsym_impl(handle, symbol, version, caller_addr);
+}
+
int dladdr(const void* addr, Dl_info* info) {
ScopedPthreadMutexLocker locker(&g_dl_mutex);
return do_dladdr(addr, info);
// 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
// 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
"erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
- // 0000000000111111 111122222222223333333333 4444444444555555555566666
- // 0123456789012345 678901234567890123456789 0123456789012345678901234
- "get_sdk_version\0android_init_namespaces\0android_create_namespace\0"
+ // 0000000000111111 111122222222223333333333 4444444444555555555566666 6666677
+ // 0123456789012345 678901234567890123456789 0123456789012345678901234 5678901
+ "get_sdk_version\0android_init_namespaces\0android_create_namespace\0dlvsym\0"
#if defined(__arm__)
- // 265
+ // 272
"dl_unwind_find_exidx\0"
#endif
;
ELFW(SYM_INITIALIZER)(173, &android_get_application_target_sdk_version, 1),
ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
+ ELFW(SYM_INITIALIZER)(265, &dlvsym, 1),
#if defined(__arm__)
- ELFW(SYM_INITIALIZER)(265, &dl_unwind_find_exidx, 1),
+ ELFW(SYM_INITIALIZER)(272, &dl_unwind_find_exidx, 1),
#endif
};
// Note that adding any new symbols here requires stubbing them out in libdl.
static unsigned g_libdl_buckets[1] = { 1 };
#if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
#else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0 };
#endif
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
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);
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);
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;