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 core_handle * open_coredump(const char *elf_file, const char *exe_file, char **error_msg) { struct core_handle *ch = sr_mallocz(sizeof(*ch)); struct exe_mapping_data *head = NULL, **tail = &head; /* Initialize libelf, open the file and get its Elf handle. */ if (elf_version(EV_CURRENT) == EV_NONE) { set_error_elf("elf_version"); goto fail_free; } /* Open input file, and parse it. */ ch->fd = open(elf_file, O_RDONLY); if (ch->fd < 0) { set_error("Unable to open '%s': %s", elf_file, strerror(errno)); goto fail_free; } ch->eh = elf_begin(ch->fd, ELF_C_READ_MMAP, NULL); if (ch->eh == NULL) { set_error_elf("elf_begin"); goto fail_close; } /* Check that we are working with a coredump. */ GElf_Ehdr ehdr; if (gelf_getehdr(ch->eh, &ehdr) == NULL || ehdr.e_type != ET_CORE) { set_error("File '%s' is not a coredump", elf_file); goto fail_elf; } executable_file = exe_file; ch->cb.find_elf = find_elf_core; ch->cb.find_debuginfo = find_debuginfo_none; ch->cb.section_address = dwfl_offline_section_address; ch->dwfl = dwfl_begin(&ch->cb); #if _ELFUTILS_PREREQ(0, 158) if (dwfl_core_file_report(ch->dwfl, ch->eh, exe_file) == -1) #else if (dwfl_core_file_report(ch->dwfl, ch->eh) == -1) #endif { set_error_dwfl("dwfl_core_file_report"); goto fail_dwfl; } if (dwfl_report_end(ch->dwfl, NULL, NULL) != 0) { set_error_dwfl("dwfl_report_end"); goto fail_dwfl; } /* needed so that module filenames are available during unwinding */ ptrdiff_t ret = dwfl_getmodules(ch->dwfl, touch_module, &tail, 0); if (ret == -1) { set_error_dwfl("dwfl_getmodules"); goto fail_dwfl; } ch->segments = head; if (!head) { if (error_msg && !*error_msg) set_error("No segments found in coredump '%s'", elf_file); goto fail_dwfl; } return ch; fail_dwfl: dwfl_end(ch->dwfl); fail_elf: elf_end(ch->eh); fail_close: close(ch->fd); fail_free: free(ch); return NULL; }
struct sr_core_stacktrace * sr_parse_coredump_maps(const char *core_file, const char *exe_file, const char *maps_file, char **error_msg) { struct sr_core_stacktrace *stacktrace = NULL; /* Initialize error_msg to 'no error'. */ if (error_msg) *error_msg = NULL; struct core_handle *ch = open_coredump(core_file, exe_file, maps_file, error_msg); if (!ch) goto fail; if (dwfl_core_file_attach(ch->dwfl, ch->eh) < 0) { set_error_dwfl("dwfl_core_file_attach"); goto fail; } stacktrace = sr_core_stacktrace_new(); if (!stacktrace) { set_error("Failed to initialize stacktrace memory"); goto fail; } struct thread_callback_arg thread_arg = { .stacktrace = stacktrace, .error_msg = NULL }; int ret = dwfl_getthreads(ch->dwfl, unwind_thread, &thread_arg); if (ret != 0) { if (ret == -1) set_error_dwfl("dwfl_getthreads"); else if (ret == DWARF_CB_ABORT) { set_error("%s", thread_arg.error_msg); free(thread_arg.error_msg); } else set_error("Unknown error in dwfl_getthreads"); sr_core_stacktrace_free(stacktrace); stacktrace = NULL; goto fail; } stacktrace->executable = sr_strdup(exe_file); stacktrace->signal = get_signal_number(ch->eh, core_file); /* FIXME: is this the best we can do? */ stacktrace->crash_thread = stacktrace->threads; fail: core_handle_free(ch); return stacktrace; }