static int frame_callback(Dwfl_Frame *frame, void *userdata) { struct stack_context *c = userdata; Dwarf_Addr pc, pc_adjusted, bias = 0; _cleanup_free_ Dwarf_Die *scopes = NULL; const char *fname = NULL, *symbol = NULL; Dwfl_Module *module; bool is_activation; assert(frame); assert(c); if (c->n_frame >= FRAMES_MAX) return DWARF_CB_ABORT; if (!dwfl_frame_pc(frame, &pc, &is_activation)) return DWARF_CB_ABORT; pc_adjusted = pc - (is_activation ? 0 : 1); module = dwfl_addrmodule(c->dwfl, pc_adjusted); if (module) { Dwarf_Die *s, *cudie; int n; cudie = dwfl_module_addrdie(module, pc_adjusted, &bias); if (cudie) { n = dwarf_getscopes(cudie, pc_adjusted - bias, &scopes); for (s = scopes; s < scopes + n; s++) { if (IN_SET(dwarf_tag(s), DW_TAG_subprogram, DW_TAG_inlined_subroutine, DW_TAG_entry_point)) { Dwarf_Attribute *a, space; a = dwarf_attr_integrate(s, DW_AT_MIPS_linkage_name, &space); if (!a) a = dwarf_attr_integrate(s, DW_AT_linkage_name, &space); if (a) symbol = dwarf_formstring(a); if (!symbol) symbol = dwarf_diename(s); if (symbol) break; } } } if (!symbol) symbol = dwfl_module_addrname(module, pc_adjusted); fname = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } fprintf(c->f, "#%-2u 0x%016" PRIx64 " %s (%s)\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname)); c->n_frame ++; return DWARF_CB_OK; }
static struct frame* unwind_thread(Dwfl *dwfl, unw_addr_space_t as, struct UCD_info *ui, int thread_no, struct expr_context *ctx) { info("thread %d:", thread_no); int i, ret; unw_cursor_t c, c_cfa; _UCD_select_thread(ui, thread_no); ret = unw_init_remote(&c, as, ui); fail_if(ret < 0, "unw_init_remote"); ret = unw_init_remote(&c_cfa, as, ui); fail_if(ret < 0, "unw_init_remote"); struct frame *head = NULL, *tail = NULL; /* infinite loop insurance */ int count = 1000; while (--count > 0) { unw_word_t ip; ret = unw_get_reg(&c, UNW_REG_IP, &ip); fail_if(ret < 0, "unw_get_reg"); if (ip == 0) break; unw_word_t off; char funcname[10*1024]; funcname[0] = '\0'; ret = unw_get_proc_name(&c, funcname, sizeof(funcname)-1, &off); if (ret < 0) { warn("unw_get_proc_name failed for IP %lx", (unsigned long)ip); } info("\t%llx %s", (unsigned long long)ip, funcname); /* According to spec[1], CFA is RSP of the previous frame. However, * libunwind returns CFA = RSP of the current frame. So we need to keep * track of the previous (i.e. next to be unwound) frame. * * [1] System V Application Binary Interface AMD64 Architecture * Processor Supplement * http://www.x86-64.org/documentation/abi.pdf */ ctx->cfa = 0; ret = unw_step(&c_cfa); if (ret > 0) { unw_word_t cfa; ret = unw_get_reg(&c_cfa, UNW_X86_64_CFA, &cfa); if (ret == 0) { ctx->cfa = (Dwarf_Addr)cfa; } } /* find compilation unit owning the IP */ Dwarf_Die *cu = dwfl_addrdie(dwfl, (Dwarf_Addr)ip, &(ctx->bias)); if (!cu) { warn("\t\tcannot find CU for ip %lx", (unsigned long)ip); goto synth_frame; } if (!supported_language(cu)) { warn("\t\tunsupported CU language"); goto synth_frame; } /* needed by child_variables */ Dwarf_Files *files; ret = dwarf_getsrcfiles(cu, &files, NULL); fail_if(ret == -1, "dwarf_getsrcfiles"); /* dwarf expression evaluation needs register values */ ctx->curs = &c; ctx->ip = (Dwarf_Addr)ip; /* TODO: subtract 1 as this is return address? */ /* TODO: we have CU - fall back to CU name if subprogram not found */ /* Following code deals with inlined functions, which do not have their * own stack frame. It is somewhat ugly due to two constraints: * - we want to produce at least one frame even if analyze_scopes * fails * - we may want to further process the frame that is returned the * last, i.e. the one that belongs to the non-inlined function */ Dwarf_Die *scopes; int nscopes = dwarf_getscopes(cu, (Dwarf_Addr)ip, &scopes); struct frame *frame = analyze_scopes(&scopes, &nscopes, ctx, files, false); if (frame == NULL) { goto synth_frame; } struct frame *last_frame; while (frame) { list_append(head, tail, frame); last_frame = frame; frame = analyze_scopes(&scopes, &nscopes, ctx, files, true); } frame = last_frame; /* frame->ip = (uint64_t)ip; */ goto next; synth_frame: /* synthesize frame even though we have no other information except * that it's there */ frame = xalloc(sizeof(*frame)); list_append(head, tail, frame); /* frame->ip = (uint64_t)ip; */ next: ret = unw_step(&c); fail_if(ret < 0, "unw_step"); if (ret == 0) break; } return head; }