/* 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 bool module_list_continues(const char *input) { /* There should be no timestamp in the continuation */ if (sr_koops_skip_timestamp(&input)) return false; /* Usually follows the module list */ if (sr_skip_string(&input, "Pid: ")) return false; /* See tests/kerneloopses/rhbz-865695-2-notime */ /* and tests/kerneloopses/github-102 */ if (sr_skip_string(&input, "CPU") && sr_skip_char_span(&input, " :") && sr_skip_char_span(&input, "0123456789")) return false; /* Other conditions may need to be added */ return true; }
static bool parse_alt_stack_end(const char **input) { const char *local_input = *input; sr_skip_char_span(&local_input, " \t"); /* Multiple '<' because of "<<EOE>>" */ if (!sr_skip_char_span(&local_input, "<") || !sr_skip_string(&local_input, "EO") || !sr_skip_char_span(&local_input, "IE") || !sr_skip_char_span(&local_input, ">")) return false; *input = local_input; return true; }
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_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; }