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
diff --git a/libdl/libdl.c b/libdl/libdl.c
index e8b01be..378f521 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -24,6 +24,8 @@
int dladdr(const void *addr, Dl_info *info) { return 0; }
int dlclose(void *handle) { return 0; }
+void android_update_LD_LIBRARY_PATH(const char* ld_library_path) { }
+
#if defined(__arm__)
void *dl_unwind_find_exidx(void *pc, int *pcount) { return 0; }
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 2184f3a..a5f8944 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -55,6 +55,11 @@
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) {
ScopedPthreadMutexLocker locker(&gDlMutex);
soinfo* result = do_dlopen(filename, flags);
@@ -141,16 +146,16 @@
}
#if defined(ANDROID_ARM_LINKER)
-// 0000000 00011111 111112 22222222 2333333 333344444444445555555
-// 0123456 78901234 567890 12345678 9012345 678901234567890123456
+// 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667
+// 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890
#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)
-// 0000000 00011111 111112 22222222 2333333 3333444444444455
-// 0123456 78901234 567890 12345678 9012345 6789012345678901
+// 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667
+// 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890
#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
#error Unsupported architecture. Only ARM, MIPS, and x86 are presently supported.
#endif
@@ -175,10 +180,11 @@
ELF32_SYM_INITIALIZER(15, &dlsym, 1),
ELF32_SYM_INITIALIZER(21, &dlerror, 1),
ELF32_SYM_INITIALIZER(29, &dladdr, 1),
+ ELF32_SYM_INITIALIZER(36, &android_update_LD_LIBRARY_PATH, 1),
#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)
- ELF32_SYM_INITIALIZER(36, &dl_iterate_phdr, 1),
+ ELF32_SYM_INITIALIZER(67, &dl_iterate_phdr, 1),
#endif
};
@@ -201,7 +207,7 @@
// Note that adding any new symbols here requires
// stubbing them out in libdl.
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.
soinfo libdl_info = {
@@ -218,7 +224,7 @@
symtab: gLibDlSymtab,
nbucket: 1,
- nchain: 7,
+ nchain: 8,
bucket: gLibDlBuckets,
chain: gLibDlChains,
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 0bdff99..6a2a958 100755
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -351,6 +351,43 @@
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
/* For a given PC, find the .so that it belongs to.
@@ -561,34 +598,28 @@
/* This is used by dl_sym(). It performs a global symbol lookup.
*/
-Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
-{
- unsigned elf_hash = elfhash(name);
- Elf32_Sym *s = NULL;
- soinfo *si;
+Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start) {
+ unsigned elf_hash = elfhash(name);
- if(start == NULL) {
- start = solist;
+ if (start == NULL) {
+ 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(si->flags & FLAG_ERROR)
- continue;
- s = soinfo_elf_lookup(si, elf_hash, name);
- if (s != NULL) {
- *found = si;
- break;
- }
- }
+ if (s != NULL) {
+ TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, found->base = 0x%08x\n",
+ name, s->st_value, (*found)->base);
+ }
- if(s != NULL) {
- TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, si->base = 0x%08x\n",
- name, s->st_value, si->base);
- return s;
- }
-
- return NULL;
+ return s;
}
soinfo *find_containing_library(const void *addr)
@@ -869,20 +900,6 @@
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)
{
soinfo *si;
@@ -909,10 +926,6 @@
soinfo* si = find_loaded_library(name);
if (si != NULL) {
- if (si->flags & FLAG_ERROR) {
- DL_ERR("\"%s\" failed to load previously", name);
- return NULL;
- }
if (si->flags & FLAG_LINKED) {
return si;
}
@@ -922,8 +935,19 @@
TRACE("[ '%s' has not been loaded yet. Locating...]\n", name);
si = load_library(name);
- if (si != NULL) {
- si = init_library(si);
+ if (si == NULL) {
+ 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;
@@ -966,6 +990,12 @@
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) {
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL)) != 0) {
DL_ERR("invalid flags to dlopen: %x", flags);
@@ -1466,8 +1496,6 @@
}
static bool soinfo_link_image(soinfo* si) {
- si->flags |= FLAG_ERROR;
-
/* "base" might wrap around UINT32_MAX. */
Elf32_Addr base = si->load_bias;
const Elf32_Phdr *phdr = si->phdr;
@@ -1747,47 +1775,9 @@
nullify_closed_stdio();
}
notify_gdb_of_load(si);
- si->flags &= ~FLAG_ERROR;
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
* fixed it's own GOT. It is safe to make references to externs
diff --git a/linker/linker.h b/linker/linker.h
index 60c76fa..377ba15 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -72,7 +72,6 @@
};
#define FLAG_LINKED 0x00000001
-#define FLAG_ERROR 0x00000002
#define FLAG_EXE 0x00000004 // The main executable
#define FLAG_LINKER 0x00000010 // The linker itself
@@ -207,6 +206,7 @@
#define DT_PREINIT_ARRAYSZ 33
#endif
+void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
soinfo* do_dlopen(const char* name, int flags);
int do_dlclose(soinfo* si);