summaryrefslogtreecommitdiffstats
path: root/src/Backtrace
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2009-11-25 16:39:18 +0100
committerKarel Klic <kklic@redhat.com>2009-11-25 16:39:18 +0100
commit02e46d27da349907b2a1f389ce7043b6e40c45cb (patch)
tree93726630ecefd98a9787fd4121b10ebc42165a42 /src/Backtrace
parent6b30462c4b8f65e7a76009cfd1308e651a973c58 (diff)
downloadabrt-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.h2
-rw-r--r--src/Backtrace/fallback.c30
-rw-r--r--src/Backtrace/fallback.h2
-rw-r--r--src/Backtrace/main.c74
-rw-r--r--src/Backtrace/parser.y120
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;