/* a special line with instruction pointer may be present in the format * RIP: 0010:[<ffffffff811c6ed5>] [<ffffffff811c6ed5>] __block_write_full_page+0xa5/0x350 * (for x86_64), or * EIP: [<f8e40765>] wdev_priv.part.8+0x3/0x5 [wl] SS:ESP 0068:f180dbf8 * (for i386, where it is AFTER the trace) */ static struct sr_koops_frame* parse_IP(const char **input) { struct sr_koops_frame *frame; const char *local_input = *input; sr_skip_char_span(&local_input, " \t"); if (sr_skip_string(&local_input, "RIP:")) { if (!sr_skip_char_span(&local_input, " \t")) return NULL; /* The address is there twice, skip the first one */ if (!sr_skip_char_cspan(&local_input, " \t")) return NULL; if (!sr_skip_char_span(&local_input, " \t")) return NULL; frame = sr_koops_frame_parse(&local_input); if (!frame) return NULL; } else if(sr_skip_string(&local_input, "EIP:")) { if (!sr_skip_char_span(&local_input, " \t")) return NULL; frame = sr_koops_frame_new(); if (!sr_koops_parse_address(&local_input, &frame->address)) { sr_koops_frame_free(frame); return NULL; } sr_skip_char_span(&local_input, " \t"); /* Question mark means unreliable */ frame->reliable = sr_skip_char(&local_input, '?') != true; sr_skip_char_span(&local_input, " \t"); if (!sr_koops_parse_function(&local_input, &frame->function_name, &frame->function_offset, &frame->function_length, &frame->module_name)) { sr_koops_frame_free(frame); return NULL; } } else return NULL; sr_skip_char_cspan(&local_input, "\n"); *input = local_input; return frame; }
static char * parse_alt_stack_start(const char **input) { char *stack_label = NULL; const char *local_input = *input; sr_skip_char_span(&local_input, " \t"); if (!sr_skip_char(&local_input, '<') || !sr_parse_char_cspan(&local_input, "> \t\n", &stack_label) || !sr_skip_char(&local_input, '>')) { free(stack_label); return NULL; } *input = local_input; return stack_label; }
struct sr_ruby_frame * sr_ruby_frame_parse(const char **input, struct sr_location *location) { const char *local_input = *input; struct sr_ruby_frame *frame = sr_ruby_frame_new(); /* take everything before the backtick * /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require' * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ char *filename_lineno_in = NULL; if (!sr_parse_char_cspan(&local_input, "`", &filename_lineno_in)) { location->message = sr_strdup("Unable to find the '`' character " "identifying the beginning of function name."); goto fail; } size_t l = strlen(filename_lineno_in); location->column += l; char *p = filename_lineno_in + l; /* /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require' * ^^^^ */ p -= strlen(":in "); if (p < filename_lineno_in || 0 != strcmp(":in ", p)) { location->column -= strlen(":in "); location->message = sr_strdup("Unable to find ':in ' preceding the " "backtick character."); goto fail; } /* Find the beginning of the line number. */ *p = '\0'; do { p--; } while (p >= filename_lineno_in && isdigit(*p)); p++; /* /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require' * ^^ */ char *p_copy = p; int lineno_len = sr_parse_uint32((const char **)&p_copy, &frame->file_line); if (lineno_len <= 0) { location->message = sr_strdup("Unable to find line number before ':in '"); goto fail; } /* /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require' * ^ */ p--; if (p < filename_lineno_in || *p != ':') { location->column -= lineno_len; location->message = sr_strdup("Unable to fin the ':' character " "preceding the line number"); goto fail; } /* Everything before the colon is the file name. */ *p = '\0'; frame->file_name = filename_lineno_in; filename_lineno_in = NULL; if(!sr_skip_char(&local_input, '`')) { location->message = sr_strdup("Unable to find the '`' character " "identifying the beginning of function name."); goto fail; } location->column++; /* The part in quotes can look like: * `rescue in rescue in block (3 levels) in func' * parse the number of rescues and blocks */ while (sr_skip_string(&local_input, "rescue in ")) { frame->rescue_level++; location->column += strlen("rescue in "); } if (sr_skip_string(&local_input, "block in ")) { frame->block_level = 1; location->column += strlen("block in"); } else if(sr_skip_string(&local_input, "block (")) { location->column += strlen("block ("); int len = sr_parse_uint32(&local_input, &frame->block_level); if (len == 0 || !sr_skip_string(&local_input, " levels) in ")) { location->message = sr_strdup("Unable to parse block depth."); goto fail; } location->column += len + strlen(" levels) in "); } if (sr_skip_char(&local_input, '<')) { location->column++; frame->special_function = true; } if (!sr_parse_char_cspan(&local_input, "'>", &frame->function_name)) { location->message = sr_strdup("Unable to find the \"'\" character " "delimiting the function name."); goto fail; } location->column += strlen(frame->function_name); if (frame->special_function) { if (!sr_skip_char(&local_input, '>')) { location->message = sr_strdup("Unable to find the \">\" character " "delimiting the function name."); goto fail; } location->column++; } if (!sr_skip_char(&local_input, '\'')) { location->message = sr_strdup("Unable to find the \"'\" character " "delimiting the function name."); goto fail; } location->column++; *input = local_input; return frame; fail: sr_ruby_frame_free(frame); free(filename_lineno_in); return NULL; }
struct sr_python_stacktrace * sr_python_stacktrace_parse(const char **input, struct sr_location *location) { const char *local_input = *input; /* Parse the header. */ if (sr_skip_char(&local_input, '\n')) location->column += 1; const char *HEADER = "Traceback (most recent call last):\n"; local_input = sr_strstr_location(local_input, HEADER, &location->line, &location->column); if (!local_input) { /* SyntaxError stack trace of an exception thrown in the executed file * conforms to the following template: * invalid syntax ($file, line $number) * * File "$file", line $number * $code * ^ * SyntaxError: invalid syntax * * for exceptions thrown from imported files, the stack trace has the * regular form, except the last frame has no function name and is * followed by the pointer line (^). */ HEADER = "invalid syntax (", local_input = sr_strstr_location(*input, HEADER, &location->line, &location->column); if (!local_input) { location->message = "Traceback header not found."; return NULL; } local_input = sr_strstr_location(local_input, " File \"", &location->line, &location->column); if (!local_input) { location->message = "Frame with invalid line not found."; return NULL; } } else { local_input += strlen(HEADER); location->line += 2; location->column = 0; } struct sr_python_stacktrace *stacktrace = sr_python_stacktrace_new(); /* Read the frames. */ struct sr_python_frame *frame; struct sr_location frame_location; sr_location_init(&frame_location); while ((frame = sr_python_frame_parse(&local_input, &frame_location))) { /* * Python stacktraces are in reverse order than other types - we * reverse it here by prepending each frame to the list instead of * appending it. */ frame->next = stacktrace->frames; stacktrace->frames = frame; sr_location_add(location, frame_location.line, frame_location.column); } if (!stacktrace->frames) { location->message = frame_location.message; sr_python_stacktrace_free(stacktrace); return NULL; } bool invalid_syntax_pointer = true; const char *tmp_input = local_input; while (*tmp_input != '\n' && *tmp_input != '\0') { if (*tmp_input != ' ' && *tmp_input != '^') { invalid_syntax_pointer = false; break; } ++tmp_input; } if (invalid_syntax_pointer) { /* Skip line " ^" pointing to the invalid code */ sr_skip_char_cspan(&local_input, "\n"); ++local_input; ++location->line; location->column = 1; } /* Parse exception name. */ if (!sr_parse_char_cspan(&local_input, ":\n", &stacktrace->exception_name)) { location->message = "Unable to find the ':\\n' characters " "identifying the end of exception name."; sr_python_stacktrace_free(stacktrace); return NULL; } *input = local_input; return stacktrace; }
struct sr_koops_stacktrace * sr_koops_stacktrace_parse(const char **input, struct sr_location *location) { const char *local_input = *input; struct sr_koops_stacktrace *stacktrace = sr_koops_stacktrace_new(); struct sr_koops_frame *frame; bool parsed_ip = false; char *alt_stack = NULL; /* Include the raw kerneloops text */ stacktrace->raw_oops = sr_strdup(*input); /* Looks for the "Tainted: " line in the whole input */ parse_taint_flags(local_input, stacktrace); while (*local_input) { sr_skip_char_span(&local_input, " \t"); /* Skip timestamp if it's present. */ sr_koops_skip_timestamp(&local_input); sr_skip_char_span(&local_input, " \t"); /* Not sure what it means on s390x but i think it's at the end of the * stack */ if (sr_skip_string(&local_input, "Last Breaking-Event-Address:\n")) { while (*local_input) local_input++; break; } if (!stacktrace->modules && (stacktrace->modules = sr_koops_stacktrace_parse_modules(&local_input))) goto next_line; if (!parsed_ip && (frame = parse_IP(&local_input))) { /* this is the very first frame (even though for i386 it's at the * end), we need to prepend it */ stacktrace->frames = sr_koops_frame_prepend(stacktrace->frames, frame); parsed_ip = true; goto next_line; } /* <IRQ>, <NMI>, ... */ if (parse_alt_stack_end(&local_input)) { free(alt_stack); alt_stack = NULL; } /* <EOI>, <<EOE>> */ char *new_alt_stack = parse_alt_stack_start(&local_input); if (new_alt_stack) { alt_stack = new_alt_stack; } if((frame = sr_koops_frame_parse(&local_input))) { if (alt_stack) frame->special_stack = sr_strdup(alt_stack); stacktrace->frames = sr_koops_frame_append(stacktrace->frames, frame); goto next_line; } sr_skip_char_cspan(&local_input, "\n"); next_line: sr_skip_char(&local_input, '\n'); } *input = local_input; return stacktrace; }
struct sr_python_frame * sr_python_frame_parse(const char **input, struct sr_location *location) { const char *local_input = *input; if (0 == sr_skip_string(&local_input, " File \"")) { location->message = sr_asprintf("Frame header not found."); return NULL; } location->column += strlen(" File \""); struct sr_python_frame *frame = sr_python_frame_new(); /* Parse file name */ if (!sr_parse_char_cspan(&local_input, "\"", &frame->file_name)) { location->message = sr_asprintf("Unable to find the '\"' character " "identifying the beginning of file name."); goto fail; } if (strlen(frame->file_name) > 0 && frame->file_name[0] == '<' && frame->file_name[strlen(frame->file_name)-1] == '>') { frame->special_file = true; frame->file_name[strlen(frame->file_name)-1] = '\0'; char *inside = sr_strdup(frame->file_name + 1); free(frame->file_name); frame->file_name = inside; } frame->file_name = anonymize_path(frame->file_name); location->column += strlen(frame->file_name); if (0 == sr_skip_string(&local_input, "\", line ")) { location->message = sr_asprintf("Line separator not found."); goto fail; } location->column += strlen("\", line "); /* Parse line number */ int length = sr_parse_uint32(&local_input, &frame->file_line); if (0 == length) { location->message = sr_asprintf("Line number not found."); goto fail; } location->column += length; if (0 == sr_skip_string(&local_input, ", in ")) { if (local_input[0] != '\n') { location->message = sr_asprintf("Function name separator not found."); goto fail; } /* The last frame of SyntaxError stack trace does not have * function name on its line. For the sake of simplicity, we will * believe that we are dealing with such a frame now. */ frame->function_name = sr_strdup("syntax"); frame->special_function = true; } else { location->column += strlen(", in "); /* Parse function name */ if (!sr_parse_char_cspan(&local_input, "\n", &frame->function_name)) { location->message = sr_asprintf("Unable to find the newline character " "identifying the end of function name."); goto fail; } location->column += strlen(frame->function_name); if (strlen(frame->function_name) > 0 && frame->function_name[0] == '<' && frame->function_name[strlen(frame->function_name)-1] == '>') { frame->special_function = true; frame->function_name[strlen(frame->function_name)-1] = '\0'; char *inside = sr_strdup(frame->function_name + 1); free(frame->function_name); frame->function_name = inside; } } if (sr_skip_char(&local_input, '\n')) sr_location_add(location, 1, 0); /* Parse source code line (optional). */ if (4 == sr_skip_string(&local_input, " ")) { if (sr_parse_char_cspan(&local_input, "\n", &frame->line_contents) && sr_skip_char(&local_input, '\n')) sr_location_add(location, 1, 0); } *input = local_input; return frame; fail: sr_python_frame_free(frame); return NULL; }