Beispiel #1
0
struct btp_frame *
btp_backtrace_get_crash_frame(struct btp_backtrace *backtrace)
{
    backtrace = btp_backtrace_dup(backtrace);

    struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace);
    if (!crash_thread)
    {
        btp_backtrace_free(backtrace);
        return NULL;
    }

    btp_normalize_backtrace(backtrace);
    struct btp_frame *crash_frame = crash_thread->frames;
    crash_frame = btp_frame_dup(crash_frame, false);
    btp_backtrace_free(backtrace);
    return crash_frame;
}
Beispiel #2
0
struct btp_backtrace *
btp_backtrace_parse(const char **input,
                    struct btp_location *location)
{
    const char *local_input = *input;
    struct btp_backtrace *imbacktrace = btp_backtrace_new(); /* im - intermediate */
    imbacktrace->libs = btp_sharedlib_parse(*input);

    /* The header is mandatory, but it might contain no frame header,
     * in some broken backtraces. In that case, backtrace.crash value
     * is kept as NULL.
     */
    if (!btp_backtrace_parse_header(&local_input,
                                    &imbacktrace->crash,
                                    location))
    {
        btp_backtrace_free(imbacktrace);
        return NULL;
    }

    struct btp_thread *thread, *prevthread = NULL;
    while ((thread = btp_thread_parse(&local_input, location)))
    {
        if (prevthread)
        {
            btp_thread_add_sibling(prevthread, thread);
            prevthread = thread;
        }
        else
            imbacktrace->threads = prevthread = thread;
    }
    if (!imbacktrace->threads)
    {
        btp_backtrace_free(imbacktrace);
        return NULL;
    }

