OSDN Git Service

linker: add dlvsym(3)
authorDimitry Ivanov <dimitry@google.com>
Fri, 11 Dec 2015 22:22:24 +0000 (14:22 -0800)
committerDimitry Ivanov <dimitry@google.com>
Wed, 16 Dec 2015 23:24:13 +0000 (15:24 -0800)
This changes implements dlvsym - dlsym for versioned symbols.

Bug: http://b/22865643
Change-Id: Ic90a60d512104261a1416c43f9100f0d88e3b46f

12 files changed:
libc/include/dlfcn.h
libdl/libdl.arm.map
libdl/libdl.arm64.map
libdl/libdl.c
libdl/libdl.map.txt
libdl/libdl.mips.map
libdl/libdl.mips64.map
libdl/libdl.x86.map
libdl/libdl.x86_64.map
linker/dlfcn.cpp
linker/linker.cpp
tests/dlfcn_test.cpp

index afa7687..c2e8980 100644 (file)
@@ -43,11 +43,12 @@ typedef struct {
                                in dli_sname */
 } Dl_info;
 
-extern void*        dlopen(const char*  filename, int flag);
-extern int          dlclose(void*  handle);
-extern const char*  dlerror(void);
-extern void*        dlsym(void*  handle, const char*  symbol);
-extern int          dladdr(const void* addr, Dl_info *info);
+extern void* dlopen(const char*  filename, int flag);
+extern int dlclose(void*  handle);
+extern const char* dlerror(void);
+extern void* dlsym(void* handle, const char* symbol) __nonnull((2));
+extern void* dlvsym(void* handle, const char* symbol, const char* version) __nonnull((2, 3));
+extern int dladdr(const void* addr, Dl_info *info);
 
 enum {
 #if defined(__LP64__)
index 5ad9f9d..b9e494a 100644 (file)
@@ -18,6 +18,7 @@ LIBC_N {
   global:
     android_init_namespaces;
     android_create_namespace;
+    dlvsym;
 } LIBC;
 
 LIBC_PRIVATE {
index 3535774..a8c98da 100644 (file)
@@ -17,6 +17,7 @@ LIBC_N {
   global:
     android_init_namespaces;
     android_create_namespace;
+    dlvsym;
 } LIBC;
 
 LIBC_PRIVATE {
index af2f83e..0604d3e 100644 (file)
 // in the dynamic linker and hijacked at runtime.
 
 void* dlopen(const char* filename __unused, int flag __unused) { return 0; }
+
 const char* dlerror(void) { return 0; }
+
 void* dlsym(void* handle __unused, const char* symbol __unused) { return 0; }
+
+void* dlvsym(void* handle __unused, const char* symbol __unused, const char* version __unused) {
+  return 0;
+}
+
 int dladdr(const void* addr __unused, Dl_info* info __unused) { return 0; }
+
 int dlclose(void* handle __unused) { return 0; }
 
 #if defined(__arm__)
index 8d123fe..55a03cb 100644 (file)
@@ -32,6 +32,7 @@ LIBC_N {
   global:
     android_init_namespaces;
     android_create_namespace;
+    dlvsym;
 } LIBC;
 
 LIBC_PRIVATE {
index 3535774..a8c98da 100644 (file)
@@ -17,6 +17,7 @@ LIBC_N {
   global:
     android_init_namespaces;
     android_create_namespace;
+    dlvsym;
 } LIBC;
 
 LIBC_PRIVATE {
index 3535774..a8c98da 100644 (file)
@@ -17,6 +17,7 @@ LIBC_N {
   global:
     android_init_namespaces;
     android_create_namespace;
+    dlvsym;
 } LIBC;
 
 LIBC_PRIVATE {
index 3535774..a8c98da 100644 (file)
@@ -17,6 +17,7 @@ LIBC_N {
   global:
     android_init_namespaces;
     android_create_namespace;
+    dlvsym;
 } LIBC;
 
 LIBC_PRIVATE {
index 3535774..a8c98da 100644 (file)
@@ -17,6 +17,7 @@ LIBC_N {
   global:
     android_init_namespaces;
     android_create_namespace;
+    dlvsym;
 } LIBC;
 
 LIBC_PRIVATE {
index 788a7a0..ba54d39 100644 (file)
@@ -88,11 +88,10 @@ void* dlopen(const char* filename, int flags) {
 
 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;
   }
@@ -100,6 +99,16 @@ void* dlsym(void* handle, const char* symbol) {
   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);
@@ -179,11 +188,11 @@ static const char ANDROID_LIBDL_STRTAB[] =
   // 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
     ;
@@ -207,8 +216,9 @@ static ElfW(Sym) g_libdl_symtab[] = {
   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
 };
 
@@ -225,9 +235,9 @@ static ElfW(Sym) g_libdl_symtab[] = {
 // 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)));
index 99152ed..e38e252 100644 (file)
@@ -2187,7 +2187,7 @@ static std::string symbol_display_name(const char* sym_name, const char* sym_ver
     return sym_name;
   }
 
-  return std::string(sym_name) + "@" + sym_ver;
+  return std::string(sym_name) + ", version " + sym_ver;
 }
 
 void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
@@ -2312,8 +2312,8 @@ bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
   version_info* vi = nullptr;
 
   if (sym_ver != nullptr) {
-    vi_instance.name = sym_name;
-    vi_instance.elf_hash = calculate_elf_hash(sym_name);
+    vi_instance.name = sym_ver;
+    vi_instance.elf_hash = calculate_elf_hash(sym_ver);
     vi = &vi_instance;
   }
 
index 30eea4a..81479d5 100644 (file)
@@ -624,8 +624,10 @@ TEST(dlfcn, dlopen_check_loop) {
   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 @@ TEST(dlfcn, dlsym_failures) {
   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 @@ TEST(dlfcn, symbol_versioning_default_via_dlsym) {
   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;