summaryrefslogtreecommitdiff
path: root/linux/bfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/bfd.c')
-rw-r--r--linux/bfd.c105
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) */