    *input = local_input;
    return imbacktrace;
}
Beispiel #3
0
float
btp_backtrace_quality_complex(struct btp_backtrace *backtrace)
{
    backtrace = btp_backtrace_dup(backtrace);

    /* Find the crash thread, and then normalize the backtrace. It is
     * not possible to find the crash thread after the backtrace has
     * been normalized.
     */
    struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace);
    btp_normalize_backtrace(backtrace);

    /* Get the quality q1 of the full backtrace. */
    float q1 = btp_backtrace_quality_simple(backtrace);

    if (!crash_thread)
    {
        btp_backtrace_free(backtrace);
        return q1;
    }

    /* Get the quality q2 of the crash thread. */
    float q2 = btp_thread_quality(crash_thread);

    /* Get the quality q3 of the frames around the crash.  First,
     * duplicate the crash thread so we can cut it. Then find an exit
     * frame, and remove it and everything above it
     * (__run_exit_handlers and such). Then remove all the redundant
     * frames (assert calls etc.) Then limit the frame count to 5.
     */
    btp_thread_remove_frames_below_n(crash_thread, 5);
    float q3 = btp_thread_quality(crash_thread);

    btp_backtrace_free(backtrace);

    /* Compute and return the final backtrace quality q. */
    return 0.25f * q1 + 0.35f * q2 + 0.4f * q3;
}
Beispiel #4
0
char *
btp_backtrace_get_duplication_hash(struct btp_backtrace *backtrace)
{
    backtrace = btp_backtrace_dup(backtrace);
    struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace);
    if (crash_thread)
        btp_backtrace_remove_threads_except_one(backtrace, crash_thread);

    btp_normalize_backtrace(backtrace);
    btp_backtrace_limit_frame_depth(backtrace, 3);
    char *hash = btp_backtrace_to_text(backtrace, false);
    btp_backtrace_free(backtrace);
    return hash;
}
Beispiel #5
0
struct btp_thread *
btp_backtrace_get_optimized_thread(struct btp_backtrace *backtrace, int max_frames)
{
    struct btp_thread *crash_thread;

    backtrace = btp_backtrace_dup(backtrace);
    crash_thread = btp_backtrace_find_crash_thread(backtrace);

    if (!crash_thread) {
        btp_backtrace_free(backtrace);
        return NULL;
    }

    btp_backtrace_remove_threads_except_one(backtrace, crash_thread);
    btp_backtrace_set_libnames(backtrace);
    btp_normalize_thread(crash_thread);
    btp_normalize_optimize_thread(crash_thread);

    /* Remove frames with no function name (i.e. signal handlers). */
    struct btp_frame *frame = crash_thread->frames, *frame_next;
    while (frame)
    {
        frame_next = frame->next;
        if (!frame->function_name)
            btp_thread_remove_frame(crash_thread, frame);
        frame = frame_next;
    }

    if (max_frames > 0)
        btp_thread_remove_frames_below_n(crash_thread, max_frames);

    crash_thread = btp_thread_dup(crash_thread, false);
    btp_backtrace_free(backtrace);

    return crash_thread;
}
int main(int argc, char **argv)
{
    abrt_init(argv);

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\b [options] -d DIR\n"
        "\n"
        "Analyzes C/C++ backtrace, generates duplication hash, backtrace rating, and identifies crash function in dump directory DIR"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Dump directory")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;

    char *component = dd_load_text(dd, FILENAME_COMPONENT);

    /* Read backtrace */
    char *backtrace_str = dd_load_text_ext(dd, FILENAME_BACKTRACE,
                                           DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
    if (!backtrace_str)
    {
        dd_close(dd);
        return 1;
    }

    /* Compute backtrace hash */
    struct btp_location location;
    btp_location_init(&location);
    char *backtrace_str_ptr = backtrace_str;
    struct btp_backtrace *backtrace = btp_backtrace_parse(&backtrace_str_ptr, &location);
    free(backtrace_str);

    /* Store backtrace hash */
    if (!backtrace)
    {
        /*
         * The parser failed. Compute the duphash from the executable
         * instead of a backtrace.
         * and component only.  This is not supposed to happen often.
         */
        log(_("Backtrace parsing failed for %s"), dump_dir_name);
        log("%d:%d: %s", location.line, location.column, location.message);
        struct strbuf *emptybt = strbuf_new();

        char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
        strbuf_prepend_str(emptybt, executable);
        free(executable);

        strbuf_prepend_str(emptybt, component);

        VERB3 log("Generating duphash: %s", emptybt->buf);
        char hash_str[SHA1_RESULT_LEN*2 + 1];
        create_hash(hash_str, emptybt->buf);

        dd_save_text(dd, FILENAME_DUPHASH, hash_str);
        /*
         * Other parts of ABRT assume that if no rating is available,
         * it is ok to allow reporting of the bug. To be sure no bad
         * backtrace is reported, rate the backtrace with the lowest
         * rating.
         */
        dd_save_text(dd, FILENAME_RATING, "0");

        strbuf_free(emptybt);
        free(component);
        dd_close(dd);

        /* Report success even if the parser failed, as the backtrace
         * has been created and rated. The failure is caused by a flaw
         * in the parser, not in the backtrace.
         */
        return 0;
    }

    /* Compute duplication hash. */
    char *str_hash_core = btp_backtrace_get_duplication_hash(backtrace);
    struct strbuf *str_hash = strbuf_new();
    strbuf_append_str(str_hash, component);
    strbuf_append_str(str_hash, str_hash_core);

    VERB3 log("Generating duphash: %s", str_hash->buf);
    char hash_str[SHA1_RESULT_LEN*2 + 1];
    create_hash(hash_str, str_hash->buf);

    dd_save_text(dd, FILENAME_DUPHASH, hash_str);
    strbuf_free(str_hash);
    free(str_hash_core);

    /* Compute the backtrace rating. */
    float quality = btp_backtrace_quality_complex(backtrace);
    const char *rating;
    if (quality < 0.6f)
        rating = "0";
    else if (quality < 0.7f)
        rating = "1";
    else if (quality < 0.8f)
        rating = "2";
    else if (quality < 0.9f)
        rating = "3";
    else
        rating = "4";
    dd_save_text(dd, FILENAME_RATING, rating);

    /* Get the function name from the crash frame. */
    struct btp_frame *crash_frame = btp_backtrace_get_crash_frame(backtrace);
    if (crash_frame)
    {
        if (crash_frame->function_name &&
            0 != strcmp(crash_frame->function_name, "??"))
        {
            dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function_name);
        }
        btp_frame_free(crash_frame);
    }
    btp_backtrace_free(backtrace);
    dd_close(dd);
    free(component);
    return 0;
}