Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}