struct thread* unwind_stacks(Dwfl *dwfl, const char *core_file, struct exec_map *em, struct expr_context *ctx) { unw_addr_space_t as; struct UCD_info *ui; struct thread *head = NULL, *tail = NULL; as = unw_create_addr_space(&_UCD_accessors, 0); fail_if(!as, "unw_create_addr_space"); ui = _UCD_create(core_file); fail_if(!ui, "_UCD_create"); for (; em != NULL; em = em->next) { if (_UCD_add_backing_file_at_vaddr(ui, em->vaddr, em->file) < 0) { fail("_UCD_add_backing_file_at_vaddr"); } } int tnum; int nthreads = _UCD_get_num_threads(ui); for (tnum = 0; tnum < nthreads; tnum++) { struct thread *thread = xalloc(sizeof(struct thread)); thread->frames = unwind_thread(dwfl, as, ui, tnum, ctx); list_append(head, tail, thread); } return head; }
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; }
struct sr_core_stacktrace * sr_parse_coredump(const char *core_file, const char *exe_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, error_msg); if (*error_msg) return NULL; unw_addr_space_t as; struct UCD_info *ui; as = unw_create_addr_space(&_UCD_accessors, 0); if (!as) { set_error("Failed to create address space"); goto fail_destroy_handle; } ui = _UCD_create(core_file); if (!ui) { set_error("Failed to set up core dump accessors for '%s'", core_file); goto fail_destroy_as; } struct exe_mapping_data *s; for (s = ch->segments; s != NULL; s = s->next) { if (_UCD_add_backing_file_at_vaddr(ui, s->start, s->filename) < 0) { /* Sometimes produces: * >_UCD_add_backing_file_at_segment: * Error reading from '/usr/lib/modules/3.6.9-2.fc17.x86_64/vdso/vdso.so' * Ignore errors for now & fail later. */ warn("Can't add backing file '%s' at addr 0x%jx", s->filename, (uintmax_t)s->start); /* goto fail_destroy_ui; */ } } stacktrace = sr_core_stacktrace_new(); int tnum, nthreads = _UCD_get_num_threads(ui); for (tnum = 0; tnum < nthreads; ++tnum) { struct sr_core_thread *trace = unwind_thread(ui, as, ch->dwfl, tnum, error_msg); if (trace) { stacktrace->threads = sr_core_thread_append(stacktrace->threads, trace); } else { sr_core_stacktrace_free(stacktrace); stacktrace = NULL; break; } } stacktrace->executable = realpath(exe_file, NULL); stacktrace->signal = get_signal_number_libunwind(ui); /* FIXME: is this the best we can do? */ stacktrace->crash_thread = stacktrace->threads; _UCD_destroy(ui); fail_destroy_as: unw_destroy_addr_space(as); fail_destroy_handle: core_handle_free(ch); return stacktrace; }