From dd11716e5c6c3e2589dfc6440e131a06d7eecd3a Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Sat, 26 Mar 2011 15:01:47 +0100 Subject: Analyze backtraces from retrace server Hi, the attached patch splits a part of abrt-action-generate-backtrace to a new tool abrt-action-analyze-backtrace, which is used by both LocalGDB and RetraceServer analyzers. Then new abrt-action-analyze-backtrace tool reads backtrace and generates duplication hash, detects crash function, and provides backtrace rating. These steps haven't been performed for remotely analyzed crashes so far. Karel --- src/plugins/Makefile.am | 20 +++ src/plugins/abrt-action-analyze-backtrace.c | 190 +++++++++++++++++++++++++++ src/plugins/abrt-action-generate-backtrace.c | 131 +----------------- src/plugins/ccpp_events.conf | 6 +- 4 files changed, 222 insertions(+), 125 deletions(-) create mode 100644 src/plugins/abrt-action-analyze-backtrace.c (limited to 'src') diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 8dd618e6..5344cdb4 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -11,6 +11,7 @@ bin_PROGRAMS = \ abrt-action-analyze-oops \ abrt-action-trim-files \ abrt-action-generate-backtrace \ + abrt-action-analyze-backtrace \ abrt-action-bugzilla \ abrt-action-rhtsupport \ abrt-action-kerneloops \ @@ -179,6 +180,25 @@ abrt_action_generate_backtrace_CPPFLAGS = \ -D_GNU_SOURCE \ -Wall -Wwrite-strings -Werror abrt_action_generate_backtrace_LDADD = \ + ../lib/libreport.la + +abrt_action_analyze_backtrace_SOURCES = \ + abrt-action-analyze-backtrace.c +abrt_action_analyze_backtrace_CPPFLAGS = \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ + -I$(srcdir)/../lib \ + -DBIN_DIR=\"$(bindir)\" \ + -DVAR_RUN=\"$(VAR_RUN)\" \ + -DCONF_DIR=\"$(CONF_DIR)\" \ + -DLOCALSTATEDIR='"$(localstatedir)"' \ + -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ + -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \ + -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ + -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + $(GLIB_CFLAGS) \ + -D_GNU_SOURCE \ + -Wall -Wwrite-strings -Werror +abrt_action_analyze_backtrace_LDADD = \ ../lib/libreport.la \ ../btparser/libbtparser.la diff --git a/src/plugins/abrt-action-analyze-backtrace.c b/src/plugins/abrt-action-analyze-backtrace.c new file mode 100644 index 00000000..e65b1781 --- /dev/null +++ b/src/plugins/abrt-action-analyze-backtrace.c @@ -0,0 +1,190 @@ +/* + Copyright (C) 2010, 2011 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "abrtlib.h" +#include "../btparser/backtrace.h" +#include "../btparser/frame.h" +#include "../btparser/location.h" +#include "parse_options.h" + +#define PROGNAME "abrt-action-generate-backtrace" + +static const char *dump_dir_name = "."; + + +static void create_hash(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *pInput) +{ + unsigned len; + unsigned char hash2[SHA1_RESULT_LEN]; + sha1_ctx_t sha1ctx; + + sha1_begin(&sha1ctx); + sha1_hash(pInput, strlen(pInput), &sha1ctx); + sha1_end(hash2, &sha1ctx); + len = SHA1_RESULT_LEN; + + char *d = hash_str; + unsigned char *s = hash2; + while (len) + { + *d++ = "0123456789abcdef"[*s >> 4]; + *d++ = "0123456789abcdef"[*s & 0xf]; + s++; + len--; + } + *d = '\0'; + //log("hash2:%s str:'%s'", hash_str, pInput); +} + +int main(int argc, char **argv) +{ + char *env_verbose = getenv("ABRT_VERBOSE"); + if (env_verbose) + g_verbose = atoi(env_verbose); + + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( + PROGNAME" [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); + + putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); + + char *pfx = getenv("ABRT_PROG_PREFIX"); + if (pfx && string_to_bool(pfx)) + msg_prefix = PROGNAME; + + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + return 1; + + char *package = dd_load_text(dd, FILENAME_PACKAGE); + char *executable = dd_load_text(dd, FILENAME_EXECUTABLE); + + /* Read backtrace */ + /* NB: get_backtrace() closes dd */ + char *backtrace_str = dd_load_text(dd, FILENAME_BACKTRACE); + if (!backtrace_str) + { + backtrace_str = xstrdup(""); + log("Backtrace file is missing"); + } + + /* 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 UUID from the executable + * and package only. This is not supposed to happen often. + */ + VERB1 log(_("Backtrace parsing failed for %s"), dump_dir_name); + VERB1 log("%d:%d: %s", location.line, location.column, location.message); + struct strbuf *emptybt = strbuf_new(); + strbuf_prepend_str(emptybt, executable); + strbuf_prepend_str(emptybt, package); + + 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(package); + free(executable); + 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, package); + strbuf_append_str(str_hash, executable); + strbuf_append_str(str_hash, str_hash_core); + + 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(executable); + free(package); + + return 0; +} diff --git a/src/plugins/abrt-action-generate-backtrace.c b/src/plugins/abrt-action-generate-backtrace.c index 0c2d9a0a..5afe6e43 100644 --- a/src/plugins/abrt-action-generate-backtrace.c +++ b/src/plugins/abrt-action-generate-backtrace.c @@ -1,6 +1,6 @@ /* Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) - Copyright (C) 2009 RedHat inc. + Copyright (C) 2009 Red Hat, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,30 +33,6 @@ static const char *debuginfo_dirs = DEBUGINFO_CACHE_DIR; static int exec_timeout_sec = 240; -static void create_hash(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *pInput) -{ - unsigned len; - unsigned char hash2[SHA1_RESULT_LEN]; - sha1_ctx_t sha1ctx; - - sha1_begin(&sha1ctx); - sha1_hash(pInput, strlen(pInput), &sha1ctx); - sha1_end(hash2, &sha1ctx); - len = SHA1_RESULT_LEN; - - char *d = hash_str; - unsigned char *s = hash2; - while (len) - { - *d++ = "0123456789abcdef"[*s >> 4]; - *d++ = "0123456789abcdef"[*s & 0xf]; - s++; - len--; - } - *d = '\0'; - //log("hash2:%s str:'%s'", hash_str, pInput); -} - /** * * @param[out] status See `man 2 wait` for status information. @@ -299,119 +275,26 @@ int main(int argc, char **argv) if (!dd) return 1; - char *package = dd_load_text(dd, FILENAME_PACKAGE); - char *executable = dd_load_text(dd, FILENAME_EXECUTABLE); - /* Create gdb backtrace */ /* NB: get_backtrace() closes dd */ - char *backtrace_str = get_backtrace(dd); - if (!backtrace_str) + char *backtrace = get_backtrace(dd); + if (!backtrace) { - backtrace_str = xstrdup(""); + backtrace = xstrdup(""); log("get_backtrace() returns NULL, broken core/gdb?"); } - /* 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); - /* Store gdb backtrace */ dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return 1; - dd_save_text(dd, FILENAME_BACKTRACE, backtrace_str); + dd_save_text(dd, FILENAME_BACKTRACE, backtrace); /* Don't be completely silent. gdb run takes a few seconds, * it is useful to let user know it (maybe) worked. */ - log(_("Backtrace is generated and saved, %u bytes"), (int)strlen(backtrace_str)); - free(backtrace_str); - - /* Store backtrace hash */ - - if (!backtrace) - { - /* - * The parser failed. Compute the UUID from the executable - * and package only. This is not supposed to happen often. - */ - VERB1 log(_("Backtrace parsing failed for %s"), dump_dir_name); - VERB1 log("%d:%d: %s", location.line, location.column, location.message); - struct strbuf *emptybt = strbuf_new(); - strbuf_prepend_str(emptybt, executable); - strbuf_prepend_str(emptybt, package); - - 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(package); - free(executable); - 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, package); - strbuf_append_str(str_hash, executable); - strbuf_append_str(str_hash, str_hash_core); - - 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(executable); - free(package); + log(_("Backtrace is generated and saved, %u bytes"), (int)strlen(backtrace)); + free(backtrace); return 0; } diff --git a/src/plugins/ccpp_events.conf b/src/plugins/ccpp_events.conf index 0698e655..8a5f377e 100644 --- a/src/plugins/ccpp_events.conf +++ b/src/plugins/ccpp_events.conf @@ -7,13 +7,17 @@ EVENT=analyze_LocalGDB analyzer=CCpp backtrace= abrt-action-trim-files -f 4 # or was this ability lost with move to python installer? EVENT=analyze_LocalGDB analyzer=CCpp backtrace= abrt-action-install-debuginfo --core="$DUMP_DIR/coredump" EVENT=analyze_LocalGDB analyzer=CCpp backtrace= abrt-action-generate-backtrace -EVENT=analyze_RetraceServer analyzer=CCpp backtrace= abrt-retrace-client batch -k --dir "$DUMP_DIR" +EVENT=analyze_LocalGDB analyzer=CCpp backtrace= abrt-action-analyze-backtrace +EVENT=analyze_RetraceServer analyzer=CCpp backtrace= abrt-retrace-client batch -k --dir "$DUMP_DIR" +EVENT=analyze_RetraceServer analyzer=CCpp backtrace= abrt-action-analyze-backtrace # Same as "analyze", but executed when user requests "refresh" in GUI # It doesn't check that backtrace is empty: EVENT=reanalyze_LocalGDB analyzer=CCpp abrt-action-trim-files -f 4096m:/var/cache/abrt-di EVENT=reanalyze_LocalGDB analyzer=CCpp abrt-action-install-debuginfo --core="$DUMP_DIR/coredump" EVENT=reanalyze_LocalGDB analyzer=CCpp abrt-action-generate-backtrace +EVENT=reanalyze_LocalGDB analyzer=CCpp abrt-action-analyze-backtrace EVENT=reanalyze_RetraceServer analyzer=CCpp abrt-retrace-client batch -k --dir "$DUMP_DIR" +EVENT=reanalyze_RetraceServer analyzer=CCpp abrt-action-analyze-backtrace EVENT=report_Bugzilla analyzer=CCpp abrt-action-bugzilla -c /etc/abrt/plugins/Bugzilla.conf -- cgit