diff options
author | Karel Klic <kklic@redhat.com> | 2010-02-07 17:34:10 +0100 |
---|---|---|
committer | Karel Klic <kklic@redhat.com> | 2010-02-07 17:34:10 +0100 |
commit | 93dc51be22ffdf1632f1aba4797eb9bab40e1280 (patch) | |
tree | 3f6d13df03247b537746010034d90aa75f4eddca /scripts | |
parent | 7ac55cf99fbbc974c6f37f3287c5897f68da0fc1 (diff) | |
download | abrt-93dc51be22ffdf1632f1aba4797eb9bab40e1280.tar.gz abrt-93dc51be22ffdf1632f1aba4797eb9bab40e1280.tar.xz abrt-93dc51be22ffdf1632f1aba4797eb9bab40e1280.zip |
abrt-rate-backtrace utility
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/abrt-rate-backtrace.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/scripts/abrt-rate-backtrace.c b/scripts/abrt-rate-backtrace.c new file mode 100644 index 00000000..07248233 --- /dev/null +++ b/scripts/abrt-rate-backtrace.c @@ -0,0 +1,183 @@ +/* -*-mode:c++;c-file-style:"bsd";c-basic-offset:4;indent-tabs-mode:nil-*- + * Returns rating 0-4 of backtrace file on stdout. + * 4 - backtrace with complete or almost-complete debuginfos + * 0 - useless backtrace with no debuginfos + * Compile: + * gcc abrt-rate-backtrace.c -std=c99 -o abrt-rate-backtrace + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> + +// Die if we can't allocate n+1 bytes (space for the null terminator) and copy +// the (possibly truncated to length n) string into it. +static char* xstrndup(const char *s, int n) +{ + int m; + char *t; + + /* We can just xmalloc(n+1) and strncpy into it, */ + /* but think about xstrndup("abc", 10000) wastage! */ + m = n; + t = (char*) s; + while (m) { + if (!*t) break; + m--; + t++; + } + n -= m; + t = (char*) malloc(n + 1); + t[n] = '\0'; + + return (char*) memcpy(t, s, n); +} + +enum LineRating +{ + // RATING EXAMPLE + MissingEverything = 0, // #0 0x0000dead in ?? () + MissingFunction = 1, // #0 0x0000dead in ?? () from /usr/lib/libfoobar.so.4 + MissingLibrary = 2, // #0 0x0000dead in foobar() + MissingSourceFile = 3, // #0 0x0000dead in FooBar::FooBar () from /usr/lib/libfoobar.so.4 + Good = 4, // #0 0x0000dead in FooBar::crash (this=0x0) at /home/user/foobar.cpp:204 + BestRating = Good, +}; + +static enum LineRating rate_line(const char *line) +{ +#define FOUND(x) (strstr(line, x) != NULL) + /* see the "enum LineRating" comments for possible combinations */ + if (FOUND(" at ")) + return Good; + const char *function = strstr(line, " in "); + if (function) + { + if (function[4] == '?') /* " in ??" does not count */ + { + function = NULL; + } + } + bool library = FOUND(" from "); + if (function && library) + return MissingSourceFile; + if (function) + return MissingLibrary; + if (library) + return MissingFunction; + + return MissingEverything; +#undef FOUND +} + +/* returns number of "stars" to show */ +static int rate_backtrace(const char *backtrace) +{ + int i, len; + int multiplier = 0; + int rating = 0; + int best_possible_rating = 0; + char last_lvl = 0; + + /* We look at the frames in reversed order, since: + * - rate_line() checks starting from the first line of the frame + * (note: it may need to look at more than one line!) + * - we increase weight (multiplier) for every frame, + * so that topmost frames end up most important + */ + len = 0; + for (i = strlen(backtrace) - 1; i >= 0; i--) + { + if (backtrace[i] == '#' + && (backtrace[i+1] >= '0' && backtrace[i+1] <= '9') /* #N */ + && (i == 0 || backtrace[i-1] == '\n') /* it's at line start */ + ) { + /* For one, "#0 xxx" always repeats, skip repeats */ + if (backtrace[i+1] == last_lvl) + continue; + last_lvl = backtrace[i+1]; + + char *s = xstrndup(backtrace + i + 1, len); + /* Replace tabs with spaces, rate_line() does not expect tabs. + * Actually, even newlines may be there. Example of multiline frame + * where " at SRCFILE" is on 2nd line: + * #3 0x0040b35d in __libc_message (do_abort=<value optimized out>, + * fmt=<value optimized out>) at ../sysdeps/unix/sysv/linux/libc_fatal.c:186 + */ + for (char *p = s; *p; p++) + if (*p == '\t' || *p == '\n') + *p = ' '; + int lrate = rate_line(s); + multiplier++; + rating += lrate * multiplier; + best_possible_rating += BestRating * multiplier; + //log("lrate:%d rating:%d best_possible_rating:%d s:'%-.40s'", lrate, rating, best_possible_rating, s); + free(s); + len = 0; /* starting new line */ + } + else + { + len++; + } + } + + /* Bogus 'backtrace' with zero frames? */ + if (best_possible_rating == 0) + return 0; + + /* Returning number of "stars" to show */ + if (rating*10 >= best_possible_rating*8) /* >= 0.8 */ + return 4; + if (rating*10 >= best_possible_rating*6) + return 3; + if (rating*10 >= best_possible_rating*4) + return 2; + if (rating*10 >= best_possible_rating*2) + return 1; + + return 0; +} + +int main(int argc, char **argv) +{ + if (argc != 2) + { + fprintf(stderr, "Usage: %s BACKTRACE_FILE\n", argv[0]); + return 1; + } + + FILE *fp = fopen(argv[1], "r"); + if (!fp) + { + fprintf(stderr, "Cannot open the input file.\n"); + return 2; + } + fseek(fp, 0, SEEK_END); + size_t size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + char *file = malloc(size + 1); + if (!file) + { + fprintf(stderr, "Malloc error.\n"); + return 3; + } + size_t read = fread(file, size, 1, fp); + if (read != 1) + { + fprintf(stderr, "Error while reading file.\n", argv[0]); + return 4; + } + fclose(fp); + file[size] = '\0'; + + int rating = 4; + /* Do not rate Python backtraces. */ + if (NULL == strstr(file, "Local variables in innermost frame:\n")) + rating = rate_backtrace(file); + + free(file); + fprintf(stdout, "%d", rating); + return 0; +} |