#include "lstate.h" | |
#include "lobject.h" | |
#define __USE_GNU | |
#include <dlfcn.h> | |
#include <elf.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#define MAX_ELF_SYM_COUNT 128 | |
struct elf_syminfo { | |
int fd; | |
size_t sz; | |
const char* elf_path; | |
Elf64_Sym* symtab; | |
char *strtab; | |
size_t symcnt; | |
Elf64_Ehdr *header; | |
} ELF_SYM_LIST[MAX_ELF_SYM_COUNT] = {0}; | |
static struct elf_syminfo* | |
_get_syminfo(const char* elf_path) { | |
size_t i=0; | |
struct elf_syminfo* p = NULL; | |
for(i=0; i<MAX_ELF_SYM_COUNT; i++) { | |
p = &ELF_SYM_LIST[i]; | |
if(!p->elf_path) { | |
break; | |
} | |
if(strcmp(p->elf_path, elf_path) == 0) { | |
return p; | |
} | |
} | |
if(i== MAX_ELF_SYM_COUNT) { | |
return NULL; | |
} | |
int fd = open(elf_path, O_RDONLY); | |
if(fd <0) { | |
return NULL; | |
} | |
size_t sz = lseek(fd, 0, SEEK_END); | |
lseek(fd, 0, SEEK_SET); | |
Elf64_Ehdr *header = NULL; | |
Elf64_Shdr* symtab_section = NULL; | |
Elf64_Shdr* str_section = NULL; | |
header = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fd, 0); | |
if (header == MAP_FAILED || | |
memcmp(header->e_ident, ELFMAG, SELFMAG) != 0 || | |
header->e_ident[EI_DATA] != 1 || | |
header->e_ident[EI_CLASS] != 2) { | |
close(fd); | |
return NULL; | |
} | |
uint8_t* elf_header = (uint8_t*)header; | |
uint16_t e_shnum = header->e_shnum; | |
uint64_t e_shoff = header->e_shoff; | |
Elf64_Shdr* sections = (Elf64_Shdr*)(elf_header + e_shoff); | |
for(i=0; i<e_shnum; i++) { | |
if(sections[i].sh_type == SHT_SYMTAB) { | |
symtab_section = §ions[i]; | |
break; | |
} | |
} | |
Elf64_Sym* symtab = (Elf64_Sym*)(elf_header + symtab_section->sh_offset); | |
size_t symcnt = symtab_section->sh_size / sizeof(*symtab); | |
str_section = sections + symtab_section->sh_link; | |
char *strtab = (char*)(elf_header + str_section->sh_offset); | |
p->fd = fd; | |
p->sz = sz; | |
p->elf_path = elf_path; | |
p->symtab = symtab; | |
p->strtab = strtab; | |
p->symcnt = symcnt; | |
p->header = header; | |
return p; | |
} | |
static int | |
elfaddr(const void *addr, Dl_info *info) { | |
int ret = dladdr(addr, info); | |
if(ret ==0) { | |
return 0; | |
} | |
// get function from .dynsym | |
if(info->dli_sname && info->dli_saddr) { | |
return 1; | |
} | |
// get function from .symtab | |
const char* elf_path = info->dli_fname; | |
struct elf_syminfo* syminfo_p = _get_syminfo(elf_path); | |
if(!syminfo_p) { | |
return 1; | |
} | |
Elf64_Sym* symtab = syminfo_p->symtab; | |
size_t symcnt = syminfo_p->symcnt; | |
char *strtab = syminfo_p->strtab; | |
Elf64_Addr target_addr = (Elf64_Addr)addr - (Elf64_Addr)info->dli_fbase; | |
if(syminfo_p->header->e_type == ET_EXEC) { | |
target_addr = (Elf64_Addr)addr; | |
} | |
size_t i=0; | |
for(i=0; i<symcnt; i++) { | |
Elf64_Sym* p = &symtab[i]; | |
if(p->st_value == target_addr) { | |
info->dli_sname = &(strtab[p->st_name]); | |
info->dli_saddr = (void*)addr; | |
break; | |
} | |
} | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment