static int touch_module(Dwfl_Module *mod, void **userdata, const char *name, Dwarf_Addr start_addr, void *arg) { struct exe_mapping_data ***tailp = arg; const char *filename = NULL; GElf_Addr bias; Dwarf_Addr base; if (dwfl_module_getelf (mod, &bias) == NULL) { warn("cannot find ELF for '%s': %s", name, dwfl_errmsg(-1)); return DWARF_CB_OK; } dwfl_module_info(mod, NULL, &base, NULL, NULL, NULL, &filename, NULL); if (filename) { **tailp = sr_mallocz(sizeof(struct exe_mapping_data)); (**tailp)->start = (uint64_t)base; (**tailp)->filename = sr_strdup(filename); *tailp = &((**tailp)->next); } return DWARF_CB_OK; }
struct sr_core_frame * resolve_frame(Dwfl *dwfl, Dwarf_Addr ip, bool minus_one) { struct sr_core_frame *frame = sr_core_frame_new(); frame->address = frame->build_id_offset = (uint64_t)ip; /* see dwfl_frame_state_pc for meaning of this parameter */ Dwarf_Addr ip_adjusted = ip - (minus_one ? 1 : 0); Dwfl_Module *mod = dwfl_addrmodule(dwfl, ip_adjusted); if (mod) { int ret; const unsigned char *build_id_bits; const char *filename, *funcname; GElf_Addr bias, bid_addr; Dwarf_Addr start; /* Initialize the module's main Elf for dwfl_module_build_id and dwfl_module_info */ /* No need to deallocate the variable 'bias' and the return value.*/ if (NULL == dwfl_module_getelf(mod, &bias)) warn("The module's main Elf was not found"); ret = dwfl_module_build_id(mod, &build_id_bits, &bid_addr); if (ret > 0) { frame->build_id = sr_mallocz(2*ret + 1); sr_bin2hex(frame->build_id, (const char *)build_id_bits, ret); } const char *modname = dwfl_module_info(mod, NULL, &start, NULL, NULL, NULL, &filename, NULL); if (modname) { frame->build_id_offset = ip - start; frame->file_name = filename ? sr_strdup(filename) : sr_strdup(modname); } funcname = dwfl_module_addrname(mod, (GElf_Addr)ip_adjusted); if (funcname) { char *demangled = sr_demangle_symbol(funcname); frame->function_name = (demangled ? demangled : sr_strdup(funcname)); } } return frame; }
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; }
static struct cie * read_cie(Dwarf_CFI_Entry *cfi, Dwarf_Off cfi_offset, unsigned char *e_ident, char **error_message) { /* Default FDE encoding (i.e. no R in augmentation string) is * DW_EH_PE_absptr. */ struct cie *cie = sr_mallocz(sizeof(struct cie)); cie->cie_offset = cfi_offset; cie->ptr_len = encoded_size(DW_EH_PE_absptr, e_ident); /* Search the augmentation data for FDE pointer encoding. * Unfortunately, 'P' can come before 'R' (which we are looking * for), so we may have to parse the whole thing. See the * abovementioned blog post for details. */ const char *augmentation = cfi->cie.augmentation; const uint8_t *augmentation_data = cfi->cie.augmentation_data; if (*augmentation == 'z') ++augmentation; while (*augmentation != '\0') { switch (*augmentation) { case 'R': cie->ptr_len = encoded_size(*augmentation_data, e_ident); if (cie->ptr_len != 4 && cie->ptr_len != 8) { *error_message = sr_asprintf("Unknown FDE encoding (CIE %jx)", (uintmax_t)cfi_offset); free(cie); return NULL; } if ((*augmentation_data & 0x70) == DW_EH_PE_pcrel) cie->pcrel = true; return cie; case 'L': ++augmentation_data; break; case 'P': { unsigned size = encoded_size(*augmentation_data, e_ident); if (0 == size) { *error_message = sr_asprintf("Unknown size for personality encoding (CIE %jx)", (uintmax_t)cfi_offset); free(cie); return NULL; } augmentation_data += size + 1; break; } default: *error_message = sr_asprintf("Unknown augmentation char (CIE %jx)", (uintmax_t)cfi_offset); free(cie); return NULL; } ++augmentation; } return cie; }