diff options
author | Karel Klic <kklic@redhat.com> | 2009-11-11 19:08:50 +0100 |
---|---|---|
committer | Karel Klic <kklic@redhat.com> | 2009-11-11 19:08:50 +0100 |
commit | 179fcfcc6d9d0aa19c6e7f36ce9e8d453bb99793 (patch) | |
tree | 0101b65845f7fa91794f99766d8f7ef2c95620c4 /src | |
parent | 3a0b5daaaa268e1ac384a4d754fdd2e9a9608171 (diff) | |
download | abrt-179fcfcc6d9d0aa19c6e7f36ce9e8d453bb99793.tar.gz abrt-179fcfcc6d9d0aa19c6e7f36ce9e8d453bb99793.tar.xz abrt-179fcfcc6d9d0aa19c6e7f36ce9e8d453bb99793.zip |
Backtrace tool WORK-IN-PROGRESS
Diffstat (limited to 'src')
-rw-r--r-- | src/Backtrace/Makefile.am | 22 | ||||
-rwxr-xr-x | src/Backtrace/abrt-bz-downloader | 60 | ||||
-rw-r--r-- | src/Backtrace/backtrace.c | 138 | ||||
-rw-r--r-- | src/Backtrace/backtrace.h | 63 | ||||
-rw-r--r-- | src/Backtrace/fallback.c | 194 | ||||
-rw-r--r-- | src/Backtrace/fallback.h | 32 | ||||
-rw-r--r-- | src/Backtrace/main.c | 135 | ||||
-rw-r--r-- | src/Backtrace/parser.y | 272 | ||||
-rw-r--r-- | src/Backtrace/strbuf.c | 95 | ||||
-rw-r--r-- | src/Backtrace/strbuf.h | 35 | ||||
-rw-r--r-- | src/Makefile.am | 2 |
11 files changed, 1047 insertions, 1 deletions
diff --git a/src/Backtrace/Makefile.am b/src/Backtrace/Makefile.am new file mode 100644 index 00000000..e188c460 --- /dev/null +++ b/src/Backtrace/Makefile.am @@ -0,0 +1,22 @@ +bin_PROGRAMS = abrt-backtrace + +#BUILT_SOURCES = parser.h +#AM_YFLAGS = -d +AM_YFLAGS = --verbose + +abrt_backtrace_SOURCES = \ + main.c \ + backtrace.h backtrace.c \ + strbuf.h strbuf.c \ + fallback.h fallback.c \ + parser.y + +#abrt_backtrace_CPPFLAGS = \ +# -I$(srcdir)/../../inc \ +# -I$(srcdir)/../../lib/Utils + +#abrt_backtrace_LDADD = \ +# ../../lib/Utils/libABRTUtils.la + +#man_MANS = abrt-backtrace.1 +#EXTRA_DIST = $(man_MANS) diff --git a/src/Backtrace/abrt-bz-downloader b/src/Backtrace/abrt-bz-downloader new file mode 100755 index 00000000..44dc4e41 --- /dev/null +++ b/src/Backtrace/abrt-bz-downloader @@ -0,0 +1,60 @@ +#!/usr/bin/python +# -*- mode:python -*- + +from bugzilla import RHBugzilla +from optparse import OptionParser +import sys +import os.path + +parser = OptionParser(version="%prog 1.0") +parser.add_option("-u", "--user", dest="user", + help="Bugzilla user name (REQUIRED)", metavar="USERNAME") +parser.add_option("-p", "--password", dest="password", + help="Bugzilla password (REQUIRED)", metavar="PASSWORD") +parser.add_option("-b", "--bugzilla", dest="bugzilla", + help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL") +parser.add_option("-f", "--fields", + action="store_true", dest="fields", default=False, + help="Print possible bug fields and exit.") + +(options, args) = parser.parse_args() + +if not options.user or len(options.user) == 0: + parser.error("User name is required.\nTry {0} --help".format(sys.argv[0])) + +if not options.password or len(options.password) == 0: + parser.error("Password is required.\nTry {0} --help".format(sys.argv[0])) + +if not options.bugzilla or len(options.bugzilla) == 0: + options.bugzilla = "https://bugzilla.redhat.com/xmlrpc.cgi" + +bz = RHBugzilla() +bz.connect(options.bugzilla) +bz.login(options.user, options.password) + +if options.fields: + print bz.bugfields + exit(0) + +buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboard':'abrt_hash'}) + +print "{0} bugs found.".format(len(buginfos)) + +for buginfo in buginfos: + # Skip bugs with already downloaded backtraces. + filename = "{0}.bt".format(buginfo.bug_id) + if os.path.isfile(filename): + print "Skipping {0} (already exists).".format(filename) + continue + + # Get backtrace from bug and store it as a file. + bug = bz.getbug(buginfo.bug_id) + for attachment in bug.attachments: + if attachment['filename'] == 'backtrace': + data = bz.openattachment(attachment['id']) + f = open(filename, 'w') + f.write(data.read()) + f.close() + print "Attachment {0} downloaded.".format(filename) + +bz.logout() diff --git a/src/Backtrace/backtrace.c b/src/Backtrace/backtrace.c new file mode 100644 index 00000000..3777c0f4 --- /dev/null +++ b/src/Backtrace/backtrace.c @@ -0,0 +1,138 @@ +/* + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "backtrace.h" +#include <stdlib.h> + +struct frame *frame_new() +{ + struct frame *f = malloc(sizeof(struct frame)); + if (!f) + { + puts("Error while allocating memory for backtrace frame."); + exit(5); + } + + f->function = NULL; + f->args = NULL; + f->number = 0; + f->binfile = NULL; + f->sourcefile = NULL; + f->crash = false; + f->next = NULL; + return f; +} + +void frame_free(struct frame *f) +{ + if (f->function) + free(f->function); + if (f->args) + free(f->args); + if (f->binfile) + free(f->binfile); + if (f->sourcefile) + free(f->sourcefile); + free(f); +} + +struct frame *frame_add_sibling(struct frame *a, struct frame *b) +{ + struct frame *aa = a; + while (aa->next) + aa = aa->next; + + aa->next = b; + return a; +} + +struct thread *thread_new() +{ + struct thread *t = malloc(sizeof(struct thread)); + if (!t) + { + puts("Error while allocating memory for backtrace thread."); + exit(5); + } + + t->number = 0; + t->frames = NULL; + t->next = NULL; +} + +void thread_free(struct thread *t) +{ + while (t->frames) + { + struct frame *rm = t->frames; + t->frames = rm->next; + frame_free(rm); + } + + free(t); +} + +struct thread *thread_add_sibling(struct thread *a, struct thread *b) +{ + struct thread *aa = a; + while (aa->next) + aa = aa->next; + + aa->next = b; + return a; +} + +struct backtrace *backtrace_new() +{ + struct backtrace *bt = malloc(sizeof(struct backtrace)); + if (!bt) + { + puts("Error while allocating memory for backtrace."); + exit(5); + } + + bt->threads = NULL; +} + +void backtrace_free(struct backtrace *bt) +{ + while (bt->threads) + { + struct thread *rm = bt->threads; + bt->threads = rm->next; + thread_free(rm); + } + + free(bt); +} + +static int backtrace_get_thread_count(struct backtrace *bt) +{ + struct thread *t = bt->threads; + int count = 0; + while (t) + { + t = t->next; + ++count; + } + return count; +} + +void backtrace_print_tree(struct backtrace *bt) +{ + printf("Thread count: %d\n", backtrace_get_thread_count(bt)); +} diff --git a/src/Backtrace/backtrace.h b/src/Backtrace/backtrace.h new file mode 100644 index 00000000..f42cfcd8 --- /dev/null +++ b/src/Backtrace/backtrace.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BACKTRACE_H +#define BACKTRACE_H + +#include <stdio.h> +#include <stdbool.h> + +struct frame +{ + char *function; + char *args; + int number; + char *binfile; + char *sourcefile; + bool crash; + struct frame *next; +}; + +struct thread +{ + int number; + struct frame *frames; + struct thread *next; +}; + +struct backtrace +{ + struct thread *threads; +}; + +extern struct frame *frame_new(); +extern void frame_free(struct frame *f); +extern struct frame *frame_add_sibling(struct frame *a, struct frame *b); + +extern struct thread *thread_new(); +extern void thread_free(struct thread *t); +extern struct thread *thread_add_sibling(struct thread *a, struct thread *b); + +extern struct backtrace *backtrace_new(); +extern void backtrace_free(struct backtrace *bt); +/* Prints how internal backtrace representation looks to stdout. */ +extern void backtrace_print_tree(struct backtrace *bt); + +/* Defined in parser.y. */ +extern struct backtrace *do_parse(FILE *input, bool debug_parser, bool debug_scanner); + +#endif diff --git a/src/Backtrace/fallback.c b/src/Backtrace/fallback.c new file mode 100644 index 00000000..04425337 --- /dev/null +++ b/src/Backtrace/fallback.c @@ -0,0 +1,194 @@ +/* + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fallback.h" +#include <stdlib.h> +#include <stdbool.h> + +/* Too large files are trimmed. */ +#define FILE_SIZE_LIMIT 10000000 /* ~ 10 MB */ + +struct header +{ + struct strbuf *text; + struct header *next; +}; + +static struct header *header_new() +{ + struct header *head = malloc(sizeof(struct header)); + if (!head) + { + puts("Error while allocating memory for backtrace header."); + exit(5); + } + head->text = NULL; + head->next = NULL; + return head; +} + +/* Recursively frees siblings. */ +static void header_free(struct header *head) +{ + strbuf_free(head->text); + if (head->next) + header_free(head->next); + free(head); +} + +/* Inserts new header to array if it is not already there. */ +static void header_set_insert(struct header *cur, struct strbuf *new) +{ + /* Duplicate found case. */ + if (strcmp(cur->text->buf, new->buf) == 0) + return; + + /* Last item case, insert new header here. */ + if (cur->next == NULL) + { + cur->next = header_new(); + cur->next->text = new; + return; + } + + /* Move to next item in array case. */ + header_set_insert(cur->next, new); +} + +struct strbuf *independent_backtrace(FILE *fp) +{ + 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; + bool in_header = false; + bool in_digit = false; + bool has_at = false; + bool has_filename = false; + bool has_bracket = false; + struct header *headers = NULL; + + const char *bk = contents; + while (*bk) + { + if (bk[0] == '#' + && bk[1] >= '0' && bk[1] <= '7' + && bk[2] == ' ' /* take only #0...#7 (8 last stack frames) */ + && !in_quote) + { + if (in_header && !has_filename) + strbuf_clear(header); + in_header = true; + } + + if (!in_header) + { + ++bk; + continue; + } + + if (isdigit(*bk) && !in_quote && !has_at) + in_digit = true; + else if (bk[0] == '\\' && bk[1] == '\"') + bk++; + else if (*bk == '\"') + in_quote = in_quote == true ? false : true; + else if (*bk == '(' && !in_quote) + { + in_bracket = true; + in_digit = false; + strbuf_append_char(header, '('); + } + else if (*bk == ')' && !in_quote) + { + in_bracket = false; + has_bracket = true; + in_digit = false; + strbuf_append_char(header, '('); + } + else if (*bk == '\n' && has_filename) + { + if (headers == NULL) + { + headers = header_new(); + headers->text = header; + } + else + header_set_insert(headers, header); + + header = strbuf_new(); + in_bracket = false; + in_quote = false; + in_header = false; + in_digit = false; + has_at = false; + has_filename = false; + has_bracket = false; + } + else if (*bk == ',' && !in_quote) + in_digit = false; + else if (isspace(*bk) && !in_quote) + in_digit = false; + else if (bk[0] == 'a' && bk[1] == 't' && has_bracket && !in_quote) + { + has_at = true; + strbuf_append_char(header, 'a'); + } + else if (bk[0] == ':' && has_at && isdigit(bk[1]) && !in_quote) + has_filename = true; + else if (in_header && !in_digit && !in_quote && !in_bracket) + strbuf_append_char(header, *bk); + + bk++; + } + + strbuf_free(header); + free(contents); + + struct strbuf *result = strbuf_new(); + struct header *loop = headers; + while (loop) + { + strbuf_append_str(result, loop->text->buf); + strbuf_append_char(result, '\n'); + loop = loop->next; + } + + header_free(headers); /* recursive */ + return result; +} diff --git a/src/Backtrace/fallback.h b/src/Backtrace/fallback.h new file mode 100644 index 00000000..9c31fecf --- /dev/null +++ b/src/Backtrace/fallback.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef FALLBACK_H +#define FALLBACK_H + +#include "strbuf.h" +#include <stdio.h> + +/* + * Reads the input file and calculates independent backtrace from it. + * @returns + * The independent backtrace. Caller is responsible for calling + * strbuf_free() on it. + */ +extern struct strbuf *independent_backtrace(FILE *fp); + +#endif diff --git a/src/Backtrace/main.c b/src/Backtrace/main.c new file mode 100644 index 00000000..d4c860f1 --- /dev/null +++ b/src/Backtrace/main.c @@ -0,0 +1,135 @@ +/* + main.cpp - parses command line arguments + + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <argp.h> +#include <stdlib.h> +#include "config.h" +#include "backtrace.h" +#include "fallback.h" + +const char *argp_program_version = "abrt-backtrace " VERSION; +const char *argp_program_bug_address = "<crash-catcher@lists.fedorahosted.org>"; + +static char doc[] = "abrt-backtrace -- backtrace analyzer"; + +/* A description of the arguments we accept. */ +static char args_doc[] = "FILE"; + +static struct argp_option options[] = { + {"independent" , 'i', 0, 0, "Prints independent backtrace (fallback)" }, + {"tree" , 't', 0, 0, "Prints backtrace analysis tree"}, + {"verbose" , 'v', 0, 0, "Prints debug information"}, + {"debug-parser" , 'p', 0, 0, "Prints parser debug information"}, + {"debug-scanner", 's', 0, 0, "Prints scanner debug information"}, + { 0 } +}; + +struct arguments +{ + bool independent; + bool tree; + bool verbose; + bool debug_parser; + bool debug_scanner; + char *filename; +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = (struct arguments*)state->input; + + switch (key) + { + case 'i': arguments->independent = true; break; + case 't': arguments->tree = true; break; + case 'v': arguments->verbose = true; break; + case 'p': arguments->debug_parser = true; break; + case 's': arguments->debug_scanner = true; break; + + case ARGP_KEY_ARG: + if (arguments->filename) + { + /* Too many arguments. */ + argp_usage(state); + exit(2); + } + arguments->filename = arg; + break; + + case ARGP_KEY_END: + if (!arguments->filename) + { + /* Not enough arguments. */ + argp_usage(state); + exit(1); + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +/* Our argp parser. */ +static struct argp argp = { options, parse_opt, args_doc, doc }; + + +int main(int argc, char **argv) +{ + /* Set options default values and parse program command line. */ + struct arguments arguments; + arguments.independent = false; + arguments.verbose = false; + arguments.tree = false; + arguments.debug_parser = false; + arguments.debug_scanner = false; + arguments.filename = 0; + argp_parse (&argp, argc, argv, 0, 0, &arguments); + + /* Open input file and parse it. */ + FILE *fp = fopen(arguments.filename, "r"); + if (!fp) + { + printf("Unable to open '%s'.\n", arguments.filename); + exit(3); + } + + if (arguments.independent) + { + struct strbuf *ibt = independent_backtrace(fp); + fclose(fp); + puts(ibt->buf); + strbuf_free(ibt); + return; + } + + struct backtrace *bt; + bt = do_parse(fp, arguments.debug_parser, arguments.debug_scanner); + fclose(fp); + + if (arguments.tree) + backtrace_print_tree(bt); + + backtrace_free(bt); + return 0; +} diff --git a/src/Backtrace/parser.y b/src/Backtrace/parser.y new file mode 100644 index 00000000..9b9caba0 --- /dev/null +++ b/src/Backtrace/parser.y @@ -0,0 +1,272 @@ +%{ /* -*- mode: yacc -*- +/* + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "backtrace.h" +#include "strbuf.h" + +struct backtrace *g_backtrace; + +#define YYDEBUG 1 +#define YYMAXDEPTH 10000000 +void yyerror(char const *s) +{ + fprintf (stderr, "\nParser error: %s\n", s); +} + +%} + +/* This defines the type of yylval */ +%union { + struct backtrace *backtrace; + struct thread *thread; + struct frame *frame; + char *str; + int num; + char c; + + struct strbuf *strbuf; +} + +/* Bison declarations. */ +%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 <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' '\\' '!' '*' '%' '|' '^' '&' '$' + +%start backtrace +%glr-parser +%error-verbose + +%% /* The grammar follows. */ + +backtrace : /* empty */ { $$ = g_backtrace = backtrace_new(); } + | ignoredpart_backtrace wsa { $$ = g_backtrace = $1; } +; + +/**/ +ignoredpart_backtrace : threads { $$ = backtrace_new(); $$->threads = $1; } + | anychar ignoredpart_backtrace { $$ = $2; } +; + +anychar : ws | digit | nondigit | '(' | ')' | '+' | '-' | '#' | '=' | ':' | ';' + | '/' | '.' | '[' | ']' | '?' | '\'' | '`' | ',' | '<' | '>' | '"' +; + +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; } +; + +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 + | file_name +; + +variables : variables_char + | variables variables_char + | variables variables_wss variables_char + | variables '\n' variables_char_no_framestart + | variables variables_wss '\n' variables_wss variables_char_no_framestart + | variables variables_wss '\n' variables_char_no_framestart + | variables '\n' variables_wss variables_char_no_framestart +; + +variables_ws : '\t' | ' ' +; + +variables_wss : variables_ws + | variables_wss variables_ws +; + + /* We hope variables in frame never contain # character. */ +variables_char : '#' | variables_char_no_framestart +; + +variables_char_no_framestart : digit | nondigit | '(' | ')' | '+' | '-' | '<' + | '>' | '"' | '/' | '.' | '[' | ']' | '?' | '\'' + | '`' | ',' | '=' | '{' | '}' | '^' | '&' | '$' + | ':' | ';' | '\\' | '!' | '@' | '*' | '%' | '|' + +function_call : function_name wsa function_args +; + +function_name : identifier + | '?' '?' { $$ = strbuf_new(); strbuf_append_str($$, "??"); } +; + +function_args : '(' wsa ')' + | '(' wsa function_args_sequence wsa ')' +; + +function_args_sequence : function_args_char + | function_args_sequence wsa function_args_char +; + +function_args_char : digit | nondigit | '{' | '}' | '<' | '>' + | '=' | '-' | '+' | '@' | ',' | '.' +; + +file_name : file_name_char { $$ = strbuf_new(); strbuf_append_char($$, $1); } + | file_name file_name_char { $$ = strbuf_append_char($1, $2); } +; + +file_name_char : digit | nondigit | '-' | '+' | '/' | '.' +; + + /* Mangled function name. */ +identifier : nondigit { $$ = strbuf_new(); strbuf_append_char($$, $1); } + | identifier nondigit { $$ = strbuf_append_char($1, $2); } + | identifier digit { $$ = strbuf_append_char($1, $2); } + | identifier '@' { $$ = strbuf_append_char($1, $2); } + | identifier '.' { $$ = strbuf_append_char($1, $2); } + | identifier ':' { $$ = strbuf_append_char($1, $2); } +; + +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_digit_sequence : hexadecimal_digit { $$ = strbuf_new(); strbuf_append_char($$, $1); } + | hexadecimal_digit_sequence hexadecimal_digit { $$ = strbuf_append_char($1, $2); } +; + +hexadecimal_digit : digit + | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' + | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' +; + +digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' +; + +nondigit : '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' + | '_' +; + + /* whitespace */ +ws : '\t' | ' ' | '\n' | '\r' +; + + /* whitespace sequence */ +wss : ws + | wss ws +; + +/* whitespace sequence allowed */ +wsa : + | wss +; + +keyword_in : 'i' 'n' +; + +keyword_at : 'a' 't' +; + +keyword_from : 'f' 'r' 'o' 'm' +; + +keyword_thread: 'T' 'h' 'r' 'e' 'a' 'd' +; + +keyword_sighandler: '<' 's' 'i' 'g' 'n' 'a' 'l' ' ' 'h' 'a' 'n' 'd' 'l' 'e' 'r' ' ' 'c' 'a' 'l' 'l' 'e' 'd' '>' +; + +%% + +static bool scanner_echo = false; +static FILE *yyin; + +int yylex() +{ + int c = fgetc(yyin); + if (c == EOF) + return 0; + + /* Debug output. */ + if (scanner_echo) + putchar(c); + + /* Return a single char. */ + return c; +} + +/* This is the function that is actually called from outside. + * @returns + * Backtrace structure. Caller is responsible for calling + * backtrace_free() on this. + */ +struct backtrace *do_parse(FILE *input, bool debug_parser, bool debug_scanner) +{ + /* Prepare for running parser. */ + g_backtrace = 0; + yyin = input; +#if YYDEBUG == 1 + if (debug_parser) + yydebug = 1; +#endif + scanner_echo = debug_scanner; + + /* Parse. */ + int failure = yyparse(); + + /* Separate debugging output. */ + if (scanner_echo) + putchar('\n'); + + if (failure) + { + if (g_backtrace) + backtrace_free(g_backtrace); + puts("Error while parsing backtrace."); + exit(6); + } + + return g_backtrace; +} diff --git a/src/Backtrace/strbuf.c b/src/Backtrace/strbuf.c new file mode 100644 index 00000000..8cdb482e --- /dev/null +++ b/src/Backtrace/strbuf.c @@ -0,0 +1,95 @@ +/* + strbuf.c - string buffer implementation + + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "strbuf.h" +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +struct strbuf *strbuf_new() +{ + struct strbuf *buf = malloc(sizeof(struct strbuf)); + if (!buf) + { + puts("Error while allocating memory for string buffer."); + exit(5); + } + + buf->alloc = 8; + buf->len = 0; + buf->buf = malloc(buf->alloc); + if (!buf->buf) + { + puts("Error while allocating memory for string buffer."); + exit(5); + } + + buf->buf[buf->len] = '\0'; + return buf; +} + +void strbuf_free(struct strbuf *buf) +{ + free(buf->buf); + free(buf); +} + +void strbuf_clear(struct strbuf *buf) +{ + assert(buf->alloc > 0); + buf->len = 0; + buf->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) +{ + if (buf->len + num + 1 > buf->alloc) + { + while (buf->len + num + 1 > buf->alloc) + buf->alloc *= 2; /* huge grow = infinite loop */ + + buf->buf = realloc(buf->buf, buf->alloc); + if (!buf->buf) + { + puts("Error while allocating memory for string buffer."); + exit(5); + } + } +} + +struct strbuf *strbuf_append_char(struct strbuf *buf, char c) +{ + strbuf_grow(buf, 1); + buf->buf[buf->len++] = c; + buf->buf[buf->len] = '\0'; + return buf; +} + +struct strbuf *strbuf_append_str(struct strbuf *buf, 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; +} diff --git a/src/Backtrace/strbuf.h b/src/Backtrace/strbuf.h new file mode 100644 index 00000000..4375dd90 --- /dev/null +++ b/src/Backtrace/strbuf.h @@ -0,0 +1,35 @@ +/* + strbuf.h - string buffer + + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef STRBUF_H +#define STRBUF_H + +struct strbuf { + int alloc; + int len; + char *buf; +}; + +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); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 2eb6c79d..dbd7ebbc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1 +1 @@ -SUBDIRS = Hooks Daemon Applet Gui CLI +SUBDIRS = Hooks Daemon Applet Gui CLI Backtrace |