diff options
Diffstat (limited to 'src/btparser/frame.c')
-rw-r--r-- | src/btparser/frame.c | 1027 |
1 files changed, 0 insertions, 1027 deletions
diff --git a/src/btparser/frame.c b/src/btparser/frame.c deleted file mode 100644 index 2bfae070..00000000 --- a/src/btparser/frame.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* - frame.c - - Copyright (C) 2010 Red Hat, 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 "frame.h" -#include "strbuf.h" -#include "utils.h" -#include "location.h" -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -struct btp_frame * -btp_frame_new() -{ - struct btp_frame *frame = btp_malloc(sizeof(struct btp_frame)); - btp_frame_init(frame); - return frame; -} - -void -btp_frame_init(struct btp_frame *frame) -{ - frame->function_name = NULL; - frame->function_type = NULL; - frame->number = 0; - frame->source_file = NULL; - frame->source_line = -1; - frame->signal_handler_called = false; - frame->address = -1; - frame->next = NULL; -} - -void -btp_frame_free(struct btp_frame *frame) -{ - if (!frame) - return; - free(frame->function_name); - free(frame->function_type); - free(frame->source_file); - free(frame); -} - -struct btp_frame * -btp_frame_dup(struct btp_frame *frame, bool siblings) -{ - struct btp_frame *result = btp_frame_new(); - memcpy(result, frame, sizeof(struct btp_frame)); - - /* Handle siblings. */ - if (siblings) - { - if (result->next) - result->next = btp_frame_dup(result->next, true); - } - else - result->next = NULL; /* Do not copy that. */ - - /* Duplicate all strings if the copy is not shallow. */ - if (result->function_name) - result->function_name = btp_strdup(result->function_name); - if (result->function_type) - result->function_type = btp_strdup(result->function_type); - if (result->source_file) - result->source_file = btp_strdup(result->source_file); - - return result; -} - -bool -btp_frame_calls_func(struct btp_frame *frame, - const char *function_name) -{ - return frame->function_name && - 0 == strcmp(frame->function_name, function_name); -} - -bool -btp_frame_calls_func_in_file(struct btp_frame *frame, - const char *function_name, - const char *source_file) -{ - return frame->function_name && - 0 == strcmp(frame->function_name, function_name) && - frame->source_file && - NULL != strstr(frame->source_file, source_file); -} - -bool -btp_frame_calls_func_in_file2(struct btp_frame *frame, - const char *function_name, - const char *source_file0, - const char *source_file1) -{ - return frame->function_name && - 0 == strcmp(frame->function_name, function_name) && - frame->source_file && - (NULL != strstr(frame->source_file, source_file0) || - NULL != strstr(frame->source_file, source_file1)); -} - -bool -btp_frame_calls_func_in_file3(struct btp_frame *frame, - const char *function_name, - const char *source_file0, - const char *source_file1, - const char *source_file2) -{ - return frame->function_name && - 0 == strcmp(frame->function_name, function_name) && - frame->source_file && - (NULL != strstr(frame->source_file, source_file0) || - NULL != strstr(frame->source_file, source_file1) || - NULL != strstr(frame->source_file, source_file2)); -} - -bool -btp_frame_calls_func_in_file4(struct btp_frame *frame, - const char *function_name, - const char *source_file0, - const char *source_file1, - const char *source_file2, - const char *source_file3) -{ - return frame->function_name && - 0 == strcmp(frame->function_name, function_name) && - frame->source_file && - (NULL != strstr(frame->source_file, source_file0) || - NULL != strstr(frame->source_file, source_file1) || - NULL != strstr(frame->source_file, source_file2) || - NULL != strstr(frame->source_file, source_file3)); -} - -int -btp_frame_cmp(struct btp_frame *f1, - struct btp_frame *f2, - bool compare_number) -{ - /* Singnal handler. */ - if (f1->signal_handler_called) - { - if (!f2->signal_handler_called) - return 1; - - /* Both contain signal handler called. */ - return 0; - } - else - { - if (f2->signal_handler_called) - return -1; - /* No signal handler called, continue. */ - } - - /* Function. */ - int function_name = btp_strcmp0(f1->function_name, f2->function_name); - if (function_name != 0) - return function_name; - int function_type = btp_strcmp0(f1->function_type, f2->function_type); - if (function_type != 0) - return function_type; - - /* Sourcefile. */ - int source_file = btp_strcmp0(f1->source_file, f2->source_file); - if (source_file != 0) - return source_file; - - /* Sourceline. */ - int source_line = f1->source_line - f2->source_line; - if (source_line != 0) - return source_line; - - /* Frame number. */ - if (compare_number) - { - int number = f1->number - f2->number; - if (number != 0) - return number; - } - - return 0; -} - -void -btp_frame_add_sibling(struct btp_frame *a, struct btp_frame *b) -{ - struct btp_frame *aa = a; - while (aa->next) - aa = aa->next; - - aa->next = b; -} - -void -btp_frame_append_to_str(struct btp_frame *frame, - struct strbuf *str, - bool verbose) -{ - if (verbose) - strbuf_append_strf(str, " #%d", frame->number); - else - strbuf_append_str(str, " "); - - if (frame->function_type) - strbuf_append_strf(str, " %s", frame->function_type); - if (frame->function_name) - strbuf_append_strf(str, " %s", frame->function_name); - if (verbose && frame->source_file) - { - if (frame->function_name) - strbuf_append_str(str, " at"); - strbuf_append_strf(str, " %s", frame->source_file); - } - - if (frame->signal_handler_called) - strbuf_append_str(str, " <signal handler called>"); - - strbuf_append_str(str, "\n"); -} - -/** - * Find string a or b in input, whatever comes first. - * If no string is found, return the \0 character at the end of input. - */ -static char * -findfirstabnul(char *input, const char *a, const char *b) -{ - size_t alen = strlen(a); - size_t blen = strlen(b); - char *p = input; - while (*p) - { - if (strncmp(p, a, alen) == 0) - return p; - if (strncmp(p, b, blen) == 0) - return p; - ++p; - } - return p; -} - -struct btp_frame * -btp_frame_parse(char **input, - struct btp_location *location) -{ - char *local_input = *input; - struct btp_frame *header = btp_frame_parse_header(input, location); - if (!header) - return NULL; - - /* Skip the variables section for now. */ - /* Todo: speedup by implementing strstrnul. */ - local_input = findfirstabnul(local_input, "\n#", "\nThread"); - if (*local_input != '\0') - ++local_input; /* ++ skips the newline */ - - if (btp_debug_parser) - { - printf("frame #%u %s\n", - header->number, - header->function_name ? header->function_name : "signal handler called"); - } - - *input = local_input; - return header; -} - -int -btp_frame_parse_frame_start(char **input, unsigned *number) -{ - char *local_input = *input; - - /* Read the hash sign. */ - if (!btp_skip_char(&local_input, '#')) - return 0; - int count = 1; - - /* Read the frame position. */ - int digits = btp_parse_unsigned_integer(&local_input, number); - count += digits; - if (0 == digits) - return 0; - - /* Read all the spaces after the positon. */ - int spaces = btp_skip_char_sequence(&local_input, ' '); - count += spaces; - if (0 == spaces) - return 0; - - *input = local_input; - return count; -} - -int -btp_frame_parseadd_operator(char **input, struct strbuf *target) -{ - char *local_input = *input; - if (0 == btp_skip_string(&local_input, "operator")) - return 0; - -#define OP(x) \ - if (0 < btp_skip_string(&local_input, x)) \ - { \ - strbuf_append_str(target, "operator"); \ - strbuf_append_str(target, x); \ - int length = local_input - *input; \ - *input = local_input; \ - return length; \ - } - - OP(">>=")OP(">>")OP(">=")OP(">"); - OP("<<=")OP("<<")OP("<=")OP("<"); - OP("->*")OP("->")OP("-"); - OP("==")OP("="); - OP("&&")OP("&=")OP("&"); - OP("||")OP("|=")OP("|"); - OP("++")OP("+=")OP("+"); - OP("--")OP("-=")OP("-"); - OP("/=")OP("/"); - OP("*=")OP("*"); - OP("%=")OP("%"); - OP("!=")OP("!"); - OP("~"); - OP("()"); - OP("[]"); - OP(","); - OP("^=")OP("^"); - OP(" new[]")OP(" new"); - OP(" delete[]")OP(" delete"); - /* User defined operators are not parsed. - Should they be? */ -#undef OP - return 0; -} - -#define FUNCTION_NAME_CHARS BTP_alnum "@.:=!*+-[]~&/%^|,_" - -int -btp_frame_parse_function_name_chunk(char **input, - bool space_allowed, - char **target) -{ - char *local_input = *input; - struct strbuf *buf = strbuf_new(); - while (*local_input) - { - if (0 < btp_frame_parseadd_operator(&local_input, buf)) - { - /* Space is allowed after operator even when it - is not normally allowed. */ - if (btp_skip_char(&local_input, ' ')) - { - /* ...but if ( follows, it is not allowed. */ - if (btp_skip_char(&local_input, '(')) - { - /* Return back both the space and (. */ - local_input -= 2; - } - else - strbuf_append_char(buf, ' '); - } - } - - if (strchr(FUNCTION_NAME_CHARS, *local_input) == NULL) - { - if (!space_allowed || strchr(" ", *local_input) == NULL) - break; - } - - strbuf_append_char(buf, *local_input); - ++local_input; - } - - if (buf->len == 0) - { - strbuf_free(buf); - return 0; - } - - *target = strbuf_free_nobuf(buf); - int total_char_count = local_input - *input; - *input = local_input; - return total_char_count; -} - -int -btp_frame_parse_function_name_braces(char **input, char **target) -{ - char *local_input = *input; - if (!btp_skip_char(&local_input, '(')) - return 0; - - struct strbuf *buf = strbuf_new(); - strbuf_append_char(buf, '('); - while (true) - { - char *namechunk = NULL; - if (0 < btp_frame_parse_function_name_chunk(&local_input, true, &namechunk) || - 0 < btp_frame_parse_function_name_braces(&local_input, &namechunk) || - 0 < btp_frame_parse_function_name_template(&local_input, &namechunk)) - { - strbuf_append_str(buf, namechunk); - free(namechunk); - } - else - break; - } - - if (!btp_skip_char(&local_input, ')')) - { - strbuf_free(buf); - return 0; - } - - strbuf_append_char(buf, ')'); - *target = strbuf_free_nobuf(buf); - int total_char_count = local_input - *input; - *input = local_input; - return total_char_count; -} - -int -btp_frame_parse_function_name_template(char **input, char **target) -{ - char *local_input = *input; - if (!btp_skip_char(&local_input, '<')) - return 0; - - struct strbuf *buf = strbuf_new(); - strbuf_append_char(buf, '<'); - while (true) - { - char *namechunk = NULL; - if (0 < btp_frame_parse_function_name_chunk(&local_input, true, &namechunk) || - 0 < btp_frame_parse_function_name_braces(&local_input, &namechunk) || - 0 < btp_frame_parse_function_name_template(&local_input, &namechunk)) - { - strbuf_append_str(buf, namechunk); - free(namechunk); - } - else - break; - } - - if (!btp_skip_char(&local_input, '>')) - { - strbuf_free(buf); - return 0; - } - - strbuf_append_char(buf, '>'); - *target = strbuf_free_nobuf(buf); - int total_char_count = local_input - *input; - *input = local_input; - return total_char_count; -} - -bool -btp_frame_parse_function_name(char **input, - char **function_name, - char **function_type, - struct btp_location *location) -{ - /* Handle unknown function name, represended by double question - mark. */ - if (btp_parse_string(input, "??", function_name)) - { - *function_type = NULL; - location->column += 2; - return true; - } - - char *local_input = *input; - /* Up to three parts of function name. */ - struct strbuf *buf0 = strbuf_new(), *buf1 = NULL; - - /* First character: - '~' for destructor - '*' for ???? - '_a-zA-Z' for mangled/nonmangled function name - '(' to start "(anonymous namespace)::" or something - */ - char first; - char *namechunk; - if (btp_parse_char_limited(&local_input, "~*_" BTP_alpha, &first)) - { - /* If it's a start of 'o'perator, put the 'o' back! */ - if (first == 'o') - --local_input; - else - { - strbuf_append_char(buf0, first); - ++location->column; - } - } - else - { - int chars = btp_frame_parse_function_name_braces(&local_input, - &namechunk); - if (0 < chars) - { - strbuf_append_str(buf0, namechunk); - free(namechunk); - location->column += chars; - } - else - { - location->message = "Expected function name."; - strbuf_free(buf0); - return false; - } - } - - /* The rest consists of function name, braces, templates...*/ - while (true) - { - char *namechunk = NULL; - int chars = btp_frame_parse_function_name_chunk(&local_input, - false, - &namechunk); - - if (0 == chars) - { - chars = btp_frame_parse_function_name_braces(&local_input, - &namechunk); - } - - if (0 == chars) - { - chars = btp_frame_parse_function_name_template(&local_input, - &namechunk); - } - - if (0 == chars) - break; - - strbuf_append_str(buf0, namechunk); - free(namechunk); - location->column += chars; - } - - /* Function name MUST be ended by empty space. */ - char space; - if (!btp_parse_char_limited(&local_input, BTP_space, &space)) - { - strbuf_free(buf0); - location->message = "Space or newline expected after function name."; - return false; - } - - /* Some C++ function names and function types might contain suffix - " const". */ - int chars = btp_skip_string(&local_input, "const"); - if (0 < chars) - { - strbuf_append_char(buf0, space); - btp_location_eat_char(location, space); - strbuf_append_str(buf0, "const"); - location->column += chars; - - /* Check the empty space after function name again.*/ - if (!btp_parse_char_limited(&local_input, BTP_space, &space)) - { - /* Function name MUST be ended by empty space. */ - strbuf_free(buf0); - location->message = "Space or newline expected after function name."; - return false; - } - } - - /* Maybe the first series was just a type of the function, and now - the real function follows. Now, we know it must not start with - '(', nor with '<'. */ - chars = btp_frame_parse_function_name_chunk(&local_input, - false, - &namechunk); - if (0 < chars) - { - /* Eat the space separator first. */ - btp_location_eat_char(location, space); - - buf1 = strbuf_new(); - strbuf_append_str(buf1, namechunk); - free(namechunk); - location->column += chars; - - /* The rest consists of a function name parts, braces, templates...*/ - while (true) - { - char *namechunk = NULL; - chars = btp_frame_parse_function_name_chunk(&local_input, - false, - &namechunk); - if (0 == chars) - { - chars = btp_frame_parse_function_name_braces(&local_input, - &namechunk); - } - if (0 == chars) - { - chars = btp_frame_parse_function_name_template(&local_input, - &namechunk); - } - if (0 == chars) - break; - - strbuf_append_str(buf1, namechunk); - free(namechunk); - location->column += chars; - } - - /* Function name MUST be ended by empty space. */ - if (!btp_parse_char_limited(&local_input, BTP_space, &space)) - { - strbuf_free(buf0); - strbuf_free(buf1); - location->message = "Space or newline expected after function name."; - return false; - } - } - - /* Again, some C++ function names might contain suffix " const" */ - chars = btp_skip_string(&local_input, "const"); - if (0 < chars) - { - struct strbuf *buf = buf1 ? buf1 : buf0; - strbuf_append_char(buf, space); - btp_location_eat_char(location, space); - strbuf_append_str(buf, "const"); - location->column += chars; - - /* Check the empty space after function name again.*/ - if (!btp_skip_char_limited(&local_input, BTP_space)) - { - /* Function name MUST be ended by empty space. */ - strbuf_free(buf0); - strbuf_free(buf1); - location->message = "Space or newline expected after function name."; - return false; - } - } - - /* Return back to the empty space. */ - --local_input; - - if (buf1) - { - *function_name = strbuf_free_nobuf(buf1); - *function_type = strbuf_free_nobuf(buf0); - } - else - { - *function_name = strbuf_free_nobuf(buf0); - *function_type = NULL; - } - - *input = local_input; - return true; -} - -bool -btp_frame_skip_function_args(char **input, struct btp_location *location) -{ - char *local_input = *input; - if (!btp_skip_char(&local_input, '(')) - { - location->message = "Expected '(' to start function argument list."; - return false; - } - location->column += 1; - - int depth = 0; - bool string = false; - bool escape = false; - do - { - if (string) - { - if (escape) - escape = false; - else if (*local_input == '\\') - escape = true; - else if (*local_input == '"') - string = false; - } - else - { - if (*local_input == '"') - string = true; - else if (*local_input == '(') - ++depth; - else if (*local_input == ')') - { - if (depth > 0) - --depth; - else - break; - } - } - btp_location_eat_char(location, *local_input); - ++local_input; - } - while (*local_input); - - if (depth != 0 || string || escape) - { - location->message = "Unbalanced function parameter list."; - return false; - } - - if (!btp_skip_char(&local_input, ')')) - { - location->message = "Expected ')' to close the function parameter list."; - return false; - } - location->column += 1; - - *input = local_input; - return true; -} - -bool -btp_frame_parse_function_call(char **input, - char **function_name, - char **function_type, - struct btp_location *location) -{ - char *local_input = *input; - char *name = NULL, *type = NULL; - if (!btp_frame_parse_function_name(&local_input, - &name, - &type, - location)) - { - /* The location message is set by the function returning - * false, no need to update it here. */ - return false; - } - - int line, column; - if (0 == btp_skip_char_span_location(&local_input, - " \n", - &line, - &column)) - { - free(name); - free(type); - location->message = "Expected a space or newline after the function name."; - return false; - } - btp_location_add(location, line, column); - - if (!btp_frame_skip_function_args(&local_input, location)) - { - free(name); - free(type); - /* The location message is set by the function returning - * false, no need to update it here. */ - return false; - } - - *function_name = name; - *function_type = type; - *input = local_input; - return true; -} - -bool -btp_frame_parse_address_in_function(char **input, - uint64_t *address, - char **function_name, - char **function_type, - struct btp_location *location) -{ - char *local_input = *input; - - /* Read memory address in hexadecimal format. */ - int digits = btp_parse_hexadecimal_number(&local_input, address); - location->column += digits; - if (0 == digits) - { - location->message = "Hexadecimal number representing memory address expected."; - return false; - } - - /* Skip spaces. */ - int chars = btp_skip_char_sequence(&local_input, ' '); - location->column += chars; - if (0 == chars) - { - location->message = "Space expected after memory address."; - return false; - } - - /* Skip keyword "in". */ - chars = btp_skip_string(&local_input, "in"); - location->column += chars; - if (0 == chars) - { - location->message = "Keyword \"in\" expected after memory address."; - return false; - } - - /* Skip spaces. */ - chars = btp_skip_char_sequence(&local_input, ' '); - location->column += chars; - if (0 == chars) - { - location->message = "Space expected after 'in'."; - return false; - } - - /* C++ specific case for "0xfafa in vtable for function ()" */ - chars = btp_skip_string(&local_input, "vtable"); - location->column += chars; - if (0 < chars) - { - chars = btp_skip_char_sequence(&local_input, ' '); - location->column += chars; - if (0 == chars) - { - location->message = "Space expected after 'vtable'."; - return false; - } - - chars = btp_skip_string(&local_input, "for"); - location->column += chars; - if (0 == chars) - { - location->message = "Keyword \"for\" expected."; - return false; - } - - chars = btp_skip_char_sequence(&local_input, ' '); - location->column += chars; - if (0 == chars) - { - location->message = "Space expected after 'for'."; - return false; - } - } - - if (!btp_frame_parse_function_call(&local_input, - function_name, - function_type, - location)) - { - /* Do not update location here, it has been modified by the - called function. */ - return false; - } - - *input = local_input; - return true; -} - -bool -btp_frame_parse_file_location(char **input, - char **file, - unsigned *fileline, - struct btp_location *location) -{ - char *local_input = *input; - int line, column; - if (0 == btp_skip_char_span_location(&local_input, " \n", &line, &column)) - { - location->message = "Expected a space or a newline."; - return false; - } - btp_location_add(location, line, column); - - int chars = btp_skip_string(&local_input, "at"); - if (0 == chars) - { - chars = btp_skip_string(&local_input, "from"); - if (0 == chars) - { - location->message = "Expected 'at' or 'from'."; - return false; - } - } - location->column += chars; - - int spaces = btp_skip_char_sequence(&local_input, ' '); - location->column += spaces; - if (0 == spaces) - { - location->message = "Expected a space before file location."; - return false; - } - - char *file_name; - chars = btp_parse_char_span(&local_input, BTP_alnum "_/\\+.-", &file_name); - location->column += chars; - if (0 == chars) - { - location->message = "Expected a file name."; - return false; - } - - if (btp_skip_char(&local_input, ':')) - { - location->column += 1; - int digits = btp_parse_unsigned_integer(&local_input, fileline); - location->column += digits; - if (0 == digits) - { - free(file_name); - location->message = "Expected a line number."; - return false; - } - } - else - *fileline = -1; - - *file = file_name; - *input = local_input; - return true; -} - -struct btp_frame * -btp_frame_parse_header(char **input, - struct btp_location *location) -{ - char *local_input = *input; - struct btp_frame *imframe = btp_frame_new(); /* im - intermediate */ - int chars = btp_frame_parse_frame_start(&local_input, - &imframe->number); - - location->column += chars; - if (0 == chars) - { - location->message = "Frame start sequence expected."; - btp_frame_free(imframe); - return NULL; - } - - struct btp_location internal_location; - btp_location_init(&internal_location); - if (btp_frame_parse_address_in_function(&local_input, - &imframe->address, - &imframe->function_name, - &imframe->function_type, - &internal_location)) - { - btp_location_add(location, - internal_location.line, - internal_location.column); - - /* Optional section " from file.c:65" */ - /* Optional section " at file.c:65" */ - btp_location_init(&internal_location); - if (btp_frame_parse_file_location(&local_input, - &imframe->source_file, - &imframe->source_line, - &internal_location)) - { - btp_location_add(location, - internal_location.line, - internal_location.column); - } - } - else - { - btp_location_init(&internal_location); - if (btp_frame_parse_function_call(&local_input, - &imframe->function_name, - &imframe->function_type, - &internal_location)) - { - btp_location_add(location, - internal_location.line, - internal_location.column); - - /* Mandatory section " at file.c:65" */ - btp_location_init(&internal_location); - if (!btp_frame_parse_file_location(&local_input, - &imframe->source_file, - &imframe->source_line, - &internal_location)) - { - location->message = "Function call in the frame header " - "misses mandatory \"at file.c:xy\" section"; - btp_frame_free(imframe); - return NULL; - } - - btp_location_add(location, - internal_location.line, - internal_location.column); - } - else - { - int chars = btp_skip_string(&local_input, "<signal handler called>"); - if (0 < chars) - { - location->column += chars; - imframe->signal_handler_called = true; - } - else - { - location->message = "Frame header variant not recognized."; - btp_frame_free(imframe); - return NULL; - } - } - } - - *input = local_input; - return imframe; -} |