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
|
||||
|
||||
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,
|
||||
|
@ -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__
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user