summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fischer <matt.fischer@garmin.com>2009-12-31 12:17:40 -0600
committerGarmin Android technology group <android@garmin.com>2010-03-17 16:11:37 -0500
commite2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5 (patch)
treee5448ec45187a37dbade76fcf10115f91135a8bd
parentede2e75f4942293342dfb8dfd4751369600ed8f1 (diff)
downloadbionic-e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5.zip
bionic-e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5.tar.gz
bionic-e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5.tar.bz2
Added support for dladdr()
dladdr() is a GNU extension function, which allows the caller to retrieve symbol information for a specified memory address. It is useful for things like generating backtrace information at runtime. Change-Id: I3a1def1a6c9c666d93e1e97b7d260dfa5b9b79a9
-rw-r--r--libc/include/dlfcn.h12
-rw-r--r--libdl/libdl.c4
-rw-r--r--linker/dlfcn.c64
-rw-r--r--linker/linker.c34
-rw-r--r--linker/linker.h2
5 files changed, 101 insertions, 15 deletions
diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h
index 9582796..f84d1d1 100644
--- a/libc/include/dlfcn.h
+++ b/libc/include/dlfcn.h
@@ -32,10 +32,22 @@
__BEGIN_DECLS
+typedef struct {
+ const char *dli_fname; /* Pathname of shared object that
+ contains address */
+ void *dli_fbase; /* Address at which shared object
+ is loaded */
+ const char *dli_sname; /* Name of nearest symbol with address
+ lower than addr */
+ void *dli_saddr; /* Exact address of symbol named
+ 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(void* addr, Dl_info *info);
enum {
RTLD_NOW = 0,
diff --git a/libdl/libdl.c b/libdl/libdl.c
index 7971942..b36af16 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -14,12 +14,14 @@
* limitations under the License.
*/
+#include <dlfcn.h>
/* These are stubs for functions that are actually defined
* in the dynamic linker (dlfcn.c), and hijacked at runtime.
*/
void *dlopen(const char *filename, int flag) { return 0; }
-char *dlerror(void) { return 0; }
+const char *dlerror(void) { return 0; }
void *dlsym(void *handle, const char *symbol) { return 0; }
+int dladdr(void *addr, Dl_info *info) { return 0; }
int dlclose(void *handle) { return 0; }
#ifdef __arm__
diff --git a/linker/dlfcn.c b/linker/dlfcn.c
index 039926c..dcadce5 100644
--- a/linker/dlfcn.c
+++ b/linker/dlfcn.c
@@ -117,6 +117,37 @@ err:
return 0;
}
+int dladdr(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;
+ info->dli_fbase = (void*)si->base;
+
+ /* Determine if any symbol in the library contains the specified address */
+ Elf32_Sym *sym = find_containing_symbol(addr, si);
+
+ if(sym != NULL) {
+ info->dli_sname = si->strtab + sym->st_name;
+ info->dli_saddr = (void*)(si->base + sym->st_value);
+ }
+
+ ret = 1;
+ }
+
+ pthread_mutex_unlock(&dl_lock);
+
+ return ret;
+}
+
int dlclose(void *handle)
{
pthread_mutex_lock(&dl_lock);
@@ -126,22 +157,22 @@ int dlclose(void *handle)
}
#if defined(ANDROID_ARM_LINKER)
-// 0000000 00011111 111112 22222222 233333333334444444444
-// 0123456 78901234 567890 12345678 901234567890123456789
+// 0000000 00011111 111112 22222222 2333333 333344444444445555555
+// 0123456 78901234 567890 12345678 9012345 678901234567890123456
#define ANDROID_LIBDL_STRTAB \
- "dlopen\0dlclose\0dlsym\0dlerror\0dl_unwind_find_exidx\0"
+ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0"
#elif defined(ANDROID_X86_LINKER)
-// 0000000 00011111 111112 22222222 2333333333344444
-// 0123456 78901234 567890 12345678 9012345678901234
+// 0000000 00011111 111112 22222222 2333333 3333444444444455
+// 0123456 78901234 567890 12345678 9012345 6789012345678901
#define ANDROID_LIBDL_STRTAB \
- "dlopen\0dlclose\0dlsym\0dlerror\0dl_iterate_phdr\0"
+ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
#elif defined(ANDROID_SH_LINKER)
-// 0000000 00011111 111112 22222222 2333333333344444
-// 0123456 78901234 567890 12345678 9012345678901234
+// 0000000 00011111 111112 22222222 2333333 3333444444444455
+// 0123456 78901234 567890 12345678 9012345 6789012345678901
#define ANDROID_LIBDL_STRTAB \
- "dlopen\0dlclose\0dlsym\0dlerror\0dl_iterate_phdr\0"
+ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
#else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */
#error Unsupported architecture. Only ARM and x86 are presently supported.
@@ -175,20 +206,25 @@ static Elf32_Sym libdl_symtab[] = {
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
-#ifdef ANDROID_ARM_LINKER
{ 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)
- { st_name: 29,
+ { st_name: 36,
st_value: (Elf32_Addr) &dl_iterate_phdr,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
},
#elif defined(ANDROID_SH_LINKER)
- { st_name: 29,
+ { st_name: 36,
st_value: (Elf32_Addr) &dl_iterate_phdr,
st_info: STB_GLOBAL << 4,
st_shndx: 1,
@@ -216,7 +252,7 @@ static Elf32_Sym libdl_symtab[] = {
* stubbing them out in libdl.
*/
static unsigned libdl_buckets[1] = { 1 };
-static unsigned libdl_chains[6] = { 0, 2, 3, 4, 5, 0 };
+static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 };
soinfo libdl_info = {
name: "libdl.so",
@@ -226,7 +262,7 @@ soinfo libdl_info = {
symtab: libdl_symtab,
nbucket: 1,
- nchain: 6,
+ nchain: 7,
bucket: libdl_buckets,
chain: libdl_chains,
};
diff --git a/linker/linker.c b/linker/linker.c
index 6d57cbc..f5294d9 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -538,6 +538,40 @@ Elf32_Sym *lookup(const char *name, soinfo **found)
return 0;
}
+soinfo *find_containing_library(void *addr)
+{
+ soinfo *si;
+
+ for(si = solist; si != NULL; si = si->next)
+ {
+ if((unsigned)addr >= si->base && (unsigned)addr - si->base < si->size) {
+ return si;
+ }
+ }
+
+ return NULL;
+}
+
+Elf32_Sym *find_containing_symbol(void *addr, soinfo *si)
+{
+ unsigned int i;
+ unsigned soaddr = (unsigned)addr - si->base;
+
+ /* Search the library's symbol table for any defined symbol which
+ * contains this address */
+ for(i=0; i<si->nchain; i++) {
+ Elf32_Sym *sym = &si->symtab[i];
+
+ if(sym->st_shndx != SHN_UNDEF &&
+ soaddr >= sym->st_value &&
+ soaddr < sym->st_value + sym->st_size) {
+ return sym;
+ }
+ }
+
+ return NULL;
+}
+
#if 0
static void dump(soinfo *si)
{
diff --git a/linker/linker.h b/linker/linker.h
index ec01489..8cd56b0 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -225,6 +225,8 @@ soinfo *find_library(const char *name);
unsigned unload_library(soinfo *si);
Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
Elf32_Sym *lookup(const char *name, soinfo **found);
+soinfo *find_containing_library(void *addr);
+Elf32_Sym *find_containing_symbol(void *addr, soinfo *si);
const char *linker_get_error(void);
#ifdef ANDROID_ARM_LINKER