Exemple #1
0
int delete_problem_dirs_over_dbus(const GList *problem_dir_paths)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return 1;

    GVariant *parameters = variant_from_string_list(problem_dir_paths);

    GError *error = NULL;
    g_dbus_proxy_call_sync(proxy,
                    "DeleteProblem",
                    parameters,
                    G_DBUS_CALL_FLAGS_NONE,
                    -1,
                    NULL,
                    &error);
//g_variant_unref(parameters); -- need this??? no?? why?

    if (error)
    {
        error_msg(_("Deleting problem directory failed: %s"), error->message);
        g_error_free(error);
        return 1;
    }
    return 0;
}
Exemple #2
0
problem_data_t *get_problem_data_dbus(const char *problem_dir_path)
{
    INITIALIZE_LIBABRT();

    static const char *elements[] = {
        FILENAME_TIME,
        FILENAME_REASON,
        FILENAME_NOT_REPORTABLE,
        FILENAME_COMPONENT,
        FILENAME_EXECUTABLE,
        FILENAME_REPORTED_TO,
        NULL,
    };

    problem_data_t *pd = problem_data_new();

    if (fill_problem_data_over_dbus(problem_dir_path, elements, pd) != 0)
    {
        error_msg(_("Can't get problem data from abrt-dbus"));
        problem_data_free(pd);
        return NULL;
    }

    return pd;
}
Exemple #3
0
int chown_dir_over_dbus(const char *problem_dir_path)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return 1;

    GError *error = NULL;
    g_dbus_proxy_call_sync(proxy,
                        "ChownProblemDir",
                        g_variant_new("(s)", problem_dir_path),
                        G_DBUS_CALL_FLAGS_NONE,
                        -1,
                        NULL,
                        &error);

    if (error)
    {
        error_msg(_("Can't chown '%s': %s"), problem_dir_path, error->message);
        g_error_free(error);
        return 1;
    }
    return 0;
}
Exemple #4
0
int test_exist_over_dbus(const char *problem_id, const char *element_name)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return -1;

    GError *error = NULL;
    GVariant *result = g_dbus_proxy_call_sync(proxy,
                                            "TestElementExists",
                                            g_variant_new("(ss)", problem_id, element_name),
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1,
                                            NULL,
                                            &error);

    if (error)
    {
        error_msg(_("Can't test whether the element exists over abrt-dbus: %s"), error->message);
        g_error_free(error);
        return -1;
    }

    gboolean retval;
    g_variant_get(result, "(b)", &retval);
    g_variant_unref(result);

    return retval;
}
Exemple #5
0
problem_data_t *get_problem_data_dbus(const char *problem_dir_path)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return NULL;

    GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
    g_variant_builder_add(builder, "s", FILENAME_TIME          );
    g_variant_builder_add(builder, "s", FILENAME_REASON        );
    g_variant_builder_add(builder, "s", FILENAME_NOT_REPORTABLE);
    g_variant_builder_add(builder, "s", FILENAME_COMPONENT     );
    g_variant_builder_add(builder, "s", FILENAME_EXECUTABLE    );
    g_variant_builder_add(builder, "s", FILENAME_REPORTED_TO   );
    GVariant *params = g_variant_new("(sas)", problem_dir_path, builder);
    g_variant_builder_unref(builder);

    GError *error = NULL;
    GVariant *result = g_dbus_proxy_call_sync(proxy,
                                            "GetInfo",
                                            params,
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1,
                                            NULL,
                                            &error);

    if (error)
    {
        error_msg(_("Can't get problem data from abrt-dbus: %s"), error->message);
        g_error_free(error);
        return NULL;
    }

    problem_data_t *pd = problem_data_new();
    char *key, *val;
    GVariantIter *iter;
    g_variant_get(result, "(a{ss})", &iter);
    while (g_variant_iter_loop(iter, "{ss}", &key, &val))
    {
        problem_data_add_text_noteditable(pd, key, val);
    }
    g_variant_unref(result);
    return pd;
}
Exemple #6
0
char *load_text_over_dbus(const char *problem_id, const char *element_name)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return ERR_PTR;

    GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
    g_variant_builder_add(builder, "s", element_name);
    GVariant *params = g_variant_new("(sas)", problem_id, builder);
    g_variant_builder_unref(builder);

    GError *error = NULL;
    GVariant *result = g_dbus_proxy_call_sync(proxy,
                                            "GetInfo",
                                            params,
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1,
                                            NULL,
                                            &error);

    if (error)
    {
        error_msg(_("Can't get problem data from abrt-dbus: %s"), error->message);
        g_error_free(error);
        return ERR_PTR;
    }

    GVariant *values = g_variant_get_child_value(result, 0);
    g_variant_unref(result);

    char *retval = NULL;
    if (g_variant_n_children(values) == 1)
    {
        GVariant *contents = g_variant_get_child_value(values, 0);
        gchar *key;
        g_variant_get(contents, "{&ss}", &key, &retval);
    }

    g_variant_unref(values);
    return retval;
}
Exemple #7
0
problem_data_t *get_full_problem_data_over_dbus(const char *problem_dir_path)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return ERR_PTR;

    GError *error = NULL;
    GVariant *result = g_dbus_proxy_call_sync(proxy,
                                    "GetProblemData",
                                    g_variant_new("(s)", problem_dir_path),
                                    G_DBUS_CALL_FLAGS_NONE,
                                    -1,
                                    NULL,
                                    &error);

    if (error)
    {
        error_msg(_("Can't get problem data from abrt-dbus: %s"), error->message);
        g_error_free(error);
        return ERR_PTR;
    }

    GVariantIter *iter = NULL;
    g_variant_get(result, "(a{s(its)})", &iter);

    gchar *name = NULL;
    gint flags;
    gulong size;
    gchar *value = NULL;

    problem_data_t *pd = problem_data_new();
    while (g_variant_iter_loop(iter, "{&s(it&s)}", &name, &flags, &size, &value))
        problem_data_add_ext(pd, name, value, flags, size);

    problem_data_add(pd, CD_DUMPDIR, problem_dir_path,
            CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE + CD_FLAG_LIST);

    g_variant_unref(result);

    return pd;
}
Exemple #8
0
int fill_problem_data_over_dbus(const char *problem_id, const char **elements, problem_data_t *problem_data)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return -1;

    GVariantBuilder *args_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));

    for (const char **iter = elements; *iter; ++iter)
        g_variant_builder_add(args_builder, "s", *iter);

    GVariant *params = g_variant_new("(sas)", problem_id, args_builder);
    g_variant_builder_unref(args_builder);

    GError *error = NULL;
    GVariant *result = g_dbus_proxy_call_sync(proxy,
                                            "GetInfo",
                                            params,
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1,
                                            NULL,
                                            &error);

    if (error)
    {
        error_msg(_("D-Bus GetInfo method call failed: %s"), error->message);
        g_error_free(error);
        return -2;
    }


    char *key, *val;
    GVariantIter *iter;
    g_variant_get(result, "(a{ss})", &iter);
    while (g_variant_iter_loop(iter, "{ss}", &key, &val))
        problem_data_add_text_noteditable(problem_data, key, val);

    g_variant_unref(result);

    return 0;
}
Exemple #9
0
GList *get_problems_over_dbus(bool authorize)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return ERR_PTR;

    GError *error = NULL;
    GVariant *result = g_dbus_proxy_call_sync(proxy,
                                    authorize ? "GetAllProblems" : "GetProblems",
                                    g_variant_new("()"),
                                    G_DBUS_CALL_FLAGS_NONE,
                                    -1,
                                    NULL,
                                    &error);

    if (error)
    {
        error_msg(_("Can't get problem list from abrt-dbus: %s"), error->message);
        g_error_free(error);
        return ERR_PTR;
    }

    GList *list = NULL;
    if (result)
    {
        /* Fetch "as" from "(as)" */
        GVariant *array = g_variant_get_child_value(result, 0);
        list = string_list_from_variant(array);
        g_variant_unref(array);
        g_variant_unref(result);
    }

    return list;
}
Exemple #10
0
char *get_backtrace(const char *dump_dir_name, unsigned timeout_sec, const char *debuginfo_dirs)
{
    INITIALIZE_LIBABRT();

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return NULL;
    char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
    dd_close(dd);

    /* Let user know what's going on */
    log(_("Generating backtrace"));

    unsigned i = 0;
    char *args[25];
    args[i++] = (char*)"gdb";
    args[i++] = (char*)"-batch";
    struct strbuf *set_debug_file_directory = strbuf_new();
    unsigned auto_load_base_index = 0;
    if(debuginfo_dirs == NULL)
    {
        // set non-existent debug file directory to prevent resolving
        // function names - we need offsets for core backtrace.
        strbuf_append_str(set_debug_file_directory, "set debug-file-directory /");
    }
    else
    {
        strbuf_append_str(set_debug_file_directory, "set debug-file-directory /usr/lib/debug");

        struct strbuf *debug_directories = strbuf_new();
        const char *p = debuginfo_dirs;
        while (1)
        {
            while (*p == ':')
                p++;
            if (*p == '\0')
                break;
            const char *colon_or_nul = strchrnul(p, ':');
            strbuf_append_strf(debug_directories, "%s%.*s/usr/lib/debug", (debug_directories->len == 0 ? "" : ":"),
                                                                          (int)(colon_or_nul - p), p);
            p = colon_or_nul;
        }

        strbuf_append_strf(set_debug_file_directory, ":%s", debug_directories->buf);

        args[i++] = (char*)"-iex";
        auto_load_base_index = i;
        args[i++] = xasprintf("add-auto-load-safe-path %s", debug_directories->buf);
        args[i++] = (char*)"-iex";
        args[i++] = xasprintf("add-auto-load-scripts-directory %s", debug_directories->buf);

        strbuf_free(debug_directories);
    }

    args[i++] = (char*)"-ex";
    const unsigned debug_dir_cmd_index = i++;
    args[debug_dir_cmd_index] = strbuf_free_nobuf(set_debug_file_directory);

    /* "file BINARY_FILE" is needed, without it gdb cannot properly
     * unwind the stack. Currently the unwind information is located
     * in .eh_frame which is stored only in binary, not in coredump
     * or debuginfo.
     *
     * Fedora GDB does not strictly need it, it will find the binary
     * by its build-id.  But for binaries either without build-id
     * (= built on non-Fedora GCC) or which do not have
     * their debuginfo rpm installed gdb would not find BINARY_FILE
     * so it is still makes sense to supply "file BINARY_FILE".
     *
     * Unfortunately, "file BINARY_FILE" doesn't work well if BINARY_FILE
     * was deleted (as often happens during system updates):
     * gdb uses specified BINARY_FILE
     * even if it is completely unrelated to the coredump.
     * See https://bugzilla.redhat.com/show_bug.cgi?id=525721
     *
     * TODO: check mtimes on COREFILE and BINARY_FILE and not supply
     * BINARY_FILE if it is newer (to at least avoid gdb complaining).
     */
    args[i++] = (char*)"-ex";
    const unsigned file_cmd_index = i++;
    args[file_cmd_index] = xasprintf("file %s", executable);
    free(executable);

    args[i++] = (char*)"-ex";
    const unsigned core_cmd_index = i++;
    args[core_cmd_index] = xasprintf("core-file %s/"FILENAME_COREDUMP, dump_dir_name);

    args[i++] = (char*)"-ex";
    const unsigned bt_cmd_index = i++;
    /*args[9] = ... see below */
    args[i++] = (char*)"-ex";
    args[i++] = (char*)"info sharedlib";
    /* glibc's abort() stores its message in __abort_msg variable */
    args[i++] = (char*)"-ex";
    args[i++] = (char*)"print (char*)__abort_msg";
    args[i++] = (char*)"-ex";
    args[i++] = (char*)"print (char*)__glib_assert_msg";
    args[i++] = (char*)"-ex";
    args[i++] = (char*)"info all-registers";
    args[i++] = (char*)"-ex";
    const unsigned dis_cmd_index = i++;
    args[dis_cmd_index] = (char*)"disassemble";
    args[i++] = NULL;

    /* Get the backtrace, but try to cap its size */
    /* Limit bt depth. With no limit, gdb sometimes OOMs the machine */
    unsigned bt_depth = 1024;
    const char *thread_apply_all = "thread apply all -ascending";
    const char *full = " full";
    char *bt = NULL;
    while (1)
    {
        args[bt_cmd_index] = xasprintf("%s backtrace %u%s", thread_apply_all, bt_depth, full);
        bt = exec_vp(args, /*redirect_stderr:*/ 1, timeout_sec, NULL);
        free(args[bt_cmd_index]);
        if ((bt && strnlen(bt, 256*1024) < 256*1024) || bt_depth <= 32)
        {
            break;
        }

        bt_depth /= 2;
        if (bt)
            log("Backtrace is too big (%u bytes), reducing depth to %u",
                        (unsigned)strlen(bt), bt_depth);
        else
            /* (NB: in fact, current impl. of exec_vp() never returns NULL) */
            log("Failed to generate backtrace, reducing depth to %u",
                        bt_depth);
        free(bt);

        /* Replace -ex disassemble (which disasms entire function $pc points to)
         * to a version which analyzes limited, small patch of code around $pc.
         * (Users reported a case where bare "disassemble" attempted to process
         * entire .bss).
         * TODO: what if "$pc-N" underflows? in my test, this happens:
         * Dump of assembler code from 0xfffffffffffffff0 to 0x30:
         * End of assembler dump.
         * (IOW: "empty" dump)
         */
        args[dis_cmd_index] = (char*)"disassemble $pc-20, $pc+64";

        if (bt_depth <= 64 && thread_apply_all[0] != '\0')
        {
            /* This program likely has gazillion threads, dont try to bt them all */
            bt_depth = 128;
            thread_apply_all = "";
        }
        if (bt_depth <= 64 && full[0] != '\0')
        {
            /* Looks like there are gigantic local structures or arrays, disable "full" bt */
            bt_depth = 128;
            full = "";
        }
    }

    if (auto_load_base_index > 0)
    {
        free(args[auto_load_base_index]);
        free(args[auto_load_base_index + 2]);
    }

    free(args[debug_dir_cmd_index]);
    free(args[file_cmd_index]);
    free(args[core_cmd_index]);
    return bt;
}