Пример #1
0
/* constructor */
PyObject *
sr_py_gdb_frame_new(PyTypeObject *object, PyObject *args, PyObject *kwds)
{
    struct sr_py_gdb_frame *fo = (struct sr_py_gdb_frame*)
        PyObject_New(struct sr_py_gdb_frame, &sr_py_gdb_frame_type);

    if (!fo)
        return PyErr_NoMemory();

    const char *str = NULL;
    if (!PyArg_ParseTuple(args, "|s", &str))
        return NULL;

    if (str)
    {
        struct sr_location location;
        sr_location_init(&location);
        fo->frame = sr_gdb_frame_parse(&str, &location);

        if (!fo->frame)
        {
            PyErr_SetString(PyExc_ValueError, location.message);
            return NULL;
        }
    }
    else
        fo->frame = sr_gdb_frame_new();

    return (PyObject*)fo;
}
Пример #2
0
static
int append_short_backtrace(struct strbuf *result, problem_data_t *problem_data, size_t max_text_size, bool print_item_name)
{
    const problem_item *item = problem_data_get_item_or_NULL(problem_data,
                                                             FILENAME_BACKTRACE);
    if (!item)
        return 0; /* "I did not print anything" */
    if (!(item->flags & CD_FLAG_TXT))
        return 0; /* "I did not print anything" */

    char *truncated = NULL;

    if (strlen(item->content) >= max_text_size)
    {
        struct sr_location location;
        sr_location_init(&location);

        /* sr_gdb_stacktrace_parse modifies the input parameter */
        char *content = item->content;
        struct sr_gdb_stacktrace *backtrace = sr_gdb_stacktrace_parse((const char **)&content, &location);

        if (!backtrace)
        {
            log(_("Can't parse backtrace"));
            return 0;
        }

        /* Get optimized thread stack trace for 10 top most frames */
        struct sr_gdb_thread *thread = sr_gdb_stacktrace_get_optimized_thread(backtrace, 10);

        sr_gdb_stacktrace_free(backtrace);

        if (!thread)
        {
            log(_("Can't find crash thread"));
            return 0;
        }

        /* Cannot be NULL, it dies on memory error */
        struct sr_strbuf *bt = sr_strbuf_new();

        sr_gdb_thread_append_to_str(thread, bt, true);

        sr_gdb_thread_free(thread);

        truncated = sr_strbuf_free_nobuf(bt);
    }

    append_text(result,
                /*item_name:*/ truncated ? "truncated_backtrace" : FILENAME_BACKTRACE,
                /*content:*/   truncated ? truncated             : item->content,
                print_item_name
    );
    free(truncated);
    return 1;
}
Пример #3
0
struct sr_core_stacktrace *
sr_core_stacktrace_from_gdb(const char *gdb_output, const char *core_file,
                            const char *exe_file, char **error_msg)
{
    /* I'm not going to rewrite it now since the function is not being used. */
    assert(error_msg);
    /* Initialize error_msg to 'no error'. */
    *error_msg = NULL;

    struct core_handle *ch = open_coredump(core_file, exe_file, error_msg);
    if (*error_msg)
        return NULL;

    struct sr_gdb_stacktrace *gdb_stacktrace;
    struct sr_location location;
    sr_location_init(&location);

    gdb_stacktrace = sr_gdb_stacktrace_parse(&gdb_output, &location);
    if (!gdb_stacktrace)
    {
        *error_msg = sr_location_to_string(&location);
        core_handle_free(ch);
        return NULL;
    }

    struct sr_core_stacktrace *core_stacktrace = sr_core_stacktrace_new();

    for (struct sr_gdb_thread *gdb_thread = gdb_stacktrace->threads;
         gdb_thread;
         gdb_thread = gdb_thread->next)
    {
        struct sr_core_thread *core_thread = sr_core_thread_new();

        for (struct sr_gdb_frame *gdb_frame = gdb_thread->frames;
             gdb_frame;
             gdb_frame = gdb_frame->next)
        {
            if (gdb_frame->signal_handler_called)
                continue;

            struct sr_core_frame *core_frame = resolve_frame(ch->dwfl,
                    gdb_frame->address, false);

            core_thread->frames = sr_core_frame_append(core_thread->frames,
                    core_frame);
        }

        if (sr_gdb_stacktrace_find_crash_thread(gdb_stacktrace) == gdb_thread)
        {
            core_stacktrace->crash_thread = core_thread;
        }

        core_stacktrace->threads = sr_core_thread_append(
                core_stacktrace->threads, core_thread);
    }

    core_stacktrace->signal = get_signal_number(ch->eh, core_file);
    core_stacktrace->executable = realpath(exe_file, NULL);

    core_handle_free(ch);
    sr_gdb_stacktrace_free(gdb_stacktrace);
    return core_stacktrace;
}
int main(int argc, char **argv)
{
    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [options] -d DIR\n"
        "\n"
        "Analyzes C/C++ backtrace, generates duplication hash, backtrace rating,\n"
        "and identifies crash function in problem 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", _("Problem 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 sr_location location;
    sr_location_init(&location);
    const char *backtrace_str_ptr = backtrace_str;
    struct sr_gdb_stacktrace *backtrace = sr_gdb_stacktrace_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);

        log_debug("Generating duphash: %s", emptybt->buf);
        char hash_str[SHA1_RESULT_LEN*2 + 1];
        str_to_sha1str(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. */
    struct sr_thread *crash_thread =
        (struct sr_thread *)sr_gdb_stacktrace_find_crash_thread(backtrace);

    if (crash_thread)
    {
        char *hash_str;

        if (g_verbose >= 3)
        {
            hash_str = sr_thread_get_duphash(crash_thread, 3, component,
                                             SR_DUPHASH_NOHASH);
            log("Generating duphash: %s", hash_str);
            free(hash_str);
        }

        hash_str = sr_thread_get_duphash(crash_thread, 3, component,
                                         SR_DUPHASH_NORMAL);
        dd_save_text(dd, FILENAME_DUPHASH, hash_str);
        free(hash_str);
    }
    else
        log(_("Crash thread not found"));


    /* Compute the backtrace rating. */
    float quality = sr_gdb_stacktrace_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 sr_gdb_frame *crash_frame = sr_gdb_stacktrace_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);
        }
        sr_gdb_frame_free(crash_frame);
    }
    sr_gdb_stacktrace_free(backtrace);
    dd_close(dd);
    free(component);
    return 0;
}
Пример #5
0
struct sr_report *
sr_abrt_report_from_dir(const char *directory,
                        char **error_message)
{
    struct sr_report *report = sr_report_new();

    /* Report type. */
    char *type_contents = file_contents(directory, "type", error_message);
    if (!type_contents)
    {
        sr_report_free(report);
        return NULL;
    }

    report->report_type = sr_abrt_type_from_type(type_contents);
    free(type_contents);

    /* Operating system. */
    report->operating_system = sr_abrt_operating_system_from_dir(
        directory, error_message);

    if (!report->operating_system)
    {
        sr_report_free(report);
        return NULL;
    }

    /* Component name. */
    report->component_name = file_contents(directory, "component", error_message);

    /* RPM packages. */
    report->rpm_packages = sr_abrt_rpm_packages_from_dir(
        directory, error_message);

    if (!report->rpm_packages)
    {
        sr_report_free(report);
        return NULL;
    }

    /* Core stacktrace. */
    if (report->report_type == SR_REPORT_CORE)
    {
        char *core_backtrace_contents = file_contents(directory, "core_backtrace",
                                                      error_message);
        if (!core_backtrace_contents)
        {
            sr_report_free(report);
            return NULL;
        }

        report->stacktrace = (struct sr_stacktrace *)sr_core_stacktrace_from_json_text(
                core_backtrace_contents, error_message);

        free(core_backtrace_contents);
        if (!report->stacktrace)
        {
            sr_report_free(report);
            return NULL;
        }
    }

    /* Python stacktrace. */
    if (report->report_type == SR_REPORT_PYTHON)
    {
        char *backtrace_contents = file_contents(directory, "backtrace",
                                                 error_message);
        if (!backtrace_contents)
        {
            sr_report_free(report);
            return NULL;
        }

        /* Parse the Python stacktrace. */
        struct sr_location location;
        sr_location_init(&location);
        const char *contents_pointer = backtrace_contents;
        report->stacktrace = (struct sr_stacktrace *)sr_python_stacktrace_parse(
            &contents_pointer,
            &location);

        free(backtrace_contents);
        if (!report->stacktrace)
        {
            *error_message = sr_location_to_string(&location);
            sr_report_free(report);
            return NULL;
        }
    }

    /* Kerneloops stacktrace. */
    if (report->report_type == SR_REPORT_KERNELOOPS)
    {
        /* Determine kernel version */
        char *kernel_contents = file_contents(directory, "kernel",
                                              error_message);
        if (!kernel_contents)
        {
            sr_report_free(report);
            return NULL;
        }

        /* Load the Kerneloops stacktrace */
        char *backtrace_contents = file_contents(directory, "backtrace", error_message);
        if (!backtrace_contents)
        {
            sr_report_free(report);
            return NULL;
        }

        /* Parse the Kerneloops stacktrace. */
        struct sr_location location;
        sr_location_init(&location);
        const char *contents_pointer = backtrace_contents;
        struct sr_koops_stacktrace *stacktrace = sr_koops_stacktrace_parse(
            &contents_pointer,
            &location);

        stacktrace->version = kernel_contents;
        report->stacktrace = (struct sr_stacktrace *)stacktrace;

        free(backtrace_contents);
        if (!report->stacktrace)
        {
            *error_message = sr_location_to_string(&location);
            sr_report_free(report);
            return NULL;
        }
    }

    /* Java stacktrace. */
    if (report->report_type == SR_REPORT_JAVA)
    {
        char *backtrace_contents = file_contents(directory, "backtrace", error_message);
        if (!backtrace_contents)
        {
            sr_report_free(report);
            return NULL;
        }

        /* Parse the Java stacktrace. */
        struct sr_location location;
        sr_location_init(&location);
        const char *contents_pointer = backtrace_contents;
        report->stacktrace = (struct sr_stacktrace *)sr_java_stacktrace_parse(
            &contents_pointer,
            &location);

        free(backtrace_contents);
        if (!report->stacktrace)
        {
            *error_message = sr_location_to_string(&location);
            sr_report_free(report);
            return NULL;
        }
    }

    /* Ruby stacktrace. */
    if (report->report_type == SR_REPORT_RUBY)
    {
        char *backtrace_contents = file_contents(directory, "backtrace",
                                                 error_message);
        if (!backtrace_contents)
        {
            sr_report_free(report);
            return NULL;
        }

        /* Parse the Ruby stacktrace. */
        struct sr_location location;
        sr_location_init(&location);
        const char *contents_pointer = backtrace_contents;
        report->stacktrace = (struct sr_stacktrace *)sr_ruby_stacktrace_parse(
            &contents_pointer,
            &location);

        free(backtrace_contents);
        if (!report->stacktrace)
        {
            *error_message = sr_location_to_string(&location);
            sr_report_free(report);
            return NULL;
        }
    }

    return report;
}
Пример #6
0
struct sr_core_stacktrace *
sr_core_stacktrace_create(const char *gdb_stacktrace_text,
                          const char *unstrip_text,
                          const char *executable_path)
{
    // Parse the GDB stacktrace.
    struct sr_location location;
    sr_location_init(&location);

    struct sr_gdb_stacktrace *gdb_stacktrace =
        sr_gdb_stacktrace_parse(&gdb_stacktrace_text, &location);

    if (!gdb_stacktrace)
    {
        warn("Unable to parse stacktrace: %d:%d: %s\n",
             location.line, location.column, location.message);

        return NULL;
    }

    // Parse the unstrip output.
    struct sr_unstrip_entry *unstrip = sr_unstrip_parse(unstrip_text);
    if (!unstrip)
    {
        warn("Unable to parse unstrip output.");

        sr_gdb_stacktrace_free(gdb_stacktrace);
        return NULL;
    }

    // Create the core stacktrace
    struct sr_core_stacktrace *core_stacktrace =
        sr_core_stacktrace_new();

    struct sr_gdb_thread *gdb_thread = gdb_stacktrace->threads;
    while (gdb_thread)
    {
        struct sr_core_thread *core_thread = sr_core_thread_new();

        struct sr_gdb_frame *gdb_frame = gdb_thread->frames;
        while (gdb_frame)
        {
            gdb_frame = gdb_frame->next;

            struct sr_core_frame *core_frame = sr_core_frame_new();
            core_frame->address = gdb_frame->address;

            struct sr_unstrip_entry *unstrip_entry =
                sr_unstrip_find_address(unstrip, gdb_frame->address);

            if (unstrip_entry)
            {
                core_frame->build_id = sr_strdup(unstrip_entry->build_id);
                core_frame->build_id_offset = core_frame->address - unstrip_entry->start;
                core_frame->file_name = sr_strdup(unstrip_entry->file_name);
            }

            if (gdb_frame->function_name &&
                0 != strcmp(gdb_frame->function_name, "??"))
            {
                core_frame->function_name =
                    sr_strdup(gdb_frame->function_name);
            }

            core_thread->frames = sr_core_frame_append(core_thread->frames, core_frame);
        }

        core_stacktrace->threads =
            sr_core_thread_append(core_stacktrace->threads,
                                  core_thread);

        gdb_thread = gdb_thread->next;
    }

    sr_unstrip_free(unstrip);
    sr_gdb_stacktrace_free(gdb_stacktrace);
    return core_stacktrace;
}
Пример #7
0
struct sr_python_stacktrace *
sr_python_stacktrace_parse(const char **input,
                           struct sr_location *location)
{
    const char *local_input = *input;

