static int get_signal_number_libunwind(struct UCD_info *ui) { int tnum, nthreads = _UCD_get_num_threads(ui); for (tnum = 0; tnum < nthreads; ++tnum) { _UCD_select_thread(ui, tnum); int signo = _UCD_get_cursig(ui); /* Return first nonzero signal, gdb/bfd seem to work this way. */ if (signo) return signo; } return 0; }
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; }
static struct sr_core_thread * unwind_thread(struct UCD_info *ui, unw_addr_space_t as, Dwfl *dwfl, int thread_no, char **error_msg) { int ret; unw_cursor_t c; struct sr_core_frame *trace = NULL; _UCD_select_thread(ui, thread_no); ret = unw_init_remote(&c, as, ui); if (ret < 0) { set_error("unw_init_remote failed: %s", unw_strerror(ret)); return NULL; } int count = 1000; while (--count > 0) { unw_word_t ip; ret = unw_get_reg(&c, UNW_REG_IP, &ip); if (ret < 0) warn("unw_get_reg(UNW_REG_IP) failed: %s", unw_strerror(ret)); /* Seen this happen when unwinding thread that did not start * in main(). */ if (ip == 0) break; struct sr_core_frame *entry = resolve_frame(dwfl, ip, false); if (!entry->function_name) { size_t funcname_len = 512; char *funcname = sr_malloc(funcname_len); if (unw_get_proc_name(&c, funcname, funcname_len, NULL) == 0) entry->function_name = funcname; else free(funcname); } trace = sr_core_frame_append(trace, entry); /* printf("%s 0x%llx %s %s -\n", (ip_seg && ip_seg->build_id) ? ip_seg->build_id : "-", (unsigned long long)(ip_seg ? ip - ip_seg->vaddr : ip), (entry->symbol ? entry->symbol : "-"), (ip_seg && ip_seg->filename) ? ip_seg->filename : "-"); */ /* Do not unwind below __libc_start_main. */ if (0 == sr_strcmp0(entry->function_name, "__libc_start_main")) break; ret = unw_step(&c); if (ret == 0) break; if (ret < 0) { warn("unw_step failed: %s", unw_strerror(ret)); break; } } if (error_msg && !*error_msg && !trace) { set_error("No frames found for thread %d", thread_no); } struct sr_core_thread *thread = sr_core_thread_new(); thread->frames = trace; return thread; }