static int frame_callback(Dwfl_Frame *frame, void *data) { struct frame_callback_arg *frame_arg = data; char **error_msg = &frame_arg->error_msg; Dwarf_Addr pc; bool minus_one; if (!dwfl_frame_pc(frame, &pc, &minus_one)) { set_error_dwfl("dwfl_frame_pc"); return DWARF_CB_ABORT; } Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(frame)); struct sr_core_frame *result = resolve_frame(dwfl, pc, minus_one); /* Do not unwind below __libc_start_main. */ if (0 == sr_strcmp0(result->function_name, "__libc_start_main")) { sr_core_frame_free(result); return CB_STOP_UNWIND; } frame_arg->thread->frames = sr_core_frame_append(frame_arg->thread->frames, result); return DWARF_CB_OK; }
struct sr_core_stacktrace * sr_core_stacktrace_from_gdb(const char *gdb_output, const char *core_file, const char *exe_file, char **error_msg) { /* I'm not going to rewrite it now since the function is not being used. */ assert(error_msg); /* Initialize error_msg to 'no error'. */ *error_msg = NULL; struct core_handle *ch = open_coredump(core_file, exe_file, error_msg); if (*error_msg) return NULL; struct sr_gdb_stacktrace *gdb_stacktrace; struct sr_location location; sr_location_init(&location); gdb_stacktrace = sr_gdb_stacktrace_parse(&gdb_output, &location); if (!gdb_stacktrace) { *error_msg = sr_location_to_string(&location); core_handle_free(ch); return NULL; } struct sr_core_stacktrace *core_stacktrace = sr_core_stacktrace_new(); for (struct sr_gdb_thread *gdb_thread = gdb_stacktrace->threads; gdb_thread; gdb_thread = gdb_thread->next) { struct sr_core_thread *core_thread = sr_core_thread_new(); for (struct sr_gdb_frame *gdb_frame = gdb_thread->frames; gdb_frame; gdb_frame = gdb_frame->next) { if (gdb_frame->signal_handler_called) continue; struct sr_core_frame *core_frame = resolve_frame(ch->dwfl, gdb_frame->address, false); core_thread->frames = sr_core_frame_append(core_thread->frames, core_frame); } if (sr_gdb_stacktrace_find_crash_thread(gdb_stacktrace) == gdb_thread) { core_stacktrace->crash_thread = core_thread; } core_stacktrace->threads = sr_core_thread_append( core_stacktrace->threads, core_thread); } core_stacktrace->signal = get_signal_number(ch->eh, core_file); core_stacktrace->executable = realpath(exe_file, NULL); core_handle_free(ch); sr_gdb_stacktrace_free(gdb_stacktrace); return core_stacktrace; }
struct sr_core_stacktrace * sr_core_stacktrace_create(const char *gdb_stacktrace_text, const char *unstrip_text, const char *executable_path) { // Parse the GDB stacktrace. struct sr_location location; sr_location_init(&location); struct sr_gdb_stacktrace *gdb_stacktrace = sr_gdb_stacktrace_parse(&gdb_stacktrace_text, &location); if (!gdb_stacktrace) { warn("Unable to parse stacktrace: %d:%d: %s\n", location.line, location.column, location.message); return NULL; } // Parse the unstrip output. struct sr_unstrip_entry *unstrip = sr_unstrip_parse(unstrip_text); if (!unstrip) { warn("Unable to parse unstrip output."); sr_gdb_stacktrace_free(gdb_stacktrace); return NULL; } // Create the core stacktrace struct sr_core_stacktrace *core_stacktrace = sr_core_stacktrace_new(); struct sr_gdb_thread *gdb_thread = gdb_stacktrace->threads; while (gdb_thread) { struct sr_core_thread *core_thread = sr_core_thread_new(); struct sr_gdb_frame *gdb_frame = gdb_thread->frames; while (gdb_frame) { gdb_frame = gdb_frame->next; struct sr_core_frame *core_frame = sr_core_frame_new(); core_frame->address = gdb_frame->address; struct sr_unstrip_entry *unstrip_entry = sr_unstrip_find_address(unstrip, gdb_frame->address); if (unstrip_entry) { core_frame->build_id = sr_strdup(unstrip_entry->build_id); core_frame->build_id_offset = core_frame->address - unstrip_entry->start; core_frame->file_name = sr_strdup(unstrip_entry->file_name); } if (gdb_frame->function_name && 0 != strcmp(gdb_frame->function_name, "??")) { core_frame->function_name = sr_strdup(gdb_frame->function_name); } core_thread->frames = sr_core_frame_append(core_thread->frames, core_frame); } core_stacktrace->threads = sr_core_thread_append(core_stacktrace->threads, core_thread); gdb_thread = gdb_thread->next; } sr_unstrip_free(unstrip); sr_gdb_stacktrace_free(gdb_stacktrace); return core_stacktrace; }
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; }