struct btp_frame * btp_backtrace_get_crash_frame(struct btp_backtrace *backtrace) { backtrace = btp_backtrace_dup(backtrace); struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace); if (!crash_thread) { btp_backtrace_free(backtrace); return NULL; } btp_normalize_backtrace(backtrace); struct btp_frame *crash_frame = crash_thread->frames; crash_frame = btp_frame_dup(crash_frame, false); btp_backtrace_free(backtrace); return crash_frame; }
struct btp_backtrace * btp_backtrace_parse(const char **input, struct btp_location *location) { const char *local_input = *input; struct btp_backtrace *imbacktrace = btp_backtrace_new(); /* im - intermediate */ imbacktrace->libs = btp_sharedlib_parse(*input); /* The header is mandatory, but it might contain no frame header, * in some broken backtraces. In that case, backtrace.crash value * is kept as NULL. */ if (!btp_backtrace_parse_header(&local_input, &imbacktrace->crash, location)) { btp_backtrace_free(imbacktrace); return NULL; } struct btp_thread *thread, *prevthread = NULL; while ((thread = btp_thread_parse(&local_input, location))) { if (prevthread) { btp_thread_add_sibling(prevthread, thread); prevthread = thread; } else imbacktrace->threads = prevthread = thread; } if (!imbacktrace->threads) { btp_backtrace_free(imbacktrace); return NULL; } *input = local_input; return imbacktrace; }
float btp_backtrace_quality_complex(struct btp_backtrace *backtrace) { backtrace = btp_backtrace_dup(backtrace); /* Find the crash thread, and then normalize the backtrace. It is * not possible to find the crash thread after the backtrace has * been normalized. */ struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace); btp_normalize_backtrace(backtrace); /* Get the quality q1 of the full backtrace. */ float q1 = btp_backtrace_quality_simple(backtrace); if (!crash_thread) { btp_backtrace_free(backtrace); return q1; } /* Get the quality q2 of the crash thread. */ float q2 = btp_thread_quality(crash_thread); /* Get the quality q3 of the frames around the crash. First, * duplicate the crash thread so we can cut it. Then find an exit * frame, and remove it and everything above it * (__run_exit_handlers and such). Then remove all the redundant * frames (assert calls etc.) Then limit the frame count to 5. */ btp_thread_remove_frames_below_n(crash_thread, 5); float q3 = btp_thread_quality(crash_thread); btp_backtrace_free(backtrace); /* Compute and return the final backtrace quality q. */ return 0.25f * q1 + 0.35f * q2 + 0.4f * q3; }
char * btp_backtrace_get_duplication_hash(struct btp_backtrace *backtrace) { backtrace = btp_backtrace_dup(backtrace); struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace); if (crash_thread) btp_backtrace_remove_threads_except_one(backtrace, crash_thread); btp_normalize_backtrace(backtrace); btp_backtrace_limit_frame_depth(backtrace, 3); char *hash = btp_backtrace_to_text(backtrace, false); btp_backtrace_free(backtrace); return hash; }
struct btp_thread * btp_backtrace_get_optimized_thread(struct btp_backtrace *backtrace, int max_frames) { struct btp_thread *crash_thread; backtrace = btp_backtrace_dup(backtrace); crash_thread = btp_backtrace_find_crash_thread(backtrace); if (!crash_thread) { btp_backtrace_free(backtrace); return NULL; } btp_backtrace_remove_threads_except_one(backtrace, crash_thread); btp_backtrace_set_libnames(backtrace); btp_normalize_thread(crash_thread); btp_normalize_optimize_thread(crash_thread); /* Remove frames with no function name (i.e. signal handlers). */ struct btp_frame *frame = crash_thread->frames, *frame_next; while (frame) { frame_next = frame->next; if (!frame->function_name) btp_thread_remove_frame(crash_thread, frame); frame = frame_next; } if (max_frames > 0) btp_thread_remove_frames_below_n(crash_thread, max_frames); crash_thread = btp_thread_dup(crash_thread, false); btp_backtrace_free(backtrace); return crash_thread; }
int main(int argc, char **argv) { abrt_init(argv); /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "\b [options] -d DIR\n" "\n" "Analyzes C/C++ backtrace, generates duplication hash, backtrace rating, and identifies crash function in dump 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", _("Dump 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 btp_location location; btp_location_init(&location); char *backtrace_str_ptr = backtrace_str; struct btp_backtrace *backtrace = btp_backtrace_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); VERB3 log("Generating duphash: %s", emptybt->buf); char hash_str[SHA1_RESULT_LEN*2 + 1]; create_hash(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. */ char *str_hash_core = btp_backtrace_get_duplication_hash(backtrace); struct strbuf *str_hash = strbuf_new(); strbuf_append_str(str_hash, component); strbuf_append_str(str_hash, str_hash_core); VERB3 log("Generating duphash: %s", str_hash->buf); char hash_str[SHA1_RESULT_LEN*2 + 1]; create_hash(hash_str, str_hash->buf); dd_save_text(dd, FILENAME_DUPHASH, hash_str); strbuf_free(str_hash); free(str_hash_core); /* Compute the backtrace rating. */ float quality = btp_backtrace_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 btp_frame *crash_frame = btp_backtrace_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); } btp_frame_free(crash_frame); } btp_backtrace_free(backtrace); dd_close(dd); free(component); return 0; }