Support System.loadLibrary for libraries with transitive dependencies.
Also fix the FLAG_ERROR annoyance --- it's not helpful to cache failures. Bug: 7896159 Bug: http://code.google.com/p/android/issues/detail?id=34416 Bug: http://code.google.com/p/android/issues/detail?id=22143 Change-Id: I60f235edb4ea4756e1f7ce56f7739f18e8a50789
This commit is contained in:
parent
4b58214205
commit
cade4c36e7
@ -24,6 +24,8 @@ void *dlsym(void *handle, const char *symbol) { return 0; }
|
|||||||
int dladdr(const void *addr, Dl_info *info) { return 0; }
|
int dladdr(const void *addr, Dl_info *info) { return 0; }
|
||||||
int dlclose(void *handle) { return 0; }
|
int dlclose(void *handle) { return 0; }
|
||||||
|
|
||||||
|
void android_update_LD_LIBRARY_PATH(const char* ld_library_path) { }
|
||||||
|
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
|
|
||||||
void *dl_unwind_find_exidx(void *pc, int *pcount) { return 0; }
|
void *dl_unwind_find_exidx(void *pc, int *pcount) { return 0; }
|
||||||
|
@ -55,6 +55,11 @@ const char* dlerror() {
|
|||||||
return old_value;
|
return old_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
|
||||||
|
ScopedPthreadMutexLocker locker(&gDlMutex);
|
||||||
|
do_android_update_LD_LIBRARY_PATH(ld_library_path);
|
||||||
|
}
|
||||||
|
|
||||||
void* dlopen(const char* filename, int flags) {
|
void* dlopen(const char* filename, int flags) {
|
||||||
ScopedPthreadMutexLocker locker(&gDlMutex);
|
ScopedPthreadMutexLocker locker(&gDlMutex);
|
||||||
soinfo* result = do_dlopen(filename, flags);
|
soinfo* result = do_dlopen(filename, flags);
|
||||||
@ -141,16 +146,16 @@ int dlclose(void* handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ANDROID_ARM_LINKER)
|
#if defined(ANDROID_ARM_LINKER)
|
||||||
// 0000000 00011111 111112 22222222 2333333 333344444444445555555
|
// 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667
|
||||||
// 0123456 78901234 567890 12345678 9012345 678901234567890123456
|
// 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890
|
||||||
#define ANDROID_LIBDL_STRTAB \
|
#define ANDROID_LIBDL_STRTAB \
|
||||||
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0"
|
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_unwind_find_exidx\0"
|
||||||
|
|
||||||
#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
|
#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
|
||||||
// 0000000 00011111 111112 22222222 2333333 3333444444444455
|
// 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667
|
||||||
// 0123456 78901234 567890 12345678 9012345 6789012345678901
|
// 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890
|
||||||
#define ANDROID_LIBDL_STRTAB \
|
#define ANDROID_LIBDL_STRTAB \
|
||||||
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
|
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_iterate_phdr\0"
|
||||||
#else
|
#else
|
||||||
#error Unsupported architecture. Only ARM, MIPS, and x86 are presently supported.
|
#error Unsupported architecture. Only ARM, MIPS, and x86 are presently supported.
|
||||||
#endif
|
#endif
|
||||||
@ -175,10 +180,11 @@ static Elf32_Sym gLibDlSymtab[] = {
|
|||||||
ELF32_SYM_INITIALIZER(15, &dlsym, 1),
|
ELF32_SYM_INITIALIZER(15, &dlsym, 1),
|
||||||
ELF32_SYM_INITIALIZER(21, &dlerror, 1),
|
ELF32_SYM_INITIALIZER(21, &dlerror, 1),
|
||||||
ELF32_SYM_INITIALIZER(29, &dladdr, 1),
|
ELF32_SYM_INITIALIZER(29, &dladdr, 1),
|
||||||
|
ELF32_SYM_INITIALIZER(36, &android_update_LD_LIBRARY_PATH, 1),
|
||||||
#if defined(ANDROID_ARM_LINKER)
|
#if defined(ANDROID_ARM_LINKER)
|
||||||
ELF32_SYM_INITIALIZER(36, &dl_unwind_find_exidx, 1),
|
ELF32_SYM_INITIALIZER(67, &dl_unwind_find_exidx, 1),
|
||||||
#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
|
#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
|
||||||
ELF32_SYM_INITIALIZER(36, &dl_iterate_phdr, 1),
|
ELF32_SYM_INITIALIZER(67, &dl_iterate_phdr, 1),
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -201,7 +207,7 @@ static Elf32_Sym gLibDlSymtab[] = {
|
|||||||
// Note that adding any new symbols here requires
|
// Note that adding any new symbols here requires
|
||||||
// stubbing them out in libdl.
|
// stubbing them out in libdl.
|
||||||
static unsigned gLibDlBuckets[1] = { 1 };
|
static unsigned gLibDlBuckets[1] = { 1 };
|
||||||
static unsigned gLibDlChains[7] = { 0, 2, 3, 4, 5, 6, 0 };
|
static unsigned gLibDlChains[8] = { 0, 2, 3, 4, 5, 6, 7, 0 };
|
||||||
|
|
||||||
// This is used by the dynamic linker. Every process gets these symbols for free.
|
// This is used by the dynamic linker. Every process gets these symbols for free.
|
||||||
soinfo libdl_info = {
|
soinfo libdl_info = {
|
||||||
@ -218,7 +224,7 @@ soinfo libdl_info = {
|
|||||||
symtab: gLibDlSymtab,
|
symtab: gLibDlSymtab,
|
||||||
|
|
||||||
nbucket: 1,
|
nbucket: 1,
|
||||||
nchain: 7,
|
nchain: 8,
|
||||||
bucket: gLibDlBuckets,
|
bucket: gLibDlBuckets,
|
||||||
chain: gLibDlChains,
|
chain: gLibDlChains,
|
||||||
|
|
||||||
|
@ -351,6 +351,43 @@ static void soinfo_free(soinfo* si)
|
|||||||
gSoInfoFreeList = si;
|
gSoInfoFreeList = si;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void parse_path(const char* path, const char* delimiters,
|
||||||
|
const char** array, char* buf, size_t buf_size, size_t max_count) {
|
||||||
|
if (path == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlcpy(buf, path, buf_size);
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
char* buf_p = buf;
|
||||||
|
while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
|
||||||
|
if (*array[i] != '\0') {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forget the last path if we had to truncate; this occurs if the 2nd to
|
||||||
|
// last char isn't '\0' (i.e. wasn't originally a delimiter).
|
||||||
|
if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
|
||||||
|
array[i - 1] = NULL;
|
||||||
|
} else {
|
||||||
|
array[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_LD_LIBRARY_PATH(const char* path) {
|
||||||
|
parse_path(path, ":", gLdPaths,
|
||||||
|
gLdPathsBuffer, sizeof(gLdPathsBuffer), LDPATH_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_LD_PRELOAD(const char* path) {
|
||||||
|
// We have historically supported ':' as well as ' ' in LD_PRELOAD.
|
||||||
|
parse_path(path, " :", gLdPreloadNames,
|
||||||
|
gLdPreloadsBuffer, sizeof(gLdPreloadsBuffer), LDPRELOAD_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ANDROID_ARM_LINKER
|
#ifdef ANDROID_ARM_LINKER
|
||||||
|
|
||||||
/* For a given PC, find the .so that it belongs to.
|
/* For a given PC, find the .so that it belongs to.
|
||||||
@ -561,34 +598,28 @@ Elf32_Sym *soinfo_lookup(soinfo *si, const char *name)
|
|||||||
|
|
||||||
/* This is used by dl_sym(). It performs a global symbol lookup.
|
/* This is used by dl_sym(). It performs a global symbol lookup.
|
||||||
*/
|
*/
|
||||||
Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
|
Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start) {
|
||||||
{
|
unsigned elf_hash = elfhash(name);
|
||||||
unsigned elf_hash = elfhash(name);
|
|
||||||
Elf32_Sym *s = NULL;
|
|
||||||
soinfo *si;
|
|
||||||
|
|
||||||
if(start == NULL) {
|
if (start == NULL) {
|
||||||
start = solist;
|
start = solist;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf32_Sym* s = NULL;
|
||||||
|
for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
|
||||||
|
s = soinfo_elf_lookup(si, elf_hash, name);
|
||||||
|
if (s != NULL) {
|
||||||
|
*found = si;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(si = start; (s == NULL) && (si != NULL); si = si->next)
|
if (s != NULL) {
|
||||||
{
|
TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, found->base = 0x%08x\n",
|
||||||
if(si->flags & FLAG_ERROR)
|
name, s->st_value, (*found)->base);
|
||||||
continue;
|
}
|
||||||
s = soinfo_elf_lookup(si, elf_hash, name);
|
|
||||||
if (s != NULL) {
|
|
||||||
*found = si;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s != NULL) {
|
return s;
|
||||||
TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, si->base = 0x%08x\n",
|
|
||||||
name, s->st_value, si->base);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo *find_containing_library(const void *addr)
|
soinfo *find_containing_library(const void *addr)
|
||||||
@ -869,20 +900,6 @@ static soinfo* load_library(const char* name) {
|
|||||||
return si.release();
|
return si.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo* init_library(soinfo* si) {
|
|
||||||
// At this point we know that whatever is loaded @ base is a valid ELF
|
|
||||||
// shared library whose segments are properly mapped in.
|
|
||||||
TRACE("[ init_library base=0x%08x sz=0x%08x name='%s') ]\n",
|
|
||||||
si->base, si->size, si->name);
|
|
||||||
|
|
||||||
if (!soinfo_link_image(si)) {
|
|
||||||
munmap((void *)si->base, si->size);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return si;
|
|
||||||
}
|
|
||||||
|
|
||||||
static soinfo *find_loaded_library(const char *name)
|
static soinfo *find_loaded_library(const char *name)
|
||||||
{
|
{
|
||||||
soinfo *si;
|
soinfo *si;
|
||||||
@ -909,10 +926,6 @@ static soinfo* find_library_internal(const char* name) {
|
|||||||
|
|
||||||
soinfo* si = find_loaded_library(name);
|
soinfo* si = find_loaded_library(name);
|
||||||
if (si != NULL) {
|
if (si != NULL) {
|
||||||
if (si->flags & FLAG_ERROR) {
|
|
||||||
DL_ERR("\"%s\" failed to load previously", name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (si->flags & FLAG_LINKED) {
|
if (si->flags & FLAG_LINKED) {
|
||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
@ -922,8 +935,19 @@ static soinfo* find_library_internal(const char* name) {
|
|||||||
|
|
||||||
TRACE("[ '%s' has not been loaded yet. Locating...]\n", name);
|
TRACE("[ '%s' has not been loaded yet. Locating...]\n", name);
|
||||||
si = load_library(name);
|
si = load_library(name);
|
||||||
if (si != NULL) {
|
if (si == NULL) {
|
||||||
si = init_library(si);
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we know that whatever is loaded @ base is a valid ELF
|
||||||
|
// shared library whose segments are properly mapped in.
|
||||||
|
TRACE("[ init_library base=0x%08x sz=0x%08x name='%s') ]\n",
|
||||||
|
si->base, si->size, si->name);
|
||||||
|
|
||||||
|
if (!soinfo_link_image(si)) {
|
||||||
|
munmap(reinterpret_cast<void*>(si->base), si->size);
|
||||||
|
soinfo_free(si);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return si;
|
return si;
|
||||||
@ -966,6 +990,12 @@ static int soinfo_unload(soinfo* si) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
|
||||||
|
if (!get_AT_SECURE()) {
|
||||||
|
parse_LD_LIBRARY_PATH(ld_library_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
soinfo* do_dlopen(const char* name, int flags) {
|
soinfo* do_dlopen(const char* name, int flags) {
|
||||||
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL)) != 0) {
|
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL)) != 0) {
|
||||||
DL_ERR("invalid flags to dlopen: %x", flags);
|
DL_ERR("invalid flags to dlopen: %x", flags);
|
||||||
@ -1466,8 +1496,6 @@ static int nullify_closed_stdio() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool soinfo_link_image(soinfo* si) {
|
static bool soinfo_link_image(soinfo* si) {
|
||||||
si->flags |= FLAG_ERROR;
|
|
||||||
|
|
||||||
/* "base" might wrap around UINT32_MAX. */
|
/* "base" might wrap around UINT32_MAX. */
|
||||||
Elf32_Addr base = si->load_bias;
|
Elf32_Addr base = si->load_bias;
|
||||||
const Elf32_Phdr *phdr = si->phdr;
|
const Elf32_Phdr *phdr = si->phdr;
|
||||||
@ -1747,47 +1775,9 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
nullify_closed_stdio();
|
nullify_closed_stdio();
|
||||||
}
|
}
|
||||||
notify_gdb_of_load(si);
|
notify_gdb_of_load(si);
|
||||||
si->flags &= ~FLAG_ERROR;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_path(const char* path, const char* delimiters,
|
|
||||||
const char** array, char* buf, size_t buf_size, size_t max_count)
|
|
||||||
{
|
|
||||||
if (path == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = strlcpy(buf, path, buf_size);
|
|
||||||
|
|
||||||
size_t i = 0;
|
|
||||||
char* buf_p = buf;
|
|
||||||
while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
|
|
||||||
if (*array[i] != '\0') {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forget the last path if we had to truncate; this occurs if the 2nd to
|
|
||||||
// last char isn't '\0' (i.e. wasn't originally a delimiter).
|
|
||||||
if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
|
|
||||||
array[i - 1] = NULL;
|
|
||||||
} else {
|
|
||||||
array[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_LD_LIBRARY_PATH(const char* path) {
|
|
||||||
parse_path(path, ":", gLdPaths,
|
|
||||||
gLdPathsBuffer, sizeof(gLdPathsBuffer), LDPATH_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_LD_PRELOAD(const char* path) {
|
|
||||||
// We have historically supported ':' as well as ' ' in LD_PRELOAD.
|
|
||||||
parse_path(path, " :", gLdPreloadNames,
|
|
||||||
gLdPreloadsBuffer, sizeof(gLdPreloadsBuffer), LDPRELOAD_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This code is called after the linker has linked itself and
|
* This code is called after the linker has linked itself and
|
||||||
* fixed it's own GOT. It is safe to make references to externs
|
* fixed it's own GOT. It is safe to make references to externs
|
||||||
|
@ -72,7 +72,6 @@ struct r_debug {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define FLAG_LINKED 0x00000001
|
#define FLAG_LINKED 0x00000001
|
||||||
#define FLAG_ERROR 0x00000002
|
|
||||||
#define FLAG_EXE 0x00000004 // The main executable
|
#define FLAG_EXE 0x00000004 // The main executable
|
||||||
#define FLAG_LINKER 0x00000010 // The linker itself
|
#define FLAG_LINKER 0x00000010 // The linker itself
|
||||||
|
|
||||||
@ -207,6 +206,7 @@ extern soinfo libdl_info;
|
|||||||
#define DT_PREINIT_ARRAYSZ 33
|
#define DT_PREINIT_ARRAYSZ 33
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
|
||||||
soinfo* do_dlopen(const char* name, int flags);
|
soinfo* do_dlopen(const char* name, int flags);
|
||||||
int do_dlclose(soinfo* si);
|
int do_dlclose(soinfo* si);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user