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; }
int coredump_make_stack_trace(int fd, const char *executable, char **ret) { static const Dwfl_Callbacks callbacks = { .find_elf = dwfl_build_id_find_elf, .find_debuginfo = dwfl_standard_find_debuginfo, }; struct stack_context c = {}; char *buf = NULL; size_t sz = 0; int r; assert(fd >= 0); assert(ret); if (lseek(fd, 0, SEEK_SET) == (off_t) -1) return -errno; c.f = open_memstream(&buf, &sz); if (!c.f) return -ENOMEM; elf_version(EV_CURRENT); c.elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); if (!c.elf) { r = -EINVAL; goto finish; } c.dwfl = dwfl_begin(&callbacks); if (!c.dwfl) { r = -EINVAL; goto finish; } if (dwfl_core_file_report(c.dwfl, c.elf, executable) < 0) { r = -EINVAL; goto finish; } if (dwfl_report_end(c.dwfl, NULL, NULL) != 0) { r = -EINVAL; goto finish; } if (dwfl_core_file_attach(c.dwfl, c.elf) < 0) { r = -EINVAL; goto finish; } if (dwfl_getthreads(c.dwfl, thread_callback, &c) < 0) { r = -EINVAL; goto finish; } c.f = safe_fclose(c.f); *ret = buf; buf = NULL; r = 0; finish: if (c.dwfl) dwfl_end(c.dwfl); if (c.elf) elf_end(c.elf); safe_fclose(c.f); free(buf); return r; }