diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp index 9e6d92e5d..4190a1df6 100644 --- a/libc/bionic/malloc_debug_check.cpp +++ b/libc/bionic/malloc_debug_check.cpp @@ -26,31 +26,30 @@ * SUCH DAMAGE. */ -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include #include +#include +#include +#include +#include #include "dlmalloc.h" #include "logd.h" - -#include "malloc_debug_common.h" #include "malloc_debug_check_mapinfo.h" +#include "malloc_debug_common.h" +#include "ScopedPthreadMutexLocker.h" static mapinfo *milist; diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp index adcc238c8..0594c0aa8 100644 --- a/libc/bionic/malloc_debug_common.cpp +++ b/libc/bionic/malloc_debug_common.cpp @@ -40,12 +40,15 @@ * or static (libc.a) linking. */ -#include -#include -#include -#include "dlmalloc.h" #include "malloc_debug_common.h" +#include +#include +#include + +#include "dlmalloc.h" +#include "ScopedPthreadMutexLocker.h" + /* * In a VM process, this is set to 1 after fork()ing out of zygote. */ diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h index 45b4e3645..78ad5e595 100644 --- a/libc/bionic/malloc_debug_common.h +++ b/libc/bionic/malloc_debug_common.h @@ -33,6 +33,8 @@ #ifndef MALLOC_DEBUG_COMMON_H #define MALLOC_DEBUG_COMMON_H +#include + #define HASHTABLE_SIZE 1543 #define BACKTRACE_SIZE 32 /* flag definitions, currently sharing storage with "size" */ @@ -101,18 +103,4 @@ typedef void (*MallocDebugFini)(); #define info_log(format, ...) \ __libc_android_log_print(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ ) -class ScopedPthreadMutexLocker { - public: - explicit ScopedPthreadMutexLocker(pthread_mutex_t* mu) : mu_(mu) { - pthread_mutex_lock(mu_); - } - - ~ScopedPthreadMutexLocker() { - pthread_mutex_unlock(mu_); - } - - private: - pthread_mutex_t* mu_; -}; - #endif // MALLOC_DEBUG_COMMON_H diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp index ca00d4d9b..090a98185 100644 --- a/libc/bionic/malloc_debug_leak.cpp +++ b/libc/bionic/malloc_debug_leak.cpp @@ -26,6 +26,7 @@ * SUCH DAMAGE. */ +#include #include #include #include @@ -36,19 +37,18 @@ #include #include #include -#include -#include - -#include #include #include #include #include #include +#include +#include #include "dlmalloc.h" #include "logd.h" #include "malloc_debug_common.h" +#include "ScopedPthreadMutexLocker.h" // This file should be included into the build only when // MALLOC_LEAK_CHECK, or MALLOC_QEMU_INSTRUMENT, or both diff --git a/libc/private/ScopedPthreadMutexLocker.h b/libc/private/ScopedPthreadMutexLocker.h new file mode 100644 index 000000000..06b8e37b2 --- /dev/null +++ b/libc/private/ScopedPthreadMutexLocker.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SCOPED_PTHREAD_MUTEX_LOCKER_H +#define SCOPED_PTHREAD_MUTEX_LOCKER_H + +#include + +class ScopedPthreadMutexLocker { + public: + explicit ScopedPthreadMutexLocker(pthread_mutex_t* mu) : mu_(mu) { + pthread_mutex_lock(mu_); + } + + ~ScopedPthreadMutexLocker() { + pthread_mutex_unlock(mu_); + } + + private: + pthread_mutex_t* mu_; + + // Disallow copy and assignment. + ScopedPthreadMutexLocker(const ScopedPthreadMutexLocker&); + void operator=(const ScopedPthreadMutexLocker&); +}; + +#endif // SCOPED_PTHREAD_MUTEX_LOCKER_H diff --git a/linker/Android.mk b/linker/Android.mk index 7b5da6294..2d198272e 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -4,7 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ arch/$(TARGET_ARCH)/begin.S \ debugger.c \ - dlfcn.c \ + dlfcn.cpp \ linker.cpp \ linker_environ.c \ linker_format.c \ diff --git a/linker/dlfcn.c b/linker/dlfcn.c deleted file mode 100644 index 920137e8e..000000000 --- a/linker/dlfcn.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include "linker.h" -#include "linker_format.h" - -/* This file hijacks the symbols stubbed out in libdl.so. */ - -#define DL_SUCCESS 0 -#define DL_ERR_CANNOT_LOAD_LIBRARY 1 -#define DL_ERR_INVALID_LIBRARY_HANDLE 2 -#define DL_ERR_BAD_SYMBOL_NAME 3 -#define DL_ERR_SYMBOL_NOT_FOUND 4 -#define DL_ERR_SYMBOL_NOT_GLOBAL 5 - -static char dl_err_buf[1024]; -static const char *dl_err_str; - -static const char *dl_errors[] = { - [DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library", - [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle", - [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name", - [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found", - [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global", -}; - -#define likely(expr) __builtin_expect (expr, 1) -#define unlikely(expr) __builtin_expect (expr, 0) - -pthread_mutex_t dl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; - -static void set_dlerror(int err) -{ - format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err], - linker_get_error()); - dl_err_str = (const char *)&dl_err_buf[0]; -}; - -void *dlopen(const char *filename, int flag) -{ - soinfo *ret; - - pthread_mutex_lock(&dl_lock); - ret = find_library(filename); - if (unlikely(ret == NULL)) { - set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY); - } else { - soinfo_call_constructors(ret); - ret->refcount++; - } - pthread_mutex_unlock(&dl_lock); - return ret; -} - -const char *dlerror(void) -{ - const char *tmp = dl_err_str; - dl_err_str = NULL; - return (const char *)tmp; -} - -void *dlsym(void *handle, const char *symbol) -{ - soinfo *found; - Elf32_Sym *sym; - unsigned bind; - - pthread_mutex_lock(&dl_lock); - - if(unlikely(handle == 0)) { - set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE); - goto err; - } - if(unlikely(symbol == 0)) { - set_dlerror(DL_ERR_BAD_SYMBOL_NAME); - goto err; - } - - if(handle == RTLD_DEFAULT) { - sym = lookup(symbol, &found, NULL); - } else if(handle == RTLD_NEXT) { - void *ret_addr = __builtin_return_address(0); - soinfo *si = find_containing_library(ret_addr); - - sym = NULL; - if(si && si->next) { - sym = lookup(symbol, &found, si->next); - } - } else { - found = (soinfo*)handle; - sym = soinfo_lookup(found, symbol); - } - - if(likely(sym != 0)) { - bind = ELF32_ST_BIND(sym->st_info); - - if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { - unsigned ret = sym->st_value + found->load_bias; - pthread_mutex_unlock(&dl_lock); - return (void*)ret; - } - - set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL); - } - else - set_dlerror(DL_ERR_SYMBOL_NOT_FOUND); - -err: - pthread_mutex_unlock(&dl_lock); - return 0; -} - -int dladdr(const void *addr, Dl_info *info) -{ - int ret = 0; - - pthread_mutex_lock(&dl_lock); - - /* Determine if this address can be found in any library currently mapped */ - soinfo *si = find_containing_library(addr); - - if(si) { - memset(info, 0, sizeof(Dl_info)); - - info->dli_fname = si->name; - /* Address at which the shared object is loaded */ - info->dli_fbase = (void*)si->base; - - /* Determine if any symbol in the library contains the specified address */ - Elf32_Sym *sym = soinfo_find_symbol(si, addr); - - if(sym != NULL) { - info->dli_sname = si->strtab + sym->st_name; - info->dli_saddr = (void*)(si->load_bias + sym->st_value); - } - - ret = 1; - } - - pthread_mutex_unlock(&dl_lock); - - return ret; -} - -int dlclose(void* handle) { - pthread_mutex_lock(&dl_lock); - int result = soinfo_unload((soinfo*)handle); - pthread_mutex_unlock(&dl_lock); - return result; -} - -#if defined(ANDROID_ARM_LINKER) -// 0000000 00011111 111112 22222222 2333333 333344444444445555555 -// 0123456 78901234 567890 12345678 9012345 678901234567890123456 -#define ANDROID_LIBDL_STRTAB \ - "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0" - -#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER) -// 0000000 00011111 111112 22222222 2333333 3333444444444455 -// 0123456 78901234 567890 12345678 9012345 6789012345678901 -#define ANDROID_LIBDL_STRTAB \ - "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" -#else -#error Unsupported architecture. Only ARM, MIPS, and x86 are presently supported. -#endif - - -static Elf32_Sym libdl_symtab[] = { - // total length of libdl_info.strtab, including trailing 0 - // This is actually the the STH_UNDEF entry. Technically, it's - // supposed to have st_name == 0, but instead, it points to an index - // in the strtab with a \0 to make iterating through the symtab easier. - { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1, - }, - { st_name: 0, // starting index of the name in libdl_info.strtab - st_value: (Elf32_Addr) &dlopen, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 7, - st_value: (Elf32_Addr) &dlclose, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 15, - st_value: (Elf32_Addr) &dlsym, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 21, - st_value: (Elf32_Addr) &dlerror, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 29, - st_value: (Elf32_Addr) &dladdr, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, -#ifdef ANDROID_ARM_LINKER - { st_name: 36, - st_value: (Elf32_Addr) &dl_unwind_find_exidx, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, -#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER) - { st_name: 36, - st_value: (Elf32_Addr) &dl_iterate_phdr, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, -#endif -}; - -/* Fake out a hash table with a single bucket. - * A search of the hash table will look through - * libdl_symtab starting with index [1], then - * use libdl_chains to find the next index to - * look at. libdl_chains should be set up to - * walk through every element in libdl_symtab, - * and then end with 0 (sentinel value). - * - * I.e., libdl_chains should look like - * { 0, 2, 3, ... N, 0 } where N is the number - * of actual symbols, or nelems(libdl_symtab)-1 - * (since the first element of libdl_symtab is not - * a real symbol). - * - * (see _elf_lookup()) - * - * Note that adding any new symbols here requires - * stubbing them out in libdl. - */ -static unsigned libdl_buckets[1] = { 1 }; -static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 }; - -soinfo libdl_info = { - name: "libdl.so", - flags: FLAG_LINKED, - - strtab: ANDROID_LIBDL_STRTAB, - symtab: libdl_symtab, - - nbucket: 1, - nchain: 7, - bucket: libdl_buckets, - chain: libdl_chains, -}; diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp new file mode 100644 index 000000000..8486bfa36 --- /dev/null +++ b/linker/dlfcn.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "linker.h" +#include "linker_format.h" + +/* This file hijacks the symbols stubbed out in libdl.so. */ + +static char dl_err_buf[1024]; +static const char* dl_err_str; + +#define likely(expr) __builtin_expect (expr, 1) +#define unlikely(expr) __builtin_expect (expr, 0) + +pthread_mutex_t dl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; + +static void set_dlerror(const char* msg, const char* detail) { + if (detail != NULL) { + format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", msg, detail); + } else { + format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s", msg); + } + dl_err_str = (const char*) &dl_err_buf[0]; +} + +void *dlopen(const char* filename, int flag) { + ScopedPthreadMutexLocker locker(&dl_lock); + soinfo* result = find_library(filename); + if (result == NULL) { + set_dlerror("dlopen failed", linker_get_error()); + return NULL; + } + soinfo_call_constructors(result); + result->refcount++; + return result; +} + +const char* dlerror() { + const char* old_value = dl_err_str; + dl_err_str = NULL; + return (const char*) old_value; +} + +void* dlsym(void* handle, const char* symbol) { + ScopedPthreadMutexLocker locker(&dl_lock); + + if (unlikely(handle == 0)) { + set_dlerror("dlsym library handle is null", NULL); + return NULL; + } + if (unlikely(symbol == 0)) { + set_dlerror("dlsym symbol name is null", NULL); + return NULL; + } + + soinfo* found = NULL; + Elf32_Sym* sym = NULL; + if (handle == RTLD_DEFAULT) { + sym = lookup(symbol, &found, NULL); + } else if (handle == RTLD_NEXT) { + void* ret_addr = __builtin_return_address(0); + soinfo* si = find_containing_library(ret_addr); + + sym = NULL; + if (si && si->next) { + sym = lookup(symbol, &found, si->next); + } + } else { + found = (soinfo*) handle; + sym = soinfo_lookup(found, symbol); + } + + if (likely(sym != 0)) { + unsigned bind = ELF32_ST_BIND(sym->st_info); + + if (likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { + unsigned ret = sym->st_value + found->load_bias; + return (void*) ret; + } + + set_dlerror("symbol found but not global", symbol); + return NULL; + } else { + set_dlerror("undefined symbol", symbol); + return NULL; + } +} + +int dladdr(const void* addr, Dl_info* info) { + ScopedPthreadMutexLocker locker(&dl_lock); + + // Determine if this address can be found in any library currently mapped. + soinfo* si = find_containing_library(addr); + if (si == NULL) { + return 0; + } + + memset(info, 0, sizeof(Dl_info)); + + info->dli_fname = si->name; + // Address at which the shared object is loaded. + info->dli_fbase = (void*) si->base; + + // Determine if any symbol in the library contains the specified address. + Elf32_Sym *sym = soinfo_find_symbol(si, addr); + if (sym != NULL) { + info->dli_sname = si->strtab + sym->st_name; + info->dli_saddr = (void*)(si->load_bias + sym->st_value); + } + + return 1; +} + +int dlclose(void* handle) { + ScopedPthreadMutexLocker locker(&dl_lock); + return soinfo_unload((soinfo*) handle); +} + +#if defined(ANDROID_ARM_LINKER) +// 0000000 00011111 111112 22222222 2333333 333344444444445555555 +// 0123456 78901234 567890 12345678 9012345 678901234567890123456 +#define ANDROID_LIBDL_STRTAB \ + "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0" + +#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER) +// 0000000 00011111 111112 22222222 2333333 3333444444444455 +// 0123456 78901234 567890 12345678 9012345 6789012345678901 +#define ANDROID_LIBDL_STRTAB \ + "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" +#else +#error Unsupported architecture. Only ARM, MIPS, and x86 are presently supported. +#endif + +// name_offset: starting index of the name in libdl_info.strtab +#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \ + { name_offset, \ + reinterpret_cast(reinterpret_cast(value)), \ + /* st_size */ 0, \ + (shndx == 0) ? 0 : (STB_GLOBAL << 4), \ + /* st_other */ 0, \ + shndx } + +static Elf32_Sym libdl_symtab[] = { + // Total length of libdl_info.strtab, including trailing 0. + // This is actually the STH_UNDEF entry. Technically, it's + // supposed to have st_name == 0, but instead, it points to an index + // in the strtab with a \0 to make iterating through the symtab easier. + ELF32_SYM_INITIALIZER(sizeof(ANDROID_LIBDL_STRTAB) - 1, NULL, 0), + ELF32_SYM_INITIALIZER( 0, &dlopen, 1), + ELF32_SYM_INITIALIZER( 7, &dlclose, 1), + ELF32_SYM_INITIALIZER(15, &dlsym, 1), + ELF32_SYM_INITIALIZER(21, &dlerror, 1), + ELF32_SYM_INITIALIZER(29, &dladdr, 1), +#if defined(ANDROID_ARM_LINKER) + ELF32_SYM_INITIALIZER(36, &dl_unwind_find_exidx, 1), +#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER) + ELF32_SYM_INITIALIZER(36, &dl_iterate_phdr, 1), +#endif +}; + +/* Fake out a hash table with a single bucket. + * A search of the hash table will look through + * libdl_symtab starting with index [1], then + * use libdl_chains to find the next index to + * look at. libdl_chains should be set up to + * walk through every element in libdl_symtab, + * and then end with 0 (sentinel value). + * + * I.e., libdl_chains should look like + * { 0, 2, 3, ... N, 0 } where N is the number + * of actual symbols, or nelems(libdl_symtab)-1 + * (since the first element of libdl_symtab is not + * a real symbol). + * + * (see _elf_lookup()) + * + * Note that adding any new symbols here requires + * stubbing them out in libdl. + */ +static unsigned libdl_buckets[1] = { 1 }; +static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 }; + +soinfo libdl_info = { + name: "libdl.so", + + phdr: 0, phnum: 0, + entry: 0, base: 0, size: 0, + unused: 0, dynamic: 0, unused2: 0, unused3: 0, + next: 0, + + flags: FLAG_LINKED, + + strtab: ANDROID_LIBDL_STRTAB, + symtab: libdl_symtab, + + nbucket: 1, + nchain: 7, + bucket: libdl_buckets, + chain: libdl_chains, + + plt_got: 0, plt_rel: 0, plt_rel_count: 0, rel: 0, rel_count: 0, + preinit_array: 0, preinit_array_count: 0, init_array: 0, init_array_count: 0, + fini_array: 0, fini_array_count: 0, init_func: 0, fini_func: 0, + +#if defined(ANDROID_ARM_LINKER) + ARM_exidx: 0, ARM_exidx_count: 0, +#elif defined(ANDROID_MIPS_LINKER) + mips_symtabno: 0, mips_local_gotno: 0, mips_gotsym: 0, +#endif + + refcount: 0, + { l_addr: 0, l_name: 0, l_ld: 0, l_next: 0, l_prev: 0, }, + constructors_called: 0, load_bias: 0, has_text_relocations: 0, +}; diff --git a/linker/linker.cpp b/linker/linker.cpp index 998e608ef..6e1c60443 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -43,6 +43,7 @@ // Private C library headers. #include #include +#include #include "linker.h" #include "linker_debug.h" @@ -161,12 +162,9 @@ DISALLOW_ALLOCATION(void*, calloc, (size_t u1 UNUSED, size_t u2 UNUSED)); static char tmp_err_buf[768]; static char __linker_dl_err_buf[768]; -#define BASENAME(s) (strrchr(s, '/') != NULL ? strrchr(s, '/') + 1 : s) #define DL_ERR(fmt, x...) \ do { \ - format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), \ - "%s(%s:%d): " fmt, \ - __FUNCTION__, BASENAME(__FILE__), __LINE__, ##x); \ + format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), fmt, ##x); \ ERROR(fmt "\n", ##x); \ } while(0) @@ -185,7 +183,7 @@ static r_debug _r_debug = {1, NULL, &rtld_db_dlactivity, RT_CONSISTENT, 0}; static link_map* r_debug_tail = 0; -static pthread_mutex_t _r_debug_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t gDebugMutex = PTHREAD_MUTEX_INITIALIZER; static void insert_soinfo_into_debug_map(soinfo * info) { // Copy the necessary fields into the debug structure. @@ -232,7 +230,7 @@ static void notify_gdb_of_load(soinfo* info) { return; } - pthread_mutex_lock(&_r_debug_lock); + ScopedPthreadMutexLocker locker(&gDebugMutex); _r_debug.r_state = RT_ADD; rtld_db_dlactivity(); @@ -241,8 +239,6 @@ static void notify_gdb_of_load(soinfo* info) { _r_debug.r_state = RT_CONSISTENT; rtld_db_dlactivity(); - - pthread_mutex_unlock(&_r_debug_lock); } static void notify_gdb_of_unload(soinfo* info) { @@ -251,7 +247,7 @@ static void notify_gdb_of_unload(soinfo* info) { return; } - pthread_mutex_lock(&_r_debug_lock); + ScopedPthreadMutexLocker locker(&gDebugMutex); _r_debug.r_state = RT_DELETE; rtld_db_dlactivity(); @@ -260,8 +256,6 @@ static void notify_gdb_of_unload(soinfo* info) { _r_debug.r_state = RT_CONSISTENT; rtld_db_dlactivity(); - - pthread_mutex_unlock(&_r_debug_lock); } extern "C" void notify_gdb_of_libraries() @@ -345,7 +339,7 @@ static void soinfo_free(soinfo* si) * * Intended to be called by libc's __gnu_Unwind_Find_exidx(). * - * This function is exposed via dlfcn.c and libdl.so. + * This function is exposed via dlfcn.cpp and libdl.so. */ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) { diff --git a/tests/dlopen_test.cpp b/tests/dlopen_test.cpp index 2fcfa0c85..5ef32ad29 100644 --- a/tests/dlopen_test.cpp +++ b/tests/dlopen_test.cpp @@ -24,14 +24,19 @@ #include +#define ASSERT_SUBSTR(needle, haystack) \ + ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack) + static bool gCalled = false; extern "C" void DlSymTestFunction() { gCalled = true; } TEST(dlopen, dlsym_in_self) { + dlerror(); // Clear any pending errors. void* self = dlopen(NULL, RTLD_NOW); ASSERT_TRUE(self != NULL); + ASSERT_TRUE(dlerror() == NULL); void* sym = dlsym(self, "DlSymTestFunction"); ASSERT_TRUE(sym != NULL); @@ -43,9 +48,52 @@ TEST(dlopen, dlsym_in_self) { ASSERT_TRUE(gCalled); } -TEST(dlopen, dladdr) { +TEST(dlopen, dlopen_failure) { + void* self = dlopen("/does/not/exist", RTLD_NOW); + ASSERT_TRUE(self == NULL); +#if __BIONIC__ + ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror()); +#else + ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror()); +#endif +} + +TEST(dlopen, dlsym_failures) { + dlerror(); // Clear any pending errors. void* self = dlopen(NULL, RTLD_NOW); ASSERT_TRUE(self != NULL); + ASSERT_TRUE(dlerror() == NULL); + + void* sym; + + // NULL handle. + sym = dlsym(NULL, "test"); + ASSERT_TRUE(sym == NULL); +#if __BIONIC__ + ASSERT_SUBSTR("dlsym library handle is null", dlerror()); +#else + ASSERT_SUBSTR("undefined symbol: test", dlerror()); // glibc isn't specific about the failure. +#endif + + // NULL symbol name. +#if __BIONIC__ + // glibc marks this parameter non-null and SEGVs if you cheat. + sym = dlsym(self, NULL); + ASSERT_TRUE(sym == NULL); + ASSERT_SUBSTR("", dlerror()); +#endif + + // Symbol that doesn't exist. + sym = dlsym(self, "ThisSymbolDoesNotExist"); + ASSERT_TRUE(sym == NULL); + ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror()); +} + +TEST(dlopen, dladdr) { + dlerror(); // Clear any pending errors. + void* self = dlopen(NULL, RTLD_NOW); + ASSERT_TRUE(self != NULL); + ASSERT_TRUE(dlerror() == NULL); void* sym = dlsym(self, "DlSymTestFunction"); ASSERT_TRUE(sym != NULL); @@ -102,9 +150,13 @@ TEST(dlopen, dladdr) { TEST(dlopen, dladdr_invalid) { Dl_info info; + dlerror(); // Clear any pending errors. + // No symbol corresponding to NULL. ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success. + ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3). // No symbol corresponding to a stack address. ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success. + ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3). }