diff options
| author | Karel Klic <kklic@redhat.com> | 2009-11-20 17:54:17 +0100 |
|---|---|---|
| committer | Karel Klic <kklic@redhat.com> | 2009-11-20 17:54:17 +0100 |
| commit | b8da7620a417ef835869da692db140b75e8b7a93 (patch) | |
| tree | 9afa3edca4663fde9118550ca839b7021f4b0eb0 | |
| parent | 10ca6da1cc2d89ba5c45179d452720d916bc4698 (diff) | |
| download | abrt-b8da7620a417ef835869da692db140b75e8b7a93.tar.gz abrt-b8da7620a417ef835869da692db140b75e8b7a93.tar.xz abrt-b8da7620a417ef835869da692db140b75e8b7a93.zip | |
Backtrace parser improvements
| -rw-r--r-- | src/Backtrace/backtrace.c | 35 | ||||
| -rw-r--r-- | src/Backtrace/backtrace.h | 8 | ||||
| -rw-r--r-- | src/Backtrace/parser.y | 138 | ||||
| -rw-r--r-- | src/Backtrace/strbuf.c | 63 | ||||
| -rw-r--r-- | src/Backtrace/strbuf.h | 11 |
5 files changed, 203 insertions, 52 deletions
diff --git a/src/Backtrace/backtrace.c b/src/Backtrace/backtrace.c index b2a1e6d..6090298 100644 --- a/src/Backtrace/backtrace.c +++ b/src/Backtrace/backtrace.c @@ -60,6 +60,21 @@ struct frame *frame_add_sibling(struct frame *a, struct frame *b) return a; } +static void frame_print_tree(struct frame *frame) +{ + printf(" #%d", frame->number); + if (frame->function) + printf(" %s", frame->function); + if (frame->sourcefile) + { + if (frame->function) + printf(" at"); + printf(" %s", frame->sourcefile); + } + + puts(""); /* newline */ +} + struct thread *thread_new() { struct thread *t = malloc(sizeof(struct thread)); @@ -96,8 +111,28 @@ struct thread *thread_add_sibling(struct thread *a, struct thread *b) return a; } +static int thread_get_frame_count(struct thread *thread) +{ + struct frame *f = thread->frames; + int count = 0; + while (f) + { + f = f->next; + ++count; + } + return count; +} + static void thread_print_tree(struct thread *thread) { + int framecount = thread_get_frame_count(thread); + printf("Thread no. %d (%d frames)\n", thread->number, framecount); + struct frame *frame = thread->frames; + while (frame) + { + frame_print_tree(frame); + frame = frame->next; + } } struct backtrace *backtrace_new() diff --git a/src/Backtrace/backtrace.h b/src/Backtrace/backtrace.h index f42cfcd..0f99a19 100644 --- a/src/Backtrace/backtrace.h +++ b/src/Backtrace/backtrace.h @@ -23,12 +23,19 @@ struct frame { + /* Function name, or NULL. */ char *function; + /* Arguments of the function call, or NULL. */ char *args; + /* Frame number. */ int number; + /* ?? */ char *binfile; + /* Name of the source file, or NULL. */ char *sourcefile; + /* True if this is the frame where the crash happened. */ bool crash; + /* Sibling frame, or NULL if this is the last frame in a thread. */ struct frame *next; }; @@ -36,6 +43,7 @@ struct thread { int number; struct frame *frames; + /* Sibling thread, or NULL if this is the last thread in a backtrace. */ struct thread *next; }; diff --git a/src/Backtrace/parser.y b/src/Backtrace/parser.y index 9b9caba..1062ae8 100644 --- a/src/Backtrace/parser.y +++ b/src/Backtrace/parser.y @@ -49,12 +49,18 @@ void yyerror(char const *s) %type <backtrace> backtrace ignoredpart_backtrace %type <thread> threads thread %type <frame> frames frame -%type <strbuf> identifier hexadecimal_digit_sequence hexadecimal_number file_name function_call function_name digit_sequence +%type <strbuf> identifier hexadecimal_digit_sequence hexadecimal_number file_name file_location function_call function_name digit_sequence frame_address_in_function %type <c> nondigit digit hexadecimal_digit file_name_char '(' ')' '+' '-' '/' '.' 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z' '_' '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' '\'' '`' ',' '#' '@' '<' '>' '=' ':' '"' ';' ' ' '\n' '\t' '\\' '!' '*' '%' '|' '^' '&' '$' +%type <num> frame_head + +%destructor { thread_free($$); } <thread> +%destructor { frame_free($$); } <frame> +%destructor { strbuf_free($$); } <strbuf> %start backtrace %glr-parser %error-verbose +%locations %% /* The grammar follows. */ @@ -75,28 +81,90 @@ threads : thread { $$ = $1; } | threads wsa thread { $$ = thread_add_sibling($1, $3); } ; -thread : keyword_thread wss digit_sequence wsa '(' keyword_thread wss digit_sequence wsa ')' ':' wsa frames { $$ = thread_new(); $$->frames = $13; } +thread : keyword_thread wss digit_sequence wsa '(' keyword_thread wss digit_sequence wsa ')' ':' wsa frames + { + $$ = thread_new(); + $$->frames = $13; + + if (sscanf($3->buf, "%d", &$$->number) != 1) + { + printf("Error while parsing thread number '%s'", $3->buf); + exit(5); + } + strbuf_free($3); + strbuf_free($8); + } ; frames : frame { $$ = $1; } | frames wsa frame { $$ = frame_add_sibling($1, $3); } ; -frame : frame_head wss function_call wsa keyword_at wss file_location wss variables %dprec 2 { $$ = frame_new(); } - | frame_head wss frame_address_in_function wss keyword_at wss file_location wss variables %dprec 3 { $$ = frame_new(); } - | frame_head wss frame_address_in_function wss keyword_from wss file_location wss variables %dprec 3 { $$ = frame_new(); } - | frame_head wss frame_address_in_function wss variables %dprec 1 { $$ = frame_new(); } - | frame_head wss keyword_sighandler wss variables { $$ = frame_new(); } -; - - -frame_head : '#' digit_sequence -; - -frame_address_in_function : hexadecimal_number wss keyword_in wss function_call -; - -file_location : file_name ':' digit_sequence +frame : frame_head wss function_call wsa keyword_at wss file_location wss variables %dprec 2 + { + $$ = frame_new(); + $$->number = $1; + $$->function = $3->buf; + strbuf_free_nobuf($3); + $$->sourcefile = $7->buf; + strbuf_free_nobuf($7); + } + | frame_head wss frame_address_in_function wss keyword_at wss file_location wss variables %dprec 3 + { + $$ = frame_new(); + $$->number = $1; + $$->function = $3->buf; + strbuf_free_nobuf($3); + $$->sourcefile = $7->buf; + strbuf_free_nobuf($7); + } + | frame_head wss frame_address_in_function wss keyword_from wss file_location wss variables %dprec 3 + { + $$ = frame_new(); + $$->number = $1; + $$->function = $3->buf; + strbuf_free_nobuf($3); + $$->sourcefile = $7->buf; + strbuf_free_nobuf($7); + } + | frame_head wss frame_address_in_function wss variables %dprec 1 + { + $$ = frame_new(); + $$->number = $1; + $$->function = $3->buf; + strbuf_free_nobuf($3); + } + | frame_head wss keyword_sighandler wss variables + { + $$ = frame_new(); + $$->number = $1; + } +; + + +frame_head : '#' digit_sequence + { + if (sscanf($2->buf, "%d", &$$) != 1) + { + printf("Error while parsing frame number '%s'.\n", $2->buf); + exit(5); + } + strbuf_free($2); + } +; + +frame_address_in_function : hexadecimal_number wss keyword_in wss function_call + { + strbuf_free($1); + $$ = $5; + } +; + +file_location : file_name ':' digit_sequence + { + $$ = $1; + strbuf_free($3); /* line number not needed for now */ + } | file_name ; @@ -129,19 +197,26 @@ function_call : function_name wsa function_args ; function_name : identifier - | '?' '?' { $$ = strbuf_new(); strbuf_append_str($$, "??"); } + | '?' '?' + { + $$ = strbuf_new(); + strbuf_append_str($$, "??"); + } ; 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 function_args_char ; -function_args_char : digit | nondigit | '{' | '}' | '<' | '>' - | '=' | '-' | '+' | '@' | ',' | '.' +function_args_char : digit | nondigit | '{' | '}' | '<' | '>' | '"' + | '=' | '-' | '+' | '@' | ',' | '.' | '[' | ']' | '/' ; file_name : file_name_char { $$ = strbuf_new(); strbuf_append_char($$, $1); } @@ -164,12 +239,25 @@ digit_sequence : digit { $$ = strbuf_new(); strbuf_append_char($$, $1); } | digit_sequence digit { $$ = strbuf_append_char($1, $2); } ; -hexadecimal_number : '0' 'x' hexadecimal_digit_sequence { $$ = strbuf_new(); strbuf_append_str($$, "0x"); strbuf_append_str($$, $3->buf); } - | '0' 'X' hexadecimal_digit_sequence { $$ = strbuf_new(); strbuf_append_str($$, "0X"); strbuf_append_str($$, $3->buf); } +hexadecimal_number : '0' 'x' hexadecimal_digit_sequence + { + $$ = $3; + strbuf_prepend_str($$, "0x"); + } + | '0' 'X' hexadecimal_digit_sequence + { + $$ = $3; + strbuf_prepend_str($$, "0X"); + } ; -hexadecimal_digit_sequence : hexadecimal_digit { $$ = strbuf_new(); strbuf_append_char($$, $1); } - | hexadecimal_digit_sequence hexadecimal_digit { $$ = strbuf_append_char($1, $2); } +hexadecimal_digit_sequence : hexadecimal_digit + { + $$ = strbuf_new(); + strbuf_append_char($$, $1); + } + | hexadecimal_digit_sequence hexadecimal_digit + { $$ = strbuf_append_char($1, $2); } ; hexadecimal_digit : digit @@ -233,6 +321,8 @@ int yylex() if (scanner_echo) putchar(c); + yylval.c = c; + /* Return a single char. */ return c; } diff --git a/src/Backtrace/strbuf.c b/src/Backtrace/strbuf.c index 8cdb482..c919354 100644 --- a/src/Backtrace/strbuf.c +++ b/src/Backtrace/strbuf.c @@ -44,31 +44,37 @@ struct strbuf *strbuf_new() return buf; } -void strbuf_free(struct strbuf *buf) +void strbuf_free(struct strbuf *strbuf) { - free(buf->buf); - free(buf); + free(strbuf->buf); + free(strbuf); } -void strbuf_clear(struct strbuf *buf) +void strbuf_free_nobuf(struct strbuf *strbuf) { - assert(buf->alloc > 0); - buf->len = 0; - buf->buf[0] = '\0'; + free(strbuf); +} + + +void strbuf_clear(struct strbuf *strbuf) +{ + assert(strbuf->alloc > 0); + strbuf->len = 0; + strbuf->buf[0] = '\0'; } /* Ensures that the buffer can be extended by num characters * without touching malloc/realloc. */ -static void strbuf_grow(struct strbuf *buf, int num) +static void strbuf_grow(struct strbuf *strbuf, int num) { - if (buf->len + num + 1 > buf->alloc) + if (strbuf->len + num + 1 > strbuf->alloc) { - while (buf->len + num + 1 > buf->alloc) - buf->alloc *= 2; /* huge grow = infinite loop */ + while (strbuf->len + num + 1 > strbuf->alloc) + strbuf->alloc *= 2; /* huge grow = infinite loop */ - buf->buf = realloc(buf->buf, buf->alloc); - if (!buf->buf) + strbuf->buf = realloc(strbuf->buf, strbuf->alloc); + if (!strbuf->buf) { puts("Error while allocating memory for string buffer."); exit(5); @@ -76,20 +82,29 @@ static void strbuf_grow(struct strbuf *buf, int num) } } -struct strbuf *strbuf_append_char(struct strbuf *buf, char c) +struct strbuf *strbuf_append_char(struct strbuf *strbuf, char c) { - strbuf_grow(buf, 1); - buf->buf[buf->len++] = c; - buf->buf[buf->len] = '\0'; - return buf; + strbuf_grow(strbuf, 1); + strbuf->buf[strbuf->len++] = c; + strbuf->buf[strbuf->len] = '\0'; + return strbuf; } -struct strbuf *strbuf_append_str(struct strbuf *buf, char *str) +struct strbuf *strbuf_append_str(struct strbuf *strbuf, char *str) { int len = strlen(str); - strbuf_grow(buf, len); - assert(buf->len + len < buf->alloc); - strcpy(buf->buf + buf->len, str); - buf->len += len; - return buf; + strbuf_grow(strbuf, len); + assert(strbuf->len + len < strbuf->alloc); + strcpy(strbuf->buf + strbuf->len, str); + strbuf->len += len; + return strbuf; +} + +struct strbuf *strbuf_prepend_str(struct strbuf *strbuf, char *str) +{ + int len = strlen(str); + strbuf_grow(strbuf, len); + assert(strbuf->len + len < strbuf->alloc); + memmove(strbuf->buf + len, strbuf->buf, strbuf->len + 1); + memcpy(strbuf->buf, str, len); } diff --git a/src/Backtrace/strbuf.h b/src/Backtrace/strbuf.h index 4375dd9..f2e4459 100644 --- a/src/Backtrace/strbuf.h +++ b/src/Backtrace/strbuf.h @@ -27,9 +27,12 @@ struct strbuf { }; extern struct strbuf *strbuf_new(); -extern void strbuf_free(struct strbuf *buf); -extern void strbuf_clear(struct strbuf *buf); -extern struct strbuf *strbuf_append_char(struct strbuf *buf, char c); -extern struct strbuf *strbuf_append_str(struct strbuf *buf, char *str); +extern void strbuf_free(struct strbuf *strbuf); +/* Releases strbuf, but not the internal buffer. */ +extern void strbuf_free_nobuf(struct strbuf *strbuf); +extern void strbuf_clear(struct strbuf *strbuf); +extern struct strbuf *strbuf_append_char(struct strbuf *strbuf, char c); +extern struct strbuf *strbuf_append_str(struct strbuf *strbuf, char *str); +extern struct strbuf *strbuf_prepend_str(struct strbuf *strbuf, char *str); #endif |
