diff options
author | Karel Klic <kklic@redhat.com> | 2009-11-25 16:39:18 +0100 |
---|---|---|
committer | Karel Klic <kklic@redhat.com> | 2009-11-25 16:39:18 +0100 |
commit | 02e46d27da349907b2a1f389ce7043b6e40c45cb (patch) | |
tree | 93726630ecefd98a9787fd4121b10ebc42165a42 /src/Backtrace | |
parent | 6b30462c4b8f65e7a76009cfd1308e651a973c58 (diff) | |
download | abrt-02e46d27da349907b2a1f389ce7043b6e40c45cb.tar.gz abrt-02e46d27da349907b2a1f389ce7043b6e40c45cb.tar.xz abrt-02e46d27da349907b2a1f389ce7043b6e40c45cb.zip |
Parser simplified and even more corner cases added. Backtrace file is now loaded into memory and preprocessed before parsing. Backtrace file size limit increased to ~20 MB
Diffstat (limited to 'src/Backtrace')
-rw-r--r-- | src/Backtrace/backtrace.h | 2 | ||||
-rw-r--r-- | src/Backtrace/fallback.c | 30 | ||||
-rw-r--r-- | src/Backtrace/fallback.h | 2 | ||||
-rw-r--r-- | src/Backtrace/main.c | 74 | ||||
-rw-r--r-- | src/Backtrace/parser.y | 120 |
5 files changed, 130 insertions, 98 deletions
diff --git a/src/Backtrace/backtrace.h b/src/Backtrace/backtrace.h index 3091c630..ed6d3151 100644 --- a/src/Backtrace/backtrace.h +++ b/src/Backtrace/backtrace.h @@ -89,6 +89,6 @@ extern void backtrace_limit_frame_depth(struct backtrace *backtrace, int depth); extern void backtrace_remove_exit_handlers(struct backtrace *backtrace); /* Defined in parser.y. */ -extern struct backtrace *do_parse(FILE *input, bool debug_parser, bool debug_scanner); +extern struct backtrace *do_parse(char *input, bool debug_parser, bool debug_scanner); #endif diff --git a/src/Backtrace/fallback.c b/src/Backtrace/fallback.c index b77a7cb7..70e5e43a 100644 --- a/src/Backtrace/fallback.c +++ b/src/Backtrace/fallback.c @@ -19,9 +19,6 @@ #include <stdlib.h> #include <stdbool.h> -/* Too large files are trimmed. */ -#define FILE_SIZE_LIMIT 10000000 /* ~ 10 MB */ - struct header { struct strbuf *text; @@ -70,30 +67,8 @@ static void header_set_insert(struct header *cur, struct strbuf *new) header_set_insert(cur->next, new); } -struct strbuf *independent_backtrace(FILE *fp) +struct strbuf *independent_backtrace(char *input) { - long pos = ftell(fp); - fseek(fp, 0, SEEK_END); - long size = ftell(fp) - pos; - fseek(fp, pos, SEEK_SET); - - /* Silently handle large files. */ - if (size > FILE_SIZE_LIMIT) - size = FILE_SIZE_LIMIT; - - char *contents = malloc(size); - if (!contents) - { - puts("Error while allocating memory for independent backtrace."); - exit(5); - } - - if (fread(contents, size, 1, fp) != 1) - { - puts("Error while reading input file."); - exit(6); - } - struct strbuf *header = strbuf_new(); bool in_bracket = false; bool in_quote = false; @@ -104,7 +79,7 @@ struct strbuf *independent_backtrace(FILE *fp) bool has_bracket = false; struct header *headers = NULL; - const char *bk = contents; + const char *bk = input; while (*bk) { if (bk[0] == '#' @@ -179,7 +154,6 @@ struct strbuf *independent_backtrace(FILE *fp) } strbuf_free(header); - free(contents); struct strbuf *result = strbuf_new(); struct header *loop = headers; diff --git a/src/Backtrace/fallback.h b/src/Backtrace/fallback.h index 9c31fecf..85b06320 100644 --- a/src/Backtrace/fallback.h +++ b/src/Backtrace/fallback.h @@ -27,6 +27,6 @@ * The independent backtrace. Caller is responsible for calling * strbuf_free() on it. */ -extern struct strbuf *independent_backtrace(FILE *fp); +extern struct strbuf *independent_backtrace(char *input); #endif diff --git a/src/Backtrace/main.c b/src/Backtrace/main.c index 459185eb..315b6efb 100644 --- a/src/Backtrace/main.c +++ b/src/Backtrace/main.c @@ -20,10 +20,14 @@ #include <argp.h> #include <stdlib.h> #include <sysexits.h> +#include <string.h> #include "config.h" #include "backtrace.h" #include "fallback.h" +/* Too large files are trimmed. */ +#define FILE_SIZE_LIMIT 20000000 /* ~ 20 MB */ + #define EX_PARSINGFAILED EX__MAX + 1 #define EX_THREADDETECTIONFAILED EX__MAX + 2 @@ -125,7 +129,7 @@ int main(int argc, char **argv) arguments.filename = 0; argp_parse(&argp, argc, argv, 0, 0, &arguments); - /* Open input file and parse it. */ + /* Open input file, and parse it. */ FILE *fp = fopen(arguments.filename, "r"); if (!fp) { @@ -133,33 +137,85 @@ int main(int argc, char **argv) exit(EX_NOINPUT); /* No such file or directory */ } + /* Header and footer of the backtrace is stripped to simplify the parser. + * A drawback is that the backtrace must be loaded to memory. + */ + fseek(fp, 0, SEEK_END); + size_t size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + if (size > FILE_SIZE_LIMIT) + { + fprintf(stderr, "Input file too big (%zd). Maximum size is %zd", + size, FILE_SIZE_LIMIT); + exit(EX_IOERR); + } + + char *bttext = malloc(size + 1); + if (1 != fread(bttext, size, 1, fp)) + { + fprintf(stderr, "Unable to read from '%s'.\n", arguments.filename); + exit(EX_IOERR); /* IO Error */ + } + + bttext[size] = '\0'; + fclose(fp); + /* Print independent backtrace and exit. */ if (arguments.independent) { - struct strbuf *ibt = independent_backtrace(fp); - fclose(fp); + struct strbuf *ibt = independent_backtrace(bttext); puts(ibt->buf); strbuf_free(ibt); + free(bttext); return 0; /* OK */ } + /* Skip the backtrace header information. */ + char *btnoheader_a = strstr(bttext, "\nThread "); + char *btnoheader_b = strstr(bttext, "#"); + char *btnoheader = bttext; + if (btnoheader < btnoheader_a) + btnoheader = btnoheader_a + 1; + if (btnoheader < btnoheader_b) + btnoheader = btnoheader_b; + + /* Cut the backtrace footer. + * Footer: lines not starting with # or "Thread", and separated from + * the backtrace body by a newline. + */ + int i; + for (i = size - 1; i > 0; --i) + { + if (bttext[i] != '\n') + continue; + if (strncmp(bttext + i + 1, "Thread", strlen("Thread")) == 0) + break; + if (bttext[i + 1] == '#') + break; + if (bttext[i - 1] == '\n') + { + bttext[i] = '\0'; + break; + } + } + /* Try to parse the backtrace. */ struct backtrace *backtrace; - backtrace = do_parse(fp, arguments.debug_parser, arguments.debug_scanner); + backtrace = do_parse(btnoheader, arguments.debug_parser, arguments.debug_scanner); /* If the parser failed print independent backtrace. */ if (!backtrace) { - fseek(fp, 0, SEEK_SET); - struct strbuf *ibt = independent_backtrace(fp); - fclose(fp); + struct strbuf *ibt = independent_backtrace(bttext); puts(ibt->buf); strbuf_free(ibt); - /* PARSING FAILED, BUT OUTPUT CAN BE USED */ + free(bttext); + /* Parsing failed, but the output can be used. */ return EX_PARSINGFAILED; } - fclose(fp); + free(bttext); /* If a single thread is requested, remove all other threads. */ int retval = 0; diff --git a/src/Backtrace/parser.y b/src/Backtrace/parser.y index 8512366a..ae068a13 100644 --- a/src/Backtrace/parser.y +++ b/src/Backtrace/parser.y @@ -48,7 +48,7 @@ void yyerror(char const *s) /* Bison declarations. */ %token END 0 "end of file" -%type <backtrace> backtrace ignoredpart_backtrace +%type <backtrace> backtrace %type <thread> threads thread %type <frame> frames frame frame_head frame_head_1 frame_head_2 frame_head_3 frame_head_4 frame_head_5 %type <strbuf> identifier hexadecimal_digit_sequence hexadecimal_number file_name file_location function_call function_name digit_sequence frame_address_in_function @@ -74,33 +74,25 @@ void yyerror(char const *s) %% /* The grammar follows. */ -backtrace : /* empty */ { $$ = g_backtrace = backtrace_new(); } - | ignoredpart_backtrace wsa { $$ = g_backtrace = $1; } -; - -/**/ -ignoredpart_backtrace : threads %dprec 2 - { - $$ = backtrace_new(); - $$->threads = $1; - } - | frame_head wss threads %dprec 4 - { - $$ = backtrace_new(); - $$->threads = $3; - $$->crash = $1; - } - | frame wss threads %dprec 3 - { - $$ = backtrace_new(); - $$->threads = $3; - $$->crash = $1; - } - | anychar ignoredpart_backtrace %dprec 1 { $$ = $2; } -; - -anychar : ws | digit | nondigit | '(' | ')' | '+' | '-' | '#' | '=' | ':' | ';' - | '/' | '.' | '[' | ']' | '?' | '\'' | '`' | ',' | '<' | '>' | '"' +backtrace : /* empty */ %dprec 1 + { $$ = g_backtrace = backtrace_new(); } + | threads wsa %dprec 2 + { + $$ = g_backtrace = backtrace_new(); + $$->threads = $1; + } + | frame_head wss threads wsa %dprec 4 + { + $$ = g_backtrace = backtrace_new(); + $$->threads = $3; + $$->crash = $1; + } + | frame wss threads wsa %dprec 3 + { + $$ = g_backtrace = backtrace_new(); + $$->threads = $3; + $$->crash = $1; + } ; threads : thread { $$ = $1; } @@ -217,36 +209,32 @@ file_location : file_name ':' digit_sequence variables : variables_line '\n' | variables_line END - | variables_line variables_wss '\n' - | variables_line variables_wss END + | variables_line wss_nonl '\n' + | variables_line wss_nonl END | variables variables_line '\n' | variables variables_line END - | variables variables_wss variables_line '\n' - | variables variables_wss variables_line END - | variables variables_wss variables_line variables_wss '\n' - | variables variables_wss variables_line variables_wss END + | variables wss_nonl variables_line '\n' + | variables wss_nonl variables_line END + | variables wss_nonl variables_line wss_nonl '\n' + | variables wss_nonl variables_line wss_nonl END ; variables_line : variables_char_no_framestart | variables_line variables_char - | variables_line variables_wss variables_char -; - -variables_ws : '\t' | ' ' -; - -variables_wss : variables_ws - | variables_wss variables_ws + | variables_line wss_nonl variables_char ; variables_char : '#' | variables_char_no_framestart ; -variables_char_no_framestart : digit | nondigit | '(' | ')' | '+' | '-' | '<' - | '>' | '"' | '/' | '.' | '[' | ']' | '?' | '\'' - | '`' | ',' | '=' | '{' | '}' | '^' | '&' | '$' - | ':' | ';' | '\\' | '!' | '@' | '*' | '%' | '|' - | '~' +/* Manually synchronized with function_args_char. */ +variables_char_no_framestart : digit | nondigit | '"' | '(' | ')' + | '+' | '-' | '<' | '>' | '/' | '.' + | '[' | ']' | '?' | '\'' | '`' | ',' + | '=' | '{' | '}' | '^' | '&' | '$' + | ':' | ';' | '\\' | '!' | '@' | '*' + | '%' | '|' | '~' +; function_call : function_name wsa function_args ; @@ -263,20 +251,24 @@ function_args : '(' wsa ')' | '(' wsa function_args_sequence wsa ')' ; - /* TODO: function arguments can contain strings in "". As the string can - contain any ascii-visible character (nonvisible chars are escaped), - this must be somehow handled, especially characters ( and ). */ function_args_sequence : function_args_char + | function_args_sequence wsa '(' wsa ')' + | function_args_sequence wsa '(' wsa function_args_sequence wsa ')' | function_args_sequence wsa function_args_char | function_args_sequence wsa function_args_string ; function_args_string : '"' function_args_string_sequence '"' + | '"' '"' ; -function_args_char : digit | nondigit | '{' | '}' | '<' | '>' | ':' | '~' - | '=' | '-' | '+' | '@' | ',' | '.' | '[' | ']' | '/' | '%' - | '\\' | '&' +/* Manually synchronized with variables_char_no_framestart. */ +function_args_char : digit | nondigit + | '+' | '-' | '<' | '>' | '/' | '.' + | '[' | ']' | '?' | '\'' | '`' | ',' + | '=' | '{' | '}' | '^' | '&' | '$' + | ':' | ';' | '\\' | '!' | '@' | '*' + | '%' | '|' | '~' ; function_args_string_sequence : function_args_string_char @@ -348,7 +340,16 @@ nondigit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' ; /* whitespace */ -ws : '\t' | ' ' | '\n' | '\r' +ws : ws_nonl | '\n' | '\r' +; + + /* No newline.*/ +ws_nonl : '\t' | ' ' +; + + /* whitespace sequence without a newline */ +wss_nonl : ws_nonl + | wss_nonl ws_nonl ; /* whitespace sequence */ @@ -379,13 +380,14 @@ keyword_sighandler: '<' 's' 'i' 'g' 'n' 'a' 'l' ' ' 'h' 'a' 'n' 'd' 'l' 'e' 'r' %% static bool scanner_echo = false; -static FILE *yyin; +static char *yyin; int yylex() { - int c = fgetc(yyin); - if (c == EOF) - return 0; + char c = *yyin; + if (c == '\0') + return END; + ++yyin; /* Debug output. */ if (scanner_echo) @@ -403,7 +405,7 @@ int yylex() * backtrace_free() on this. * Returns NULL when parsing failed. */ -struct backtrace *do_parse(FILE *input, bool debug_parser, bool debug_scanner) +struct backtrace *do_parse(char *input, bool debug_parser, bool debug_scanner) { /* Prepare for running parser. */ g_backtrace = 0; |