summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2009-11-20 17:54:17 +0100
committerKarel Klic <kklic@redhat.com>2009-11-20 17:54:17 +0100
commitb8da7620a417ef835869da692db140b75e8b7a93 (patch)
tree9afa3edca4663fde9118550ca839b7021f4b0eb0
parent10ca6da1cc2d89ba5c45179d452720d916bc4698 (diff)
downloadabrt-b8da7620a417ef835869da692db140b75e8b7a93.tar.gz
abrt-b8da7620a417ef835869da692db140b75e8b7a93.tar.xz
abrt-b8da7620a417ef835869da692db140b75e8b7a93.zip
Backtrace parser improvements
-rw-r--r--src/Backtrace/backtrace.c35
-rw-r--r--src/Backtrace/backtrace.h8
-rw-r--r--src/Backtrace/parser.y138
-rw-r--r--src/Backtrace/strbuf.c63
-rw-r--r--src/Backtrace/strbuf.h11
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