int sr_java_frame_cmp(struct sr_java_frame *frame1, struct sr_java_frame *frame2) { if (frame1->is_exception != frame2->is_exception) return frame1->is_exception ? 1 : -1; int res = sr_strcmp0(frame1->name, frame2->name); if (res != 0) return res; /* Don't compare exception messages because of localization! */ if (frame1->is_exception) return 0; /* Method call comparsion */ res = sr_strcmp0(frame1->class_path, frame2->class_path); if (res != 0) return res; res = sr_strcmp0(frame1->file_name, frame2->file_name); if (res != 0) return res; if (frame1->is_native != frame2->is_native) return frame1->is_native ? 1 : -1; return frame1->file_line - frame2->file_line; }
int sr_python_frame_cmp_distance(struct sr_python_frame *frame1, struct sr_python_frame *frame2) { /* function_name */ int function_name = sr_strcmp0(frame1->function_name, frame2->function_name); if (function_name != 0) return function_name; /* file_name */ int file_name = sr_strcmp0(frame1->file_name, frame2->file_name); if (file_name != 0) return file_name; /* special_function */ int special_function = frame1->special_function - frame2->special_function; if (special_function != 0) return special_function; /* special_file */ int special_file = frame1->special_file - frame2->special_file; if (special_file != 0) return special_file; return 0; }
static bool next_functions_similar(struct sr_gdb_frame *frame1, struct sr_gdb_frame *frame2) { if ((!frame1->next && frame2->next) || (frame1->next && !frame2->next) || (frame1->next && frame2->next && (0 != sr_strcmp0(frame1->next->function_name, frame2->next->function_name) || 0 == sr_strcmp0(frame1->next->function_name, "??") || (frame1->next->library_name && frame2->next->library_name && 0 != strcmp(frame1->next->library_name, frame2->next->library_name))))) return false; return true; }
static int frame_callback(Dwfl_Frame *frame, void *data) { struct frame_callback_arg *frame_arg = data; char **error_msg = &frame_arg->error_msg; Dwarf_Addr pc; bool minus_one; if (!dwfl_frame_pc(frame, &pc, &minus_one)) { set_error_dwfl("dwfl_frame_pc"); return DWARF_CB_ABORT; } Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(frame)); struct sr_core_frame *result = resolve_frame(dwfl, pc, minus_one); /* Do not unwind below __libc_start_main. */ if (0 == sr_strcmp0(result->function_name, "__libc_start_main")) { sr_core_frame_free(result); return CB_STOP_UNWIND; } frame_arg->thread->frames = sr_core_frame_append(frame_arg->thread->frames, result); return DWARF_CB_OK; }
int sr_java_frame_cmp_distance(struct sr_java_frame *frame1, struct sr_java_frame *frame2) { int res = sr_strcmp0(frame1->name, frame2->name); if (res != 0) return res; return 0; }
int sr_python_frame_cmp(struct sr_python_frame *frame1, struct sr_python_frame *frame2) { /* function_name */ int function_name = sr_strcmp0(frame1->function_name, frame2->function_name); if (function_name != 0) return function_name; /* file_name */ int file_name = sr_strcmp0(frame1->file_name, frame2->file_name); if (file_name != 0) return file_name; /* file_line */ int file_line = frame1->file_line - frame2->file_line; if (file_line != 0) return file_line; /* special_function */ int special_function = frame1->special_function - frame2->special_function; if (special_function != 0) return special_function; /* special_file */ int special_file = frame1->special_file - frame2->special_file; if (special_file != 0) return special_file; /* line_contents */ int line_contents = sr_strcmp0(frame1->line_contents, frame2->line_contents); if (line_contents != 0) return line_contents; return 0; }
int sr_ruby_frame_cmp(struct sr_ruby_frame *frame1, struct sr_ruby_frame *frame2) { /* function_name */ int function_name = sr_strcmp0(frame1->function_name, frame2->function_name); if (function_name != 0) return function_name; /* file_name */ int file_name = sr_strcmp0(frame1->file_name, frame2->file_name); if (file_name != 0) return file_name; /* file_line */ int file_line = frame1->file_line - frame2->file_line; if (file_line != 0) return file_line; /* special_function */ int special_function = frame1->special_function - frame2->special_function; if (special_function != 0) return special_function; /* block_level */ int block_level = frame1->block_level - frame2->block_level; if (block_level != 0) return block_level; /* rescue_level */ int rescue_level = frame1->rescue_level - frame2->rescue_level; if (rescue_level != 0) return rescue_level; return 0; }
void sr_normalize_gdb_paired_unknown_function_names(struct sr_gdb_thread *thread1, struct sr_gdb_thread *thread2) { if (!thread1->frames || !thread2->frames) { return; } int i = 0; struct sr_gdb_frame *curr_frame1 = thread1->frames; struct sr_gdb_frame *curr_frame2 = thread2->frames; if (0 == sr_strcmp0(curr_frame1->function_name, "??") && 0 == sr_strcmp0(curr_frame2->function_name, "??") && !(curr_frame1->library_name && curr_frame2->library_name && strcmp(curr_frame1->library_name, curr_frame2->library_name)) && next_functions_similar(curr_frame1, curr_frame2)) { free(curr_frame1->function_name); curr_frame1->function_name = sr_asprintf("__unknown_function_%d", i); free(curr_frame2->function_name); curr_frame2->function_name = sr_asprintf("__unknown_function_%d", i); i++; } struct sr_gdb_frame *prev_frame1 = curr_frame1; struct sr_gdb_frame *prev_frame2 = curr_frame2; curr_frame1 = curr_frame1->next; curr_frame2 = curr_frame2->next; while (curr_frame1) { if (0 == sr_strcmp0(curr_frame1->function_name, "??")) { while (curr_frame2) { if (0 == sr_strcmp0(curr_frame2->function_name, "??") && !(curr_frame1->library_name && curr_frame2->library_name && strcmp(curr_frame1->library_name, curr_frame2->library_name)) && 0 != sr_strcmp0(prev_frame2->function_name, "??") && next_functions_similar(curr_frame1, curr_frame2) && 0 == sr_strcmp0(prev_frame1->function_name, prev_frame2->function_name) && !(prev_frame1->library_name && prev_frame2->library_name && strcmp(prev_frame1->library_name, prev_frame2->library_name))) { free(curr_frame1->function_name); curr_frame1->function_name = sr_asprintf("__unknown_function_%d", i); free(curr_frame2->function_name); curr_frame2->function_name = sr_asprintf("__unknown_function_%d", i); i++; break; } prev_frame2 = curr_frame2; curr_frame2 = curr_frame2->next; } } prev_frame1 = curr_frame1; curr_frame1 = curr_frame1->next; prev_frame2 = thread2->frames; curr_frame2 = prev_frame2->next; } }
void sr_normalize_core_thread(struct sr_core_thread *thread) { /* Find the exit frame and remove everything above it. */ struct sr_core_frame *exit_frame = sr_core_thread_find_exit_frame(thread); if (exit_frame) { bool success = sr_thread_remove_frames_above((struct sr_thread *)thread, (struct sr_frame *)exit_frame); assert(success); /* if this fails, some code become broken */ success = sr_thread_remove_frame((struct sr_thread *)thread, (struct sr_frame *)exit_frame); assert(success); /* if this fails, some code become broken */ } /* Normalize function names by removing various prefixes that * occur only in some cases. */ struct sr_core_frame *frame = thread->frames; while (frame) { /* Remove IA__ prefix used in GLib, GTK and GDK. */ remove_func_prefix(frame->function_name, "IA__gdk", strlen("IA__")); remove_func_prefix(frame->function_name, "IA__g_", strlen("IA__")); remove_func_prefix(frame->function_name, "IA__gtk", strlen("IA__")); /* Remove __GI_ (glibc internal) prefix. */ remove_func_prefix(frame->function_name, "__GI_", strlen("__GI_")); frame = frame->next; } /* Unify some functions by renaming them. */ frame = thread->frames; while (frame) { char *new_function_name = find_new_function_name_glibc(frame->function_name, frame->file_name); if (new_function_name) { free(frame->function_name); frame->function_name = new_function_name; } frame = frame->next; } /* Remove redundant frames from the thread. */ frame = thread->frames; while (frame) { struct sr_core_frame *next_frame = frame->next; /* Remove frames which are not a cause of the crash. */ bool removable = is_removable_dbus(frame->function_name, frame->file_name) || is_removable_gdk(frame->function_name, frame->file_name) || is_removable_glib(frame->function_name, frame->file_name) || is_removable_glibc(frame->function_name, frame->file_name) || is_removable_libstdcpp(frame->function_name, frame->file_name) || is_removable_linux(frame->function_name, frame->file_name) || is_removable_xorg(frame->function_name, frame->file_name) || is_removable_jvm(frame->function_name, frame->file_name) || is_removable_vim(frame->function_name, frame->file_name); bool removable_with_above = is_removable_glibc_with_above(frame->function_name, frame->file_name) || sr_core_thread_is_exit_frame(frame); if (removable_with_above) { bool success = sr_thread_remove_frames_above((struct sr_thread *)thread, (struct sr_frame *)frame); assert(success); } if (removable || removable_with_above) sr_thread_remove_frame((struct sr_thread *)thread, (struct sr_frame *)frame); frame = next_frame; } /* If the first frame has address 0x0000 and its name is '??', it * is a dereferenced null, and we remove it. This frame is not * really invalid, but it affects stacktrace quality rating. See * Red Hat Bugzilla bug #639038. * @code * #0 0x0000000000000000 in ?? () * No symbol table info available. * #1 0x0000000000422648 in main (argc=1, argv=0x7fffa57cf0d8) at totem.c:242 * error = 0x0 * totem = 0xdee070 [TotemObject] * @endcode */ if (thread->frames && thread->frames->address == 0x0000 && !thread->frames->function_name) { sr_thread_remove_frame((struct sr_thread *)thread, (struct sr_frame *)thread->frames); } /* If the last frame has address 0x0000 and its name is '??', * remove it. This frame is not really invalid, but it affects * stacktrace quality rating. See Red Hat Bugzilla bug #592523. * @code * #2 0x00007f4dcebbd62d in clone () * at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112 * No locals. * #3 0x0000000000000000 in ?? () * @endcode */ struct sr_core_frame *last = thread->frames; while (last && last->next) last = last->next; if (last && last->address == 0x0000 && !last->function_name) { sr_thread_remove_frame((struct sr_thread *)thread, (struct sr_frame *)last); } /* Merge recursively called functions into single frame */ struct sr_core_frame *curr_frame = thread->frames; struct sr_core_frame *prev_frame = NULL; while (curr_frame) { if (prev_frame && prev_frame->function_name && 0 == sr_strcmp0(prev_frame->function_name, curr_frame->function_name)) { prev_frame->next = curr_frame->next; sr_core_frame_free(curr_frame); curr_frame = prev_frame->next; continue; } prev_frame = curr_frame; curr_frame = curr_frame->next; } }
static struct sr_core_thread * unwind_thread(struct UCD_info *ui, unw_addr_space_t as, Dwfl *dwfl, int thread_no, char **error_msg) { int ret; unw_cursor_t c; struct sr_core_frame *trace = NULL; _UCD_select_thread(ui, thread_no); ret = unw_init_remote(&c, as, ui); if (ret < 0) { set_error("unw_init_remote failed: %s", unw_strerror(ret)); return NULL; } int count = 1000; while (--count > 0) { unw_word_t ip; ret = unw_get_reg(&c, UNW_REG_IP, &ip); if (ret < 0) warn("unw_get_reg(UNW_REG_IP) failed: %s", unw_strerror(ret)); /* Seen this happen when unwinding thread that did not start * in main(). */ if (ip == 0) break; struct sr_core_frame *entry = resolve_frame(dwfl, ip, false); if (!entry->function_name) { size_t funcname_len = 512; char *funcname = sr_malloc(funcname_len); if (unw_get_proc_name(&c, funcname, funcname_len, NULL) == 0) entry->function_name = funcname; else free(funcname); } trace = sr_core_frame_append(trace, entry); /* printf("%s 0x%llx %s %s -\n", (ip_seg && ip_seg->build_id) ? ip_seg->build_id : "-", (unsigned long long)(ip_seg ? ip - ip_seg->vaddr : ip), (entry->symbol ? entry->symbol : "-"), (ip_seg && ip_seg->filename) ? ip_seg->filename : "-"); */ /* Do not unwind below __libc_start_main. */ if (0 == sr_strcmp0(entry->function_name, "__libc_start_main")) break; ret = unw_step(&c); if (ret == 0) break; if (ret < 0) { warn("unw_step failed: %s", unw_strerror(ret)); break; } } if (error_msg && !*error_msg && !trace) { set_error("No frames found for thread %d", thread_no); } struct sr_core_thread *thread = sr_core_thread_new(); thread->frames = trace; return thread; }