diff options
Diffstat (limited to 'linux/bfd.c')
-rw-r--r-- | linux/bfd.c | 105 |
1 files changed, 81 insertions, 24 deletions
diff --git a/linux/bfd.c b/linux/bfd.c index cfa55ecd..69f4da59 100644 --- a/linux/bfd.c +++ b/linux/bfd.c @@ -21,6 +21,8 @@ * */ +#if !defined(_HF_LINUX_NO_BFD) + #include "linux/bfd.h" #include <bfd.h> @@ -40,10 +42,17 @@ #include "libhfcommon/log.h" #include "libhfcommon/util.h" +#if !defined(bfd_get_section_size) +#define bfd_get_section_size(section) bfd_section_size(section) +#endif /* !defined(bfd_get_section_size) */ +#if !defined(bfd_get_section_vma) +#define bfd_get_section_vma(ptr, section) bfd_section_vma(section) +#endif /* !defined(bfd_get_section_size) */ + typedef struct { - bfd* bfdh; - asection* section; + bfd* bfdh; asymbol** syms; + asymbol** dsyms; } bfd_t; /* @@ -74,14 +83,16 @@ static bool arch_bfdInit(pid_t pid, bfd_t* bfdParams) { LOG_E("bfd_get_symtab_upper_bound() returned '%d'", storage_needed); return false; } - - bfdParams->syms = (asymbol**)util_Malloc(storage_needed); + bfdParams->syms = (asymbol**)util_Calloc(storage_needed); bfd_canonicalize_symtab(bfdParams->bfdh, bfdParams->syms); - if ((bfdParams->section = bfd_get_section_by_name(bfdParams->bfdh, ".text")) == NULL) { - LOG_E("bfd_get_section_by_name('.text') failed"); + storage_needed = bfd_get_dynamic_symtab_upper_bound(bfdParams->bfdh); + if (storage_needed <= 0) { + LOG_E("bfd_get_dynamic_symtab_upper_bound() returned '%d'", storage_needed); return false; } + bfdParams->dsyms = (asymbol**)util_Calloc(storage_needed); + bfd_canonicalize_dynamic_symtab(bfdParams->bfdh, bfdParams->dsyms); return true; } @@ -89,43 +100,87 @@ static bool arch_bfdInit(pid_t pid, bfd_t* bfdParams) { static void arch_bfdDestroy(bfd_t* bfdParams) { if (bfdParams->syms) { free(bfdParams->syms); + bfdParams->syms = NULL; + } + if (bfdParams->dsyms) { + free(bfdParams->dsyms); + bfdParams->dsyms = NULL; } if (bfdParams->bfdh) { bfd_close(bfdParams->bfdh); + bfdParams->bfdh = NULL; + } +} + +void arch_bfdDemangle(funcs_t* funcs, size_t funcCnt) { + /* From -liberty, should be depended on by (included with) libbfd */ + __attribute__((weak)) char* cplus_demangle(const char* mangled, int options); + if (!cplus_demangle) { + return; + } + for (size_t i = 0; i < funcCnt; i++) { + if (strncmp(funcs[i].func, "_Z", 2) == 0) { + char* new_name = cplus_demangle(funcs[i].func, 0); + if (new_name) { + snprintf(funcs[i].func, sizeof(funcs[i].func), "%s", new_name); + free(new_name); + } + } } } +static struct bfd_section* arch_getSectionForPc(bfd* bfdh, uint64_t pc) { + for (struct bfd_section* section = bfdh->sections; section; section = section->next) { + uintptr_t vma = (uintptr_t)bfd_get_section_vma(bfdh, section); + uintptr_t sz = (uintptr_t)bfd_get_section_size(section); + if ((pc > vma) && (pc < (vma + sz))) { + return section; + } + } + return NULL; +} + void arch_bfdResolveSyms(pid_t pid, funcs_t* funcs, size_t num) { /* Guess what? libbfd is not multi-threading safe */ MX_SCOPED_LOCK(&arch_bfd_mutex); bfd_init(); - __block bfd_t bfdParams = { - .bfdh = NULL, - .section = NULL, - .syms = NULL, + bfd_t bfdParams = { + .bfdh = NULL, + .syms = NULL, + .dsyms = NULL, }; - if (arch_bfdInit(pid, &bfdParams) == false) { + if (!arch_bfdInit(pid, &bfdParams)) { return; } - const char* func; - const char* file; + const char* func; + const char* file; unsigned int line; for (unsigned int i = 0; i < num; i++) { - snprintf(funcs[i].func, sizeof(funcs->func), "[UNKNOWN]"); + snprintf(funcs[i].func, sizeof(funcs->func), "UNKNOWN"); if (funcs[i].pc == NULL) { continue; } - long offset = (long)funcs[i].pc - bfdParams.section->vma; - if ((offset < 0 || (unsigned long)offset > bfdParams.section->size)) { + struct bfd_section* section = arch_getSectionForPc(bfdParams.bfdh, (uintptr_t)funcs[i].pc); + if (section == NULL) { continue; } + + long sec_offset = (long)funcs[i].pc - bfd_get_section_vma(bfdParams.bfdh, section); + + if (bfd_find_nearest_line( + bfdParams.bfdh, section, bfdParams.syms, sec_offset, &file, &func, &line) == TRUE) { + snprintf(funcs[i].func, sizeof(funcs->func), "%s", func ? func : ""); + snprintf(funcs[i].file, sizeof(funcs->file), "%s", file ? file : ""); + funcs[i].line = line; + } if (bfd_find_nearest_line( - bfdParams.bfdh, bfdParams.section, bfdParams.syms, offset, &file, &func, &line)) { - snprintf(funcs[i].func, sizeof(funcs->func), "%s", func); + bfdParams.bfdh, section, bfdParams.syms, sec_offset, &file, &func, &line) == TRUE) { + snprintf(funcs[i].func, sizeof(funcs->func), "%s", func ? func : ""); + snprintf(funcs[i].file, sizeof(funcs->file), "%s", file ? file : ""); funcs[i].line = line; } } @@ -165,7 +220,7 @@ void arch_bfdDisasm(pid_t pid, uint8_t* mem, size_t size, char* instr) { disassembler(bfd_get_arch(bfdh), bfd_little_endian(bfdh) ? FALSE : TRUE, 0, NULL); #else disassembler_ftype disassemble = disassembler(bfdh); -#endif // defined(_HD_BFD_GE_2_29) +#endif // defined(_HD_BFD_GE_2_29) if (disassemble == NULL) { LOG_W("disassembler() failed"); bfd_close(bfdh); @@ -174,12 +229,12 @@ void arch_bfdDisasm(pid_t pid, uint8_t* mem, size_t size, char* instr) { struct disassemble_info info; init_disassemble_info(&info, instr, arch_bfdFPrintF); - info.arch = bfd_get_arch(bfdh); - info.mach = bfd_get_mach(bfdh); - info.buffer = mem; + info.arch = bfd_get_arch(bfdh); + info.mach = bfd_get_mach(bfdh); + info.buffer = mem; info.buffer_length = size; - info.section = NULL; - info.endian = bfd_little_endian(bfdh) ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; + info.section = NULL; + info.endian = bfd_little_endian(bfdh) ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; disassemble_init_for_target(&info); strcpy(instr, ""); @@ -189,3 +244,5 @@ void arch_bfdDisasm(pid_t pid, uint8_t* mem, size_t size, char* instr) { bfd_close(bfdh); } + +#endif /* !defined(_HF_LINUX_NO_BFD) */ |