static int debuginfo__init_offline_dwarf(struct debuginfo *self, const char *path) { Dwfl_Module *mod; int fd; fd = open(path, O_RDONLY); if (fd < 0) return fd; self->dwfl = dwfl_begin(&offline_callbacks); if (!self->dwfl) goto error; mod = dwfl_report_offline(self->dwfl, "", "", fd); if (!mod) goto error; self->dbg = dwfl_module_getdwarf(mod, &self->bias); if (!self->dbg) goto error; return 0; error: if (self->dwfl) dwfl_end(self->dwfl); else close(fd); memset(self, 0, sizeof(*self)); return -ENOENT; }
/* Get a Dwarf from offline image */ static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, const char *path) { int fd; fd = open(path, O_RDONLY); if (fd < 0) return fd; dbg->dwfl = dwfl_begin(&offline_callbacks); if (!dbg->dwfl) goto error; dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); if (!dbg->mod) goto error; dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); if (!dbg->dbg) goto error; return 0; error: if (dbg->dwfl) dwfl_end(dbg->dwfl); else close(fd); memset(dbg, 0, sizeof(*dbg)); return -ENOENT; }
/* Get a Dwarf from live kernel image */ static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, Dwarf_Addr *bias) { Dwarf *dbg; if (!dwflp) return NULL; *dwflp = dwfl_begin(&kernel_callbacks); if (!*dwflp) return NULL; /* Load the kernel dwarves: Don't care the result here */ dwfl_linux_kernel_report_kernel(*dwflp); dwfl_linux_kernel_report_modules(*dwflp); dbg = dwfl_addrdwarf(*dwflp, addr, bias); /* Here, check whether we could get a real dwarf */ if (!dbg) { pr_debug("Failed to find kernel dwarf at %lx\n", (unsigned long)addr); dwfl_end(*dwflp); *dwflp = NULL; } return dbg; }
struct refl * refl_begin (void) { struct refl *result = malloc (sizeof (*result)); if (result == NULL) { __refl_seterr (REFL_E_SYSTEM); return NULL; } Dwfl *dwfl = dwfl_begin (&callbacks); if (dwfl == NULL) { __refl_seterr (REFL_E_DWFL); goto err_out; } dwfl_report_begin (dwfl); int status = dwfl_linux_proc_report (dwfl, getpid ()); dwfl_report_end (dwfl, NULL, NULL); if (status < 0) { __refl_seterr (REFL_E_DWFL); goto err_out; } result->dwfl = dwfl; return result; err_out: free (result); return NULL; }
// Create a libdw session with DWARF information for all loaded modules LibdwSession *libdwInit() { LibdwSession *session = stgCallocBytes(1, sizeof(LibdwSession), "libdwInit"); // Initialize ELF library if (elf_version(EV_CURRENT) == EV_NONE) { sysErrorBelch("libelf version too old!"); return NULL; } // Initialize a libdwfl session static char *debuginfo_path; static const Dwfl_Callbacks proc_callbacks = { .find_debuginfo = dwfl_standard_find_debuginfo, .debuginfo_path = &debuginfo_path, .find_elf = dwfl_linux_proc_find_elf, }; session->dwfl = dwfl_begin (&proc_callbacks); if (session->dwfl == NULL) { sysErrorBelch("dwfl_begin failed: %s", dwfl_errmsg(dwfl_errno())); free(session); return NULL; } // Report the loaded modules int ret = dwfl_linux_proc_report(session->dwfl, getpid()); if (ret < 0) { sysErrorBelch("dwfl_linux_proc_report failed: %s", dwfl_errmsg(dwfl_errno())); goto fail; } if (dwfl_report_end (session->dwfl, NULL, NULL) != 0) { sysErrorBelch("dwfl_report_end failed: %s", dwfl_errmsg(dwfl_errno())); goto fail; } pid_t pid = getpid(); if (! dwfl_attach_state(session->dwfl, NULL, pid, &thread_cbs, NULL)) { sysErrorBelch("dwfl_attach_state failed: %s", dwfl_errmsg(dwfl_errno())); goto fail; } return session; fail: dwfl_end(session->dwfl); free(session); return NULL; }
int main (void) { Dwfl *dwfl = dwfl_begin (&callbacks); for (int i = 0; i < 5; ++i) { dwfl_report_begin (dwfl); dwfl_report_module (dwfl, "module1", 0, 10); dwfl_report_end (dwfl, NULL, NULL); } dwfl_end (dwfl); return 0; }
static Dwfl * pid_to_dwfl (pid_t pid) { static char *debuginfo_path; static const Dwfl_Callbacks proc_callbacks = { .find_debuginfo = dwfl_standard_find_debuginfo, .debuginfo_path = &debuginfo_path, .find_elf = dwfl_linux_proc_find_elf, }; Dwfl *dwfl = dwfl_begin (&proc_callbacks); if (dwfl == NULL) error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); report_pid (dwfl, pid); return dwfl; }
static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, Dwarf_Addr addr) { self->dwfl = dwfl_begin(&kernel_callbacks); if (!self->dwfl) return -EINVAL; dwfl_linux_kernel_report_kernel(self->dwfl); dwfl_linux_kernel_report_modules(self->dwfl); self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); if (!self->dbg) { pr_debug("Failed to find kernel dwarf at %lx\n", (unsigned long)addr); dwfl_end(self->dwfl); memset(self, 0, sizeof(*self)); return -ENOENT; } return 0; }
/* Get a Dwarf from live kernel image */ static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, Dwarf_Addr addr) { self->dwfl = dwfl_begin(&kernel_callbacks); if (!self->dwfl) return -EINVAL; /* Load the kernel dwarves: Don't care the result here */ dwfl_linux_kernel_report_kernel(self->dwfl); dwfl_linux_kernel_report_modules(self->dwfl); self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); /* Here, check whether we could get a real dwarf */ if (!self->dbg) { pr_debug("Failed to find kernel dwarf at %lx\n", (unsigned long)addr); dwfl_end(self->dwfl); memset(self, 0, sizeof(*self)); return -ENOENT; } return 0; }
int main(void) { Dwfl *dw; Dwfl_Module *mod; Dwarf_Addr bias; Dwarf_Die *die = NULL; dw = dwfl_begin(&cb); if (!dw) errx(1, "dwfl_begin %s", dwfl_errmsg(-1)); mod = dwfl_report_offline(dw, "", "tst", -1); if (!mod) errx(1, "dwfl_begin %s", dwfl_errmsg(-1)); while ((die = dwfl_nextcu(dw, die, &bias))) { print_die_rec(die, -1); printf("\n"); } dwfl_end(dw); return 0; }
/* Get a Dwarf from offline image */ static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) { Dwfl_Module *mod; Dwarf *dbg = NULL; if (!dwflp) return NULL; *dwflp = dwfl_begin(&offline_callbacks); if (!*dwflp) return NULL; mod = dwfl_report_offline(*dwflp, "", "", fd); if (!mod) goto error; dbg = dwfl_module_getdwarf(mod, bias); if (!dbg) { error: dwfl_end(*dwflp); *dwflp = NULL; } return dbg; }
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; }
/* * Return: * 0 if return address for the program counter @pc is on stack * 1 if return address is in LR and no new stack frame was allocated * 2 if return address is in LR and a new frame was allocated (but not * yet used) * -1 in case of errors */ static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc) { int rc = -1; Dwfl *dwfl; Dwfl_Module *mod; Dwarf_Frame *frame; int ra_regno; Dwarf_Addr start = pc; Dwarf_Addr end = pc; bool signalp; const char *exec_file = dso->long_name; dwfl = dso->dwfl; if (!dwfl) { dwfl = dwfl_begin(&offline_callbacks); if (!dwfl) { pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1)); return -1; } mod = dwfl_report_elf(dwfl, exec_file, exec_file, -1, map_start, false); if (!mod) { pr_debug("dwfl_report_elf() failed %s\n", dwarf_errmsg(-1)); /* * We normally cache the DWARF debug info and never * call dwfl_end(). But to prevent fd leak, free in * case of error. */ dwfl_end(dwfl); goto out; } dso->dwfl = dwfl; } mod = dwfl_addrmodule(dwfl, pc); if (!mod) { pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1)); goto out; } /* * To work with split debug info files (eg: glibc), check both * .eh_frame and .debug_frame sections of the ELF header. */ frame = get_eh_frame(mod, pc); if (!frame) { frame = get_dwarf_frame(mod, pc); if (!frame) goto out; } ra_regno = dwarf_frame_info(frame, &start, &end, &signalp); if (ra_regno < 0) { pr_debug("Return address register unavailable: %s\n", dwarf_errmsg(-1)); goto out; } rc = check_return_reg(ra_regno, frame); out: return rc; }