static int
frame_callback(Dwfl_Frame *frame, void *data)
{
    struct frame_callback_arg *frame_arg = data;
    char **error_msg = &frame_arg->error_msg;

    Dwarf_Addr pc;
    bool minus_one;
    if (!dwfl_frame_pc(frame, &pc, &minus_one))
    {
        set_error_dwfl("dwfl_frame_pc");
        return DWARF_CB_ABORT;
    }

    Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(frame));
    struct sr_core_frame *result = resolve_frame(dwfl, pc, minus_one);

    /* Do not unwind below __libc_start_main. */
    if (0 == sr_strcmp0(result->function_name, "__libc_start_main"))
    {
        sr_core_frame_free(result);
        return CB_STOP_UNWIND;
    }

    frame_arg->thread->frames =
        sr_core_frame_append(frame_arg->thread->frames, result);

    return DWARF_CB_OK;
}
Exemple #2
0
void
sr_normalize_core_thread(struct sr_core_thread *thread)
{
    /* Find the exit frame and remove everything above it. */
    struct sr_core_frame *exit_frame = sr_core_thread_find_exit_frame(thread);
    if (exit_frame)
    {
        bool success = sr_thread_remove_frames_above((struct sr_thread *)thread,
                                                     (struct sr_frame *)exit_frame);
        assert(success); /* if this fails, some code become broken */
        success = sr_thread_remove_frame((struct sr_thread *)thread,
                                         (struct sr_frame *)exit_frame);
        assert(success); /* if this fails, some code become broken */
    }

    /* Normalize function names by removing various prefixes that
     * occur only in some cases.
     */
    struct sr_core_frame *frame = thread->frames;
    while (frame)
    {
        /* Remove IA__ prefix used in GLib, GTK and GDK. */
        remove_func_prefix(frame->function_name, "IA__gdk", strlen("IA__"));
        remove_func_prefix(frame->function_name, "IA__g_", strlen("IA__"));
        remove_func_prefix(frame->function_name, "IA__gtk", strlen("IA__"));

        /* Remove __GI_ (glibc internal) prefix. */
        remove_func_prefix(frame->function_name, "__GI_", strlen("__GI_"));

        frame = frame->next;
    }

    /* Unify some functions by renaming them.
     */
    frame = thread->frames;
    while (frame)
    {
        char *new_function_name =
            find_new_function_name_glibc(frame->function_name, frame->file_name);

        if (new_function_name)
        {
            free(frame->function_name);
            frame->function_name = new_function_name;
        }

        frame = frame->next;
    }

    /* Remove redundant frames from the thread.
     */
    frame = thread->frames;
    while (frame)
    {
        struct sr_core_frame *next_frame = frame->next;

        /* Remove frames which are not a cause of the crash. */
        bool removable =
            is_removable_dbus(frame->function_name, frame->file_name) ||
            is_removable_gdk(frame->function_name, frame->file_name) ||
            is_removable_glib(frame->function_name, frame->file_name) ||
            is_removable_glibc(frame->function_name, frame->file_name) ||
            is_removable_libstdcpp(frame->function_name, frame->file_name) ||
            is_removable_linux(frame->function_name, frame->file_name) ||
            is_removable_xorg(frame->function_name, frame->file_name) ||
            is_removable_jvm(frame->function_name, frame->file_name) ||
            is_removable_vim(frame->function_name, frame->file_name);

        bool removable_with_above =
            is_removable_glibc_with_above(frame->function_name, frame->file_name)  ||
            sr_core_thread_is_exit_frame(frame);

        if (removable_with_above)
        {
            bool success = sr_thread_remove_frames_above((struct sr_thread *)thread,
                                                         (struct sr_frame *)frame);
            assert(success);
        }

        if (removable || removable_with_above)
            sr_thread_remove_frame((struct sr_thread *)thread, (struct sr_frame *)frame);

        frame = next_frame;
    }

    /* If the first frame has address 0x0000 and its name is '??', it
     * is a dereferenced null, and we remove it. This frame is not
     * really invalid, but it affects stacktrace quality rating. See
     * Red Hat Bugzilla bug #639038.
     * @code
     * #0  0x0000000000000000 in ?? ()
     * No symbol table info available.
     * #1  0x0000000000422648 in main (argc=1, argv=0x7fffa57cf0d8) at totem.c:242
     *       error = 0x0
     *       totem = 0xdee070 [TotemObject]
     * @endcode
     */
    if (thread->frames &&
        thread->frames->address == 0x0000 &&
        !thread->frames->function_name)
    {
        sr_thread_remove_frame((struct sr_thread *)thread,
                               (struct sr_frame *)thread->frames);
    }

    /* If the last frame has address 0x0000 and its name is '??',
     * remove it. This frame is not really invalid, but it affects
     * stacktrace quality rating. See Red Hat Bugzilla bug #592523.
     * @code
     * #2  0x00007f4dcebbd62d in clone ()
     * at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
     * No locals.
     * #3  0x0000000000000000 in ?? ()
     * @endcode
     */
    struct sr_core_frame *last = thread->frames;
    while (last && last->next)
        last = last->next;
    if (last &&
        last->address == 0x0000 &&
        !last->function_name)
    {
        sr_thread_remove_frame((struct sr_thread *)thread, (struct sr_frame *)last);
    }

    /* Merge recursively called functions into single frame */
    struct sr_core_frame *curr_frame = thread->frames;
    struct sr_core_frame *prev_frame = NULL;
    while (curr_frame)
    {
        if (prev_frame &&
            prev_frame->function_name &&
            0 == sr_strcmp0(prev_frame->function_name, curr_frame->function_name))
        {
            prev_frame->next = curr_frame->next;
            sr_core_frame_free(curr_frame);
            curr_frame = prev_frame->next;
            continue;
        }

        prev_frame = curr_frame;
        curr_frame = curr_frame->next;
    }

}