    /* Parse the header. */
    if (sr_skip_char(&local_input, '\n'))
        location->column += 1;

    const char *HEADER = "Traceback (most recent call last):\n";
    local_input = sr_strstr_location(local_input,
                                     HEADER,
                                     &location->line,
                                     &location->column);

    if (!local_input)
    {
        /* SyntaxError stack trace of an exception thrown in the executed file
         * conforms to the following template:
         * invalid syntax ($file, line $number)
         *
         *    File "$file", line $number
         *       $code
         *         ^
         * SyntaxError: invalid syntax
         *
         * for exceptions thrown from imported files, the stack trace has the
         * regular form, except the last frame has no function name and is
         * followed by the pointer line (^).
         */
        HEADER = "invalid syntax (",
        local_input = sr_strstr_location(*input,
                                     HEADER,
                                     &location->line,
                                     &location->column);

        if (!local_input)
        {
            location->message = "Traceback header not found.";
            return NULL;
        }

        local_input = sr_strstr_location(local_input,
                           "  File \"",
                           &location->line,
                           &location->column);

        if (!local_input)
        {
            location->message = "Frame with invalid line not found.";
            return NULL;
        }
    }
    else
    {
        local_input += strlen(HEADER);
        location->line += 2;
        location->column = 0;
    }

