static int handle_cfi (Dwfl *dwfl, const char *which, Dwarf_CFI *cfi, GElf_Addr pc, struct stuff *stuff) { int result = dwarf_cfi_addrframe (cfi, pc - stuff->bias, &stuff->frame); if (result != 0) { error (0, 0, "dwarf_addrframe (%s): %s", which, dwfl_errmsg (-1)); return 1; } Dwarf_Addr start = pc; Dwarf_Addr end = pc; bool signalp; int ra_regno = dwarf_frame_info (stuff->frame, &start, &end, &signalp); if (ra_regno >= 0) { start += stuff->bias; end += stuff->bias; } printf ("%s has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "):\n", which, pc, start, end); if (ra_regno < 0) printf ("\treturn address register unavailable (%s)\n", dwarf_errmsg (0)); else printf ("\treturn address in reg%u%s\n", ra_regno, signalp ? " (signal frame)" : ""); Dwarf_Op *cfa_ops; size_t cfa_nops; result = dwarf_frame_cfa (stuff->frame, &cfa_ops, &cfa_nops); printf ("\tCFA "); print_detail (result, cfa_ops, cfa_nops, stuff->bias); (void) dwfl_module_register_names (dwfl_addrmodule (dwfl, pc), &print_register, stuff); return 0; }
/* * Return: * 0 if return address for the program counter @pc is on stack * 1 if return address is in LR and no new stack frame was allocated * 2 if return address is in LR and a new frame was allocated (but not * yet used) * -1 in case of errors */ static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc) { int rc = -1; Dwfl *dwfl; Dwfl_Module *mod; Dwarf_Frame *frame; int ra_regno; Dwarf_Addr start = pc; Dwarf_Addr end = pc; bool signalp; const char *exec_file = dso->long_name; dwfl = dso->dwfl; if (!dwfl) { dwfl = dwfl_begin(&offline_callbacks); if (!dwfl) { pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1)); return -1; } mod = dwfl_report_elf(dwfl, exec_file, exec_file, -1, map_start, false); if (!mod) { pr_debug("dwfl_report_elf() failed %s\n", dwarf_errmsg(-1)); /* * We normally cache the DWARF debug info and never * call dwfl_end(). But to prevent fd leak, free in * case of error. */ dwfl_end(dwfl); goto out; } dso->dwfl = dwfl; } mod = dwfl_addrmodule(dwfl, pc); if (!mod) { pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1)); goto out; } /* * To work with split debug info files (eg: glibc), check both * .eh_frame and .debug_frame sections of the ELF header. */ frame = get_eh_frame(mod, pc); if (!frame) { frame = get_dwarf_frame(mod, pc); if (!frame) goto out; } ra_regno = dwarf_frame_info(frame, &start, &end, &signalp); if (ra_regno < 0) { pr_debug("Return address register unavailable: %s\n", dwarf_errmsg(-1)); goto out; } rc = check_return_reg(ra_regno, frame); out: return rc; }