[SATYR PATCH 6/9] Implement normalization for core threads
Martin Milata
mmilata at redhat.com
Wed Jun 26 20:14:10 UTC 2013
Most of the code was copypasted from the gdb function and I don't see an
elegant solution to this. At least we should expect to have more than
the two copies in the future ...
Signed-off-by: Martin Milata <mmilata at redhat.com>
---
include/gdb/frame.h | 9 ---
include/normalize.h | 4 ++
lib/gdb_frame.c | 23 -------
lib/normalize.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 179 insertions(+), 38 deletions(-)
diff --git a/include/gdb/frame.h b/include/gdb/frame.h
index 756b458..a9b71bd 100644
--- a/include/gdb/frame.h
+++ b/include/gdb/frame.h
@@ -452,15 +452,6 @@ struct sr_gdb_frame *
sr_gdb_frame_parse_header(const char **input,
struct sr_location *location);
-/**
- * Removes first num chars from function name in the frame if it begins
- * with the prefix.
- */
-void
-sr_gdb_frame_remove_func_prefix(struct sr_gdb_frame *frame,
- const char *prefix,
- int num);
-
#ifdef __cplusplus
}
#endif
diff --git a/include/normalize.h b/include/normalize.h
index a595cb9..34e4034 100644
--- a/include/normalize.h
+++ b/include/normalize.h
@@ -36,6 +36,7 @@ extern "C" {
struct sr_gdb_frame;
struct sr_gdb_thread;
struct sr_gdb_stacktrace;
+struct sr_core_thread;
void
sr_normalize_gdb_thread(struct sr_gdb_thread *thread);
@@ -43,6 +44,9 @@ sr_normalize_gdb_thread(struct sr_gdb_thread *thread);
void
sr_normalize_gdb_stacktrace(struct sr_gdb_stacktrace *stacktrace);
+void
+sr_normalize_core_thread(struct sr_core_thread *thread);
+
// TODO: move to gdb_stacktrace.h
/**
* Checks whether the thread it contains some function used to exit
diff --git a/lib/gdb_frame.c b/lib/gdb_frame.c
index 6deb1a3..220e358 100644
--- a/lib/gdb_frame.c
+++ b/lib/gdb_frame.c
@@ -1101,29 +1101,6 @@ sr_gdb_frame_parse_header(const char **input,
return imframe;
}
-void
-sr_gdb_frame_remove_func_prefix(struct sr_gdb_frame *frame,
- const char *prefix,
- int num)
-{
- int prefix_len, func_len;
-
- if (!frame->function_name || !frame->source_file)
- return;
-
- prefix_len = strlen(prefix);
-
- if (strncmp(frame->function_name, prefix, prefix_len))
- return;
-
- func_len = strlen(frame->function_name);
- if (num > func_len)
- num = func_len;
-
- memmove(frame->function_name, frame->function_name + num,
- func_len - num + 1);
-}
-
static void
gdb_append_bthash_text(struct sr_gdb_frame *frame, enum sr_bthash_flags flags,
struct sr_strbuf *strbuf)
diff --git a/lib/normalize.c b/lib/normalize.c
index 6a8c351..50b13ae 100644
--- a/lib/normalize.c
+++ b/lib/normalize.c
@@ -21,6 +21,9 @@
#include "gdb/frame.h"
#include "gdb/thread.h"
#include "gdb/stacktrace.h"
+#include "core/frame.h"
+#include "core/thread.h"
+#include "thread.h"
#include "utils.h"
#include <string.h>
#include <assert.h>
@@ -227,6 +230,26 @@ find_new_function_name_glibc(const char *function_name,
return NULL;
}
+static void
+remove_func_prefix(char *function_name, const char *prefix, int num)
+{
+ int prefix_len, func_len;
+
+ if (!function_name)
+ return;
+
+ prefix_len = strlen(prefix);
+
+ if (strncmp(function_name, prefix, prefix_len))
+ return;
+
+ func_len = strlen(function_name);
+ if (num > func_len)
+ num = func_len;
+
+ memmove(function_name, function_name + num, func_len - num + 1);
+}
+
void
sr_normalize_gdb_thread(struct sr_gdb_thread *thread)
{
@@ -246,13 +269,16 @@ sr_normalize_gdb_thread(struct sr_gdb_thread *thread)
struct sr_gdb_frame *frame = thread->frames;
while (frame)
{
- /* Remove IA__ prefix used in GLib, GTK and GDK. */
- sr_gdb_frame_remove_func_prefix(frame, "IA__gdk", strlen("IA__"));
- sr_gdb_frame_remove_func_prefix(frame, "IA__g_", strlen("IA__"));
- sr_gdb_frame_remove_func_prefix(frame, "IA__gtk", strlen("IA__"));
+ if (frame->source_file)
+ {
+ /* 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. */
- sr_gdb_frame_remove_func_prefix(frame, "__GI_", strlen("__GI_"));
+ /* Remove __GI_ (glibc internal) prefix. */
+ remove_func_prefix(frame->function_name, "__GI_", strlen("__GI_"));
+ }
frame = frame->next;
}
@@ -368,6 +394,149 @@ sr_normalize_gdb_thread(struct sr_gdb_thread *thread)
}
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);
+
+ bool removable_with_above =
+ is_removable_glibc_with_above(frame->function_name, frame->file_name);
+
+ 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;
+ }
+
+}
+
+void
sr_normalize_gdb_stacktrace(struct sr_gdb_stacktrace *stacktrace)
{
struct sr_gdb_thread *thread = stacktrace->threads;
--
1.7.11.7
More information about the Crash-catcher
mailing list