    struct sr_python_stacktrace *stacktrace = sr_python_stacktrace_new();

    /* Read the frames. */
    struct sr_python_frame *frame;
    struct sr_location frame_location;
    sr_location_init(&frame_location);
    while ((frame = sr_python_frame_parse(&local_input, &frame_location)))
    {
        /*
         * Python stacktraces are in reverse order than other types - we
         * reverse it here by prepending each frame to the list instead of
         * appending it.
         */
        frame->next = stacktrace->frames;
        stacktrace->frames = frame;

        sr_location_add(location,
                        frame_location.line,
                        frame_location.column);
    }

    if (!stacktrace->frames)
    {
        location->message = frame_location.message;
        sr_python_stacktrace_free(stacktrace);
        return NULL;
    }

    bool invalid_syntax_pointer = true;
    const char *tmp_input = local_input;
    while (*tmp_input != '\n' && *tmp_input != '\0')
    {
        if (*tmp_input != ' ' && *tmp_input != '^')
        {
            invalid_syntax_pointer = false;
            break;
        }
        ++tmp_input;
    }

    if (invalid_syntax_pointer)
    {
        /* Skip line "   ^" pointing to the invalid code */
        sr_skip_char_cspan(&local_input, "\n");
        ++local_input;
        ++location->line;
        location->column = 1;
    }

    /* Parse exception name. */
    if (!sr_parse_char_cspan(&local_input, ":\n", &stacktrace->exception_name))
    {

        location->message = "Unable to find the ':\\n' characters "
                            "identifying the end of exception name.";
        sr_python_stacktrace_free(stacktrace);
        return NULL;

    }

    *input = local_input;
    return stacktrace;
}