/* constructor */ PyObject * sr_py_gdb_frame_new(PyTypeObject *object, PyObject *args, PyObject *kwds) { struct sr_py_gdb_frame *fo = (struct sr_py_gdb_frame*) PyObject_New(struct sr_py_gdb_frame, &sr_py_gdb_frame_type); if (!fo) return PyErr_NoMemory(); const char *str = NULL; if (!PyArg_ParseTuple(args, "|s", &str)) return NULL; if (str) { struct sr_location location; sr_location_init(&location); fo->frame = sr_gdb_frame_parse(&str, &location); if (!fo->frame) { PyErr_SetString(PyExc_ValueError, location.message); return NULL; } } else fo->frame = sr_gdb_frame_new(); return (PyObject*)fo; }
static int append_short_backtrace(struct strbuf *result, problem_data_t *problem_data, size_t max_text_size, bool print_item_name) { const problem_item *item = problem_data_get_item_or_NULL(problem_data, FILENAME_BACKTRACE); if (!item) return 0; /* "I did not print anything" */ if (!(item->flags & CD_FLAG_TXT)) return 0; /* "I did not print anything" */ char *truncated = NULL; if (strlen(item->content) >= max_text_size) { struct sr_location location; sr_location_init(&location); /* sr_gdb_stacktrace_parse modifies the input parameter */ char *content = item->content; struct sr_gdb_stacktrace *backtrace = sr_gdb_stacktrace_parse((const char **)&content, &location); if (!backtrace) { log(_("Can't parse backtrace")); return 0; } /* Get optimized thread stack trace for 10 top most frames */ struct sr_gdb_thread *thread = sr_gdb_stacktrace_get_optimized_thread(backtrace, 10); sr_gdb_stacktrace_free(backtrace); if (!thread) { log(_("Can't find crash thread")); return 0; } /* Cannot be NULL, it dies on memory error */ struct sr_strbuf *bt = sr_strbuf_new(); sr_gdb_thread_append_to_str(thread, bt, true); sr_gdb_thread_free(thread); truncated = sr_strbuf_free_nobuf(bt); } append_text(result, /*item_name:*/ truncated ? "truncated_backtrace" : FILENAME_BACKTRACE, /*content:*/ truncated ? truncated : item->content, print_item_name ); free(truncated); return 1; }
struct sr_core_stacktrace * sr_core_stacktrace_from_gdb(const char *gdb_output, const char *core_file, const char *exe_file, char **error_msg) { /* I'm not going to rewrite it now since the function is not being used. */ assert(error_msg); /* Initialize error_msg to 'no error'. */ *error_msg = NULL; struct core_handle *ch = open_coredump(core_file, exe_file, error_msg); if (*error_msg) return NULL; struct sr_gdb_stacktrace *gdb_stacktrace; struct sr_location location; sr_location_init(&location); gdb_stacktrace = sr_gdb_stacktrace_parse(&gdb_output, &location); if (!gdb_stacktrace) { *error_msg = sr_location_to_string(&location); core_handle_free(ch); return NULL; } struct sr_core_stacktrace *core_stacktrace = sr_core_stacktrace_new(); for (struct sr_gdb_thread *gdb_thread = gdb_stacktrace->threads; gdb_thread; gdb_thread = gdb_thread->next) { struct sr_core_thread *core_thread = sr_core_thread_new(); for (struct sr_gdb_frame *gdb_frame = gdb_thread->frames; gdb_frame; gdb_frame = gdb_frame->next) { if (gdb_frame->signal_handler_called) continue; struct sr_core_frame *core_frame = resolve_frame(ch->dwfl, gdb_frame->address, false); core_thread->frames = sr_core_frame_append(core_thread->frames, core_frame); } if (sr_gdb_stacktrace_find_crash_thread(gdb_stacktrace) == gdb_thread) { core_stacktrace->crash_thread = core_thread; } core_stacktrace->threads = sr_core_thread_append( core_stacktrace->threads, core_thread); } core_stacktrace->signal = get_signal_number(ch->eh, core_file); core_stacktrace->executable = realpath(exe_file, NULL); core_handle_free(ch); sr_gdb_stacktrace_free(gdb_stacktrace); return core_stacktrace; }
int main(int argc, char **argv) { /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif abrt_init(argv); /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "& [options] -d DIR\n" "\n" "Analyzes C/C++ backtrace, generates duplication hash, backtrace rating,\n" "and identifies crash function in problem directory DIR" ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1 }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Problem directory")), OPT_END() }; /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(0); struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return 1; char *component = dd_load_text(dd, FILENAME_COMPONENT); /* Read backtrace */ char *backtrace_str = dd_load_text_ext(dd, FILENAME_BACKTRACE, DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE); if (!backtrace_str) { dd_close(dd); return 1; } /* Compute backtrace hash */ struct sr_location location; sr_location_init(&location); const char *backtrace_str_ptr = backtrace_str; struct sr_gdb_stacktrace *backtrace = sr_gdb_stacktrace_parse(&backtrace_str_ptr, &location); free(backtrace_str); /* Store backtrace hash */ if (!backtrace) { /* * The parser failed. Compute the duphash from the executable * instead of a backtrace. * and component only. This is not supposed to happen often. */ log(_("Backtrace parsing failed for %s"), dump_dir_name); log("%d:%d: %s", location.line, location.column, location.message); struct strbuf *emptybt = strbuf_new(); char *executable = dd_load_text(dd, FILENAME_EXECUTABLE); strbuf_prepend_str(emptybt, executable); free(executable); strbuf_prepend_str(emptybt, component); log_debug("Generating duphash: %s", emptybt->buf); char hash_str[SHA1_RESULT_LEN*2 + 1]; str_to_sha1str(hash_str, emptybt->buf); dd_save_text(dd, FILENAME_DUPHASH, hash_str); /* * Other parts of ABRT assume that if no rating is available, * it is ok to allow reporting of the bug. To be sure no bad * backtrace is reported, rate the backtrace with the lowest * rating. */ dd_save_text(dd, FILENAME_RATING, "0"); strbuf_free(emptybt); free(component); dd_close(dd); /* Report success even if the parser failed, as the backtrace * has been created and rated. The failure is caused by a flaw * in the parser, not in the backtrace. */ return 0; } /* Compute duplication hash. */ struct sr_thread *crash_thread = (struct sr_thread *)sr_gdb_stacktrace_find_crash_thread(backtrace); if (crash_thread) { char *hash_str; if (g_verbose >= 3) { hash_str = sr_thread_get_duphash(crash_thread, 3, component, SR_DUPHASH_NOHASH); log("Generating duphash: %s", hash_str); free(hash_str); } hash_str = sr_thread_get_duphash(crash_thread, 3, component, SR_DUPHASH_NORMAL); dd_save_text(dd, FILENAME_DUPHASH, hash_str); free(hash_str); } else log(_("Crash thread not found")); /* Compute the backtrace rating. */ float quality = sr_gdb_stacktrace_quality_complex(backtrace); const char *rating; if (quality < 0.6f) rating = "0"; else if (quality < 0.7f) rating = "1"; else if (quality < 0.8f) rating = "2"; else if (quality < 0.9f) rating = "3"; else rating = "4"; dd_save_text(dd, FILENAME_RATING, rating); /* Get the function name from the crash frame. */ struct sr_gdb_frame *crash_frame = sr_gdb_stacktrace_get_crash_frame(backtrace); if (crash_frame) { if (crash_frame->function_name && 0 != strcmp(crash_frame->function_name, "??")) { dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function_name); } sr_gdb_frame_free(crash_frame); } sr_gdb_stacktrace_free(backtrace); dd_close(dd); free(component); return 0; }
struct sr_report * sr_abrt_report_from_dir(const char *directory, char **error_message) { struct sr_report *report = sr_report_new(); /* Report type. */ char *type_contents = file_contents(directory, "type", error_message); if (!type_contents) { sr_report_free(report); return NULL; } report->report_type = sr_abrt_type_from_type(type_contents); free(type_contents); /* Operating system. */ report->operating_system = sr_abrt_operating_system_from_dir( directory, error_message); if (!report->operating_system) { sr_report_free(report); return NULL; } /* Component name. */ report->component_name = file_contents(directory, "component", error_message); /* RPM packages. */ report->rpm_packages = sr_abrt_rpm_packages_from_dir( directory, error_message); if (!report->rpm_packages) { sr_report_free(report); return NULL; } /* Core stacktrace. */ if (report->report_type == SR_REPORT_CORE) { char *core_backtrace_contents = file_contents(directory, "core_backtrace", error_message); if (!core_backtrace_contents) { sr_report_free(report); return NULL; } report->stacktrace = (struct sr_stacktrace *)sr_core_stacktrace_from_json_text( core_backtrace_contents, error_message); free(core_backtrace_contents); if (!report->stacktrace) { sr_report_free(report); return NULL; } } /* Python stacktrace. */ if (report->report_type == SR_REPORT_PYTHON) { char *backtrace_contents = file_contents(directory, "backtrace", error_message); if (!backtrace_contents) { sr_report_free(report); return NULL; } /* Parse the Python stacktrace. */ struct sr_location location; sr_location_init(&location); const char *contents_pointer = backtrace_contents; report->stacktrace = (struct sr_stacktrace *)sr_python_stacktrace_parse( &contents_pointer, &location); free(backtrace_contents); if (!report->stacktrace) { *error_message = sr_location_to_string(&location); sr_report_free(report); return NULL; } } /* Kerneloops stacktrace. */ if (report->report_type == SR_REPORT_KERNELOOPS) { /* Determine kernel version */ char *kernel_contents = file_contents(directory, "kernel", error_message); if (!kernel_contents) { sr_report_free(report); return NULL; } /* Load the Kerneloops stacktrace */ char *backtrace_contents = file_contents(directory, "backtrace", error_message); if (!backtrace_contents) { sr_report_free(report); return NULL; } /* Parse the Kerneloops stacktrace. */ struct sr_location location; sr_location_init(&location); const char *contents_pointer = backtrace_contents; struct sr_koops_stacktrace *stacktrace = sr_koops_stacktrace_parse( &contents_pointer, &location); stacktrace->version = kernel_contents; report->stacktrace = (struct sr_stacktrace *)stacktrace; free(backtrace_contents); if (!report->stacktrace) { *error_message = sr_location_to_string(&location); sr_report_free(report); return NULL; } } /* Java stacktrace. */ if (report->report_type == SR_REPORT_JAVA) { char *backtrace_contents = file_contents(directory, "backtrace", error_message); if (!backtrace_contents) { sr_report_free(report); return NULL; } /* Parse the Java stacktrace. */ struct sr_location location; sr_location_init(&location); const char *contents_pointer = backtrace_contents; report->stacktrace = (struct sr_stacktrace *)sr_java_stacktrace_parse( &contents_pointer, &location); free(backtrace_contents); if (!report->stacktrace) { *error_message = sr_location_to_string(&location); sr_report_free(report); return NULL; } } /* Ruby stacktrace. */ if (report->report_type == SR_REPORT_RUBY) { char *backtrace_contents = file_contents(directory, "backtrace", error_message); if (!backtrace_contents) { sr_report_free(report); return NULL; } /* Parse the Ruby stacktrace. */ struct sr_location location; sr_location_init(&location); const char *contents_pointer = backtrace_contents; report->stacktrace = (struct sr_stacktrace *)sr_ruby_stacktrace_parse( &contents_pointer, &location); free(backtrace_contents); if (!report->stacktrace) { *error_message = sr_location_to_string(&location); sr_report_free(report); return NULL; } } return report; }
struct sr_core_stacktrace * sr_core_stacktrace_create(const char *gdb_stacktrace_text, const char *unstrip_text, const char *executable_path) { // Parse the GDB stacktrace. struct sr_location location; sr_location_init(&location); struct sr_gdb_stacktrace *gdb_stacktrace = sr_gdb_stacktrace_parse(&gdb_stacktrace_text, &location); if (!gdb_stacktrace) { warn("Unable to parse stacktrace: %d:%d: %s\n", location.line, location.column, location.message); return NULL; } // Parse the unstrip output. struct sr_unstrip_entry *unstrip = sr_unstrip_parse(unstrip_text); if (!unstrip) { warn("Unable to parse unstrip output."); sr_gdb_stacktrace_free(gdb_stacktrace); return NULL; } // Create the core stacktrace struct sr_core_stacktrace *core_stacktrace = sr_core_stacktrace_new(); struct sr_gdb_thread *gdb_thread = gdb_stacktrace->threads; while (gdb_thread) { struct sr_core_thread *core_thread = sr_core_thread_new(); struct sr_gdb_frame *gdb_frame = gdb_thread->frames; while (gdb_frame) { gdb_frame = gdb_frame->next; struct sr_core_frame *core_frame = sr_core_frame_new(); core_frame->address = gdb_frame->address; struct sr_unstrip_entry *unstrip_entry = sr_unstrip_find_address(unstrip, gdb_frame->address); if (unstrip_entry) { core_frame->build_id = sr_strdup(unstrip_entry->build_id); core_frame->build_id_offset = core_frame->address - unstrip_entry->start; core_frame->file_name = sr_strdup(unstrip_entry->file_name); } if (gdb_frame->function_name && 0 != strcmp(gdb_frame->function_name, "??")) { core_frame->function_name = sr_strdup(gdb_frame->function_name); } core_thread->frames = sr_core_frame_append(core_thread->frames, core_frame); } core_stacktrace->threads = sr_core_thread_append(core_stacktrace->threads, core_thread); gdb_thread = gdb_thread->next; } sr_unstrip_free(unstrip); sr_gdb_stacktrace_free(gdb_stacktrace); return core_stacktrace; }
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; }