Merge "linker: add dlvsym(3)"
This commit is contained in:
commit
d4f86aed42
@ -43,11 +43,12 @@ typedef struct {
|
|||||||
in dli_sname */
|
in dli_sname */
|
||||||
} Dl_info;
|
} Dl_info;
|
||||||
|
|
||||||
extern void* dlopen(const char* filename, int flag);
|
extern void* dlopen(const char* filename, int flag);
|
||||||
extern int dlclose(void* handle);
|
extern int dlclose(void* handle);
|
||||||
extern const char* dlerror(void);
|
extern const char* dlerror(void);
|
||||||
extern void* dlsym(void* handle, const char* symbol);
|
extern void* dlsym(void* handle, const char* symbol) __nonnull((2));
|
||||||
extern int dladdr(const void* addr, Dl_info *info);
|
extern void* dlvsym(void* handle, const char* symbol, const char* version) __nonnull((2, 3));
|
||||||
|
extern int dladdr(const void* addr, Dl_info *info);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
#if defined(__LP64__)
|
#if defined(__LP64__)
|
||||||
|
@ -18,6 +18,7 @@ LIBC_N {
|
|||||||
global:
|
global:
|
||||||
android_init_namespaces;
|
android_init_namespaces;
|
||||||
android_create_namespace;
|
android_create_namespace;
|
||||||
|
dlvsym;
|
||||||
} LIBC;
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
|
@ -17,6 +17,7 @@ LIBC_N {
|
|||||||
global:
|
global:
|
||||||
android_init_namespaces;
|
android_init_namespaces;
|
||||||
android_create_namespace;
|
android_create_namespace;
|
||||||
|
dlvsym;
|
||||||
} LIBC;
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
|
@ -24,9 +24,17 @@
|
|||||||
// in the dynamic linker and hijacked at runtime.
|
// in the dynamic linker and hijacked at runtime.
|
||||||
|
|
||||||
void* dlopen(const char* filename __unused, int flag __unused) { return 0; }
|
void* dlopen(const char* filename __unused, int flag __unused) { return 0; }
|
||||||
|
|
||||||
const char* dlerror(void) { return 0; }
|
const char* dlerror(void) { return 0; }
|
||||||
|
|
||||||
void* dlsym(void* handle __unused, const char* symbol __unused) { 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 dladdr(const void* addr __unused, Dl_info* info __unused) { return 0; }
|
||||||
|
|
||||||
int dlclose(void* handle __unused) { return 0; }
|
int dlclose(void* handle __unused) { return 0; }
|
||||||
|
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
|
@ -32,6 +32,7 @@ LIBC_N {
|
|||||||
global:
|
global:
|
||||||
android_init_namespaces;
|
android_init_namespaces;
|
||||||
android_create_namespace;
|
android_create_namespace;
|
||||||
|
dlvsym;
|
||||||
} LIBC;
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
|
@ -17,6 +17,7 @@ LIBC_N {
|
|||||||
global:
|
global:
|
||||||
android_init_namespaces;
|
android_init_namespaces;
|
||||||
android_create_namespace;
|
android_create_namespace;
|
||||||
|
dlvsym;
|
||||||
} LIBC;
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
|
@ -17,6 +17,7 @@ LIBC_N {
|
|||||||
global:
|
global:
|
||||||
android_init_namespaces;
|
android_init_namespaces;
|
||||||
android_create_namespace;
|
android_create_namespace;
|
||||||
|
dlvsym;
|
||||||
} LIBC;
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
|
@ -17,6 +17,7 @@ LIBC_N {
|
|||||||
global:
|
global:
|
||||||
android_init_namespaces;
|
android_init_namespaces;
|
||||||
android_create_namespace;
|
android_create_namespace;
|
||||||
|
dlvsym;
|
||||||
} LIBC;
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
|
@ -17,6 +17,7 @@ LIBC_N {
|
|||||||
global:
|
global:
|
||||||
android_init_namespaces;
|
android_init_namespaces;
|
||||||
android_create_namespace;
|
android_create_namespace;
|
||||||
|
dlvsym;
|
||||||
} LIBC;
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
|
@ -88,11 +88,10 @@ void* dlopen(const char* filename, int flags) {
|
|||||||
|
|
||||||
extern android_namespace_t* g_anonymous_namespace;
|
extern android_namespace_t* g_anonymous_namespace;
|
||||||
|
|
||||||
void* dlsym(void* handle, const char* symbol) {
|
void* dlsym_impl(void* handle, const char* symbol, const char* version, void* caller_addr) {
|
||||||
void* caller_addr = __builtin_return_address(0);
|
|
||||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||||
void* result;
|
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);
|
__bionic_format_dlerror(linker_get_error_buffer(), nullptr);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -100,6 +99,16 @@ void* dlsym(void* handle, const char* symbol) {
|
|||||||
return result;
|
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) {
|
int dladdr(const void* addr, Dl_info* info) {
|
||||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||||
return do_dladdr(addr, info);
|
return do_dladdr(addr, info);
|
||||||
@ -179,11 +188,11 @@ static const char ANDROID_LIBDL_STRTAB[] =
|
|||||||
// 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
|
// 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
|
||||||
// 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
|
// 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
|
||||||
"erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
|
"erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
|
||||||
// 0000000000111111 111122222222223333333333 4444444444555555555566666
|
// 0000000000111111 111122222222223333333333 4444444444555555555566666 6666677
|
||||||
// 0123456789012345 678901234567890123456789 0123456789012345678901234
|
// 0123456789012345 678901234567890123456789 0123456789012345678901234 5678901
|
||||||
"get_sdk_version\0android_init_namespaces\0android_create_namespace\0"
|
"get_sdk_version\0android_init_namespaces\0android_create_namespace\0dlvsym\0"
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
// 265
|
// 272
|
||||||
"dl_unwind_find_exidx\0"
|
"dl_unwind_find_exidx\0"
|
||||||
#endif
|
#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)(173, &android_get_application_target_sdk_version, 1),
|
||||||
ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
|
ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
|
||||||
ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
|
ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
|
||||||
|
ELFW(SYM_INITIALIZER)(265, &dlvsym, 1),
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
ELFW(SYM_INITIALIZER)(265, &dl_unwind_find_exidx, 1),
|
ELFW(SYM_INITIALIZER)(272, &dl_unwind_find_exidx, 1),
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -225,9 +235,9 @@ static ElfW(Sym) g_libdl_symtab[] = {
|
|||||||
// Note that adding any new symbols here requires stubbing them out in libdl.
|
// Note that adding any new symbols here requires stubbing them out in libdl.
|
||||||
static unsigned g_libdl_buckets[1] = { 1 };
|
static unsigned g_libdl_buckets[1] = { 1 };
|
||||||
#if defined(__arm__)
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
|
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
|
||||||
|
@ -2187,7 +2187,7 @@ static std::string symbol_display_name(const char* sym_name, const char* sym_ver
|
|||||||
return sym_name;
|
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) {
|
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;
|
version_info* vi = nullptr;
|
||||||
|
|
||||||
if (sym_ver != nullptr) {
|
if (sym_ver != nullptr) {
|
||||||
vi_instance.name = sym_name;
|
vi_instance.name = sym_ver;
|
||||||
vi_instance.elf_hash = calculate_elf_hash(sym_name);
|
vi_instance.elf_hash = calculate_elf_hash(sym_ver);
|
||||||
vi = &vi_instance;
|
vi = &vi_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,8 +624,10 @@ TEST(dlfcn, dlopen_check_loop) {
|
|||||||
handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
|
handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
|
||||||
ASSERT_TRUE(handle == nullptr);
|
ASSERT_TRUE(handle == nullptr);
|
||||||
#ifdef __BIONIC__
|
#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());
|
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
|
#endif
|
||||||
|
|
||||||
handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
|
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());
|
ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
|
||||||
#endif
|
#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.
|
// Symbol that doesn't exist.
|
||||||
sym = dlsym(self, "ThisSymbolDoesNotExist");
|
sym = dlsym(self, "ThisSymbolDoesNotExist");
|
||||||
ASSERT_TRUE(sym == nullptr);
|
ASSERT_TRUE(sym == nullptr);
|
||||||
@ -1054,6 +1048,26 @@ TEST(dlfcn, symbol_versioning_default_via_dlsym) {
|
|||||||
dlclose(handle);
|
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
|
// This preempts the implementation from libtest_versioned_lib.so
|
||||||
extern "C" int version_zero_function() {
|
extern "C" int version_zero_function() {
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user