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
This commit is contained in:
parent
ede2e75f49
commit
e2a8b1fd19
@ -32,10 +32,22 @@
|
|||||||
|
|
||||||
__BEGIN_DECLS
|
__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 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);
|
||||||
|
extern int dladdr(void* addr, Dl_info *info);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RTLD_NOW = 0,
|
RTLD_NOW = 0,
|
||||||
|
@ -14,12 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
/* These are stubs for functions that are actually defined
|
/* These are stubs for functions that are actually defined
|
||||||
* in the dynamic linker (dlfcn.c), and hijacked at runtime.
|
* in the dynamic linker (dlfcn.c), and hijacked at runtime.
|
||||||
*/
|
*/
|
||||||
void *dlopen(const char *filename, int flag) { return 0; }
|
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; }
|
void *dlsym(void *handle, const char *symbol) { return 0; }
|
||||||
|
int dladdr(void *addr, Dl_info *info) { return 0; }
|
||||||
int dlclose(void *handle) { return 0; }
|
int dlclose(void *handle) { return 0; }
|
||||||
|
|
||||||
#ifdef __arm__
|
#ifdef __arm__
|
||||||
|
@ -117,6 +117,37 @@ err:
|
|||||||
return 0;
|
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)
|
int dlclose(void *handle)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&dl_lock);
|
pthread_mutex_lock(&dl_lock);
|
||||||
@ -126,22 +157,22 @@ int dlclose(void *handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ANDROID_ARM_LINKER)
|
#if defined(ANDROID_ARM_LINKER)
|
||||||
// 0000000 00011111 111112 22222222 233333333334444444444
|
// 0000000 00011111 111112 22222222 2333333 333344444444445555555
|
||||||
// 0123456 78901234 567890 12345678 901234567890123456789
|
// 0123456 78901234 567890 12345678 9012345 678901234567890123456
|
||||||
#define ANDROID_LIBDL_STRTAB \
|
#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)
|
#elif defined(ANDROID_X86_LINKER)
|
||||||
// 0000000 00011111 111112 22222222 2333333333344444
|
// 0000000 00011111 111112 22222222 2333333 3333444444444455
|
||||||
// 0123456 78901234 567890 12345678 9012345678901234
|
// 0123456 78901234 567890 12345678 9012345 6789012345678901
|
||||||
#define ANDROID_LIBDL_STRTAB \
|
#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)
|
#elif defined(ANDROID_SH_LINKER)
|
||||||
// 0000000 00011111 111112 22222222 2333333333344444
|
// 0000000 00011111 111112 22222222 2333333 3333444444444455
|
||||||
// 0123456 78901234 567890 12345678 9012345678901234
|
// 0123456 78901234 567890 12345678 9012345 6789012345678901
|
||||||
#define ANDROID_LIBDL_STRTAB \
|
#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) */
|
#else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */
|
||||||
#error Unsupported architecture. Only ARM and x86 are presently supported.
|
#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_info: STB_GLOBAL << 4,
|
||||||
st_shndx: 1,
|
st_shndx: 1,
|
||||||
},
|
},
|
||||||
#ifdef ANDROID_ARM_LINKER
|
|
||||||
{ st_name: 29,
|
{ 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_value: (Elf32_Addr) &dl_unwind_find_exidx,
|
||||||
st_info: STB_GLOBAL << 4,
|
st_info: STB_GLOBAL << 4,
|
||||||
st_shndx: 1,
|
st_shndx: 1,
|
||||||
},
|
},
|
||||||
#elif defined(ANDROID_X86_LINKER)
|
#elif defined(ANDROID_X86_LINKER)
|
||||||
{ st_name: 29,
|
{ st_name: 36,
|
||||||
st_value: (Elf32_Addr) &dl_iterate_phdr,
|
st_value: (Elf32_Addr) &dl_iterate_phdr,
|
||||||
st_info: STB_GLOBAL << 4,
|
st_info: STB_GLOBAL << 4,
|
||||||
st_shndx: 1,
|
st_shndx: 1,
|
||||||
},
|
},
|
||||||
#elif defined(ANDROID_SH_LINKER)
|
#elif defined(ANDROID_SH_LINKER)
|
||||||
{ st_name: 29,
|
{ st_name: 36,
|
||||||
st_value: (Elf32_Addr) &dl_iterate_phdr,
|
st_value: (Elf32_Addr) &dl_iterate_phdr,
|
||||||
st_info: STB_GLOBAL << 4,
|
st_info: STB_GLOBAL << 4,
|
||||||
st_shndx: 1,
|
st_shndx: 1,
|
||||||
@ -216,7 +252,7 @@ static Elf32_Sym libdl_symtab[] = {
|
|||||||
* stubbing them out in libdl.
|
* stubbing them out in libdl.
|
||||||
*/
|
*/
|
||||||
static unsigned libdl_buckets[1] = { 1 };
|
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 = {
|
soinfo libdl_info = {
|
||||||
name: "libdl.so",
|
name: "libdl.so",
|
||||||
@ -226,7 +262,7 @@ soinfo libdl_info = {
|
|||||||
symtab: libdl_symtab,
|
symtab: libdl_symtab,
|
||||||
|
|
||||||
nbucket: 1,
|
nbucket: 1,
|
||||||
nchain: 6,
|
nchain: 7,
|
||||||
bucket: libdl_buckets,
|
bucket: libdl_buckets,
|
||||||
chain: libdl_chains,
|
chain: libdl_chains,
|
||||||
};
|
};
|
||||||
|
@ -538,6 +538,40 @@ Elf32_Sym *lookup(const char *name, soinfo **found)
|
|||||||
return 0;
|
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
|
#if 0
|
||||||
static void dump(soinfo *si)
|
static void dump(soinfo *si)
|
||||||
{
|
{
|
||||||
|
@ -225,6 +225,8 @@ soinfo *find_library(const char *name);
|
|||||||
unsigned unload_library(soinfo *si);
|
unsigned unload_library(soinfo *si);
|
||||||
Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
|
Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
|
||||||
Elf32_Sym *lookup(const char *name, soinfo **found);
|
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);
|
const char *linker_get_error(void);
|
||||||
|
|
||||||
#ifdef ANDROID_ARM_LINKER
|
#ifdef ANDROID_ARM_LINKER
|
||||||
|
Loading…
x
Reference in New Issue
Block a user