[SATYR PATCH 8/9] Implement duplication hashes
Martin Milata
mmilata at redhat.com
Wed Jun 26 20:14:12 UTC 2013
Related to #66.
Signed-off-by: Martin Milata <mmilata at redhat.com>
---
include/thread.h | 34 ++++++++++++++++++++++++++++++
lib/core_frame.c | 31 ++++++++++++++++++++++++++++
lib/gdb_frame.c | 25 ++++++++++++++++++++++
lib/generic_frame.c | 9 ++++++++
lib/generic_frame.h | 8 ++++++++
lib/generic_thread.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++--
lib/java_frame.c | 19 +++++++++++++++++
lib/koops_frame.c | 16 +++++++++++++++
lib/python_frame.c | 16 +++++++++++++++
9 files changed, 214 insertions(+), 2 deletions(-)
diff --git a/include/thread.h b/include/thread.h
index c62c08f..3e1130b 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -47,6 +47,24 @@ struct sr_thread
};
/**
+ * Flags that influence how the duphash is computed.
+ */
+enum sr_duphash_flags
+{
+ /* Default hashing process.
+ */
+ SR_DUPHASH_NORMAL = 1 << 0,
+
+ /* Return the plaintext that would be hashed. Useful mainly for debugging.
+ */
+ SR_DUPHASH_NOHASH = 1 << 1,
+
+ /* Do not perform stacktrace normalization.
+ */
+ SR_DUPHASH_NONORMALIZE = 1 << 2,
+};
+
+/**
* Returns pointer to the first frame in thread.
*/
struct sr_frame *
@@ -125,6 +143,22 @@ sr_thread_dup(struct sr_thread *thread);
void
sr_thread_normalize(struct sr_thread *thread);
+/**
+ * Returns the duplication hash. Two threads resulting from the same crash
+ * should have the same duphash. The returned string is allocated by malloc().
+ *
+ * @param thread The thread to hash.
+ * @param frames Number of frames to include in the hash. If the value is 0,
+ * all frames are used.
+ * @param prefix String that should be prefixed before the text from which the
+ * hash is computed. ABRT/FAF used the crash component here. Can
+ * be NULL.
+ * @param flags Bitwise OR of sr_duphash_flags.
+ */
+char *
+sr_thread_get_duphash(struct sr_thread *thread, int frames, char *prefix,
+ enum sr_duphash_flags flags);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/core_frame.c b/lib/core_frame.c
index 4ae8e8c..a75f859 100644
--- a/lib/core_frame.c
+++ b/lib/core_frame.c
@@ -22,6 +22,7 @@
#include "strbuf.h"
#include "json.h"
#include "generic_frame.h"
+#include "thread.h"
#include "stacktrace.h"
#include "internal_utils.h"
#include <string.h>
@@ -31,6 +32,9 @@
static void
core_append_bthash_text(struct sr_core_frame *frame, enum sr_bthash_flags flags,
struct sr_strbuf *strbuf);
+static void
+core_append_duphash_text(struct sr_core_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf);
DEFINE_NEXT_FUNC(core_next, struct sr_frame, struct sr_core_frame)
DEFINE_SET_NEXT_FUNC(core_set_next, struct sr_frame, struct sr_core_frame)
@@ -44,6 +48,8 @@ struct frame_methods core_frame_methods =
.cmp_distance = (frame_cmp_fn_t) sr_core_frame_cmp_distance,
.frame_append_bthash_text =
(frame_append_bthash_text_fn_t) core_append_bthash_text,
+ .frame_append_duphash_text =
+ (frame_append_duphash_text_fn_t) core_append_duphash_text,
.frame_free = (frame_free_fn_t) sr_core_frame_free,
};
@@ -428,3 +434,28 @@ core_append_bthash_text(struct sr_core_frame *frame, enum sr_bthash_flags flags,
OR_UNKNOWN(frame->file_name),
OR_UNKNOWN(frame->fingerprint));
}
+
+static void
+core_append_duphash_text(struct sr_core_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf)
+{
+ /* Build id should be the preferred deduplication mechanism. */
+ if (frame->build_id)
+ sr_strbuf_append_strf(strbuf, "%s+0x%"PRIx64"\n",
+ frame->build_id,
+ frame->build_id_offset);
+
+ /* If we don't have it, try the function name. */
+ else if (frame->function_name)
+ sr_strbuf_append_strf(strbuf, " %s\n", frame->function_name);
+
+ /* Function fingerprint? */
+ else if (frame->fingerprint)
+ sr_strbuf_append_strf(strbuf, "%s+0x%"PRIx64"\n",
+ frame->fingerprint,
+ frame->build_id_offset);
+
+ /* Address should be better than nothing. */
+ else
+ sr_strbuf_append_strf(strbuf, "0x%"PRIx64"\n", frame->address);
+}
diff --git a/lib/gdb_frame.c b/lib/gdb_frame.c
index 220e358..e3985c4 100644
--- a/lib/gdb_frame.c
+++ b/lib/gdb_frame.c
@@ -22,6 +22,7 @@
#include "strbuf.h"
#include "location.h"
#include "generic_frame.h"
+#include "thread.h"
#include "stacktrace.h"
#include "internal_utils.h"
#include <stdlib.h>
@@ -35,6 +36,9 @@
static void
gdb_append_bthash_text(struct sr_gdb_frame *frame, enum sr_bthash_flags flags,
struct sr_strbuf *strbuf);
+static void
+gdb_append_duphash_text(struct sr_gdb_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf);
DEFINE_NEXT_FUNC(gdb_next, struct sr_frame, struct sr_gdb_frame)
DEFINE_SET_NEXT_FUNC(gdb_set_next, struct sr_frame, struct sr_gdb_frame)
@@ -54,6 +58,8 @@ struct frame_methods gdb_frame_methods =
.cmp_distance = (frame_cmp_fn_t) sr_gdb_frame_cmp_distance,
.frame_append_bthash_text =
(frame_append_bthash_text_fn_t) gdb_append_bthash_text,
+ .frame_append_duphash_text =
+ (frame_append_duphash_text_fn_t) gdb_append_duphash_text,
.frame_free = (frame_free_fn_t) sr_gdb_frame_free,
};
@@ -1116,3 +1122,22 @@ gdb_append_bthash_text(struct sr_gdb_frame *frame, enum sr_bthash_flags flags,
frame->address,
OR_UNKNOWN(frame->library_name));
}
+
+static void
+gdb_append_duphash_text(struct sr_gdb_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf)
+{
+ /* Taken from btparser. */
+ sr_strbuf_append_str(strbuf, " ");
+
+ if (frame->function_type)
+ sr_strbuf_append_strf(strbuf, " %s", frame->function_type);
+
+ if (frame->function_name)
+ sr_strbuf_append_strf(strbuf, " %s", frame->function_name);
+
+ if (frame->signal_handler_called)
+ sr_strbuf_append_str(strbuf, " <signal handler called>");
+
+ sr_strbuf_append_str(strbuf, "\n");
+}
diff --git a/lib/generic_frame.c b/lib/generic_frame.c
index b3a5f3c..eb644b5 100644
--- a/lib/generic_frame.c
+++ b/lib/generic_frame.c
@@ -23,6 +23,7 @@
#include "report_type.h"
#include "internal_utils.h"
#include "generic_frame.h"
+#include "generic_thread.h"
#include "stacktrace.h"
/* Initialize dispatch table. */
@@ -80,6 +81,14 @@ frame_append_bthash_text(struct sr_frame *frame, enum sr_bthash_flags flags,
(frame, flags, strbuf);
}
+void
+frame_append_duphash_text(struct sr_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf)
+{
+ DISPATCH(dtable, frame->type, frame_append_duphash_text)
+ (frame, flags, strbuf);
+}
+
void sr_frame_free(struct sr_frame *frame)
{
if (!frame)
diff --git a/lib/generic_frame.h b/lib/generic_frame.h
index 7a02bbe..a61626d 100644
--- a/lib/generic_frame.h
+++ b/lib/generic_frame.h
@@ -23,6 +23,7 @@
#include "frame.h"
enum sr_bthash_flags;
+enum sr_duphash_flags;
typedef void (*append_to_str_fn_t)(struct sr_frame *, struct sr_strbuf *);
typedef struct sr_frame* (*next_frame_fn_t)(struct sr_frame *);
@@ -30,6 +31,8 @@ typedef void (*set_next_frame_fn_t)(struct sr_frame *, struct sr_frame *);
typedef int (*frame_cmp_fn_t)(struct sr_frame *, struct sr_frame *);
typedef void (*frame_append_bthash_text_fn_t)(struct sr_frame*, enum sr_bthash_flags,
struct sr_strbuf*);
+typedef void (*frame_append_duphash_text_fn_t)(struct sr_frame*, enum sr_duphash_flags,
+ struct sr_strbuf*);
typedef void (*frame_free_fn_t)(struct sr_frame*);
struct frame_methods
@@ -40,6 +43,7 @@ struct frame_methods
frame_cmp_fn_t cmp;
frame_cmp_fn_t cmp_distance;
frame_append_bthash_text_fn_t frame_append_bthash_text;
+ frame_append_duphash_text_fn_t frame_append_duphash_text;
frame_free_fn_t frame_free;
};
@@ -50,4 +54,8 @@ void
frame_append_bthash_text(struct sr_frame *frame, enum sr_bthash_flags flags,
struct sr_strbuf *strbuf);
+void
+frame_append_duphash_text(struct sr_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf);
+
#endif
diff --git a/lib/generic_thread.c b/lib/generic_thread.c
index 4b17a63..9370159 100644
--- a/lib/generic_thread.c
+++ b/lib/generic_thread.c
@@ -20,12 +20,15 @@
#include "report_type.h"
#include "internal_utils.h"
-#include "frame.h"
-#include "stacktrace.h"
+#include "generic_frame.h"
#include "generic_thread.h"
+#include "stacktrace.h"
+#include "sha1.h"
+#include "strbuf.h"
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
//XXX
/* Note that python and koops do not have multiple threads, thus the functions
@@ -213,3 +216,54 @@ sr_thread_normalize(struct sr_thread *thread)
{
DISPATCH(dtable, thread->type, normalize)(thread);
}
+
+char *
+sr_thread_get_duphash(struct sr_thread *thread, int nframes, char *prefix,
+ enum sr_duphash_flags flags)
+{
+ char *ret;
+ struct sr_strbuf *strbuf = sr_strbuf_new();
+
+ /* Normalization is destructive, we need to make a copy. */
+ thread = sr_thread_dup(thread);
+
+ if (!(flags & SR_DUPHASH_NONORMALIZE))
+ sr_thread_normalize(thread);
+
+ /* User supplied hash text prefix. */
+ if (prefix)
+ sr_strbuf_append_str(strbuf, prefix);
+
+ /* Here would be the place to append thread-specific information. However,
+ * no current problem type has any for duphash. So we just append
+ * "Thread\n" here because that is what btparser does, in order to produce
+ * compatible hashes at least for gdb problems. */
+ /*
+ DISPATCH(dtable, thread->type, thread_append_duphash_text)
+ (thread, flags, strbuf);
+ */
+ sr_strbuf_append_str(strbuf, "Thread\n");
+
+ /* Number of nframes, (almost) not limited if nframes = 0. */
+ if (nframes == 0)
+ nframes = INT_MAX;
+
+ for (struct sr_frame *frame = sr_thread_frames(thread);
+ frame && nframes > 0;
+ frame = sr_frame_next(frame), nframes--)
+ {
+ frame_append_duphash_text(frame, flags, strbuf);
+ }
+
+ if (flags & SR_DUPHASH_NOHASH)
+ ret = sr_strbuf_free_nobuf(strbuf);
+ else
+ {
+ ret = sr_sha1_hash_string(strbuf->buf);
+ sr_strbuf_free(strbuf);
+ }
+
+ sr_thread_free(thread);
+
+ return ret;
+}
diff --git a/lib/java_frame.c b/lib/java_frame.c
index 4e61332..2bea373 100644
--- a/lib/java_frame.c
+++ b/lib/java_frame.c
@@ -24,6 +24,7 @@
#include "utils.h"
#include "json.h"
#include "generic_frame.h"
+#include "thread.h"
#include "stacktrace.h"
#include "internal_utils.h"
#include <string.h>
@@ -37,6 +38,9 @@
static void
java_append_bthash_text(struct sr_java_frame *frame, enum sr_bthash_flags flags,
struct sr_strbuf *strbuf);
+static void
+java_append_duphash_text(struct sr_java_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf);
DEFINE_NEXT_FUNC(java_next, struct sr_frame, struct sr_java_frame)
DEFINE_SET_NEXT_FUNC(java_set_next, struct sr_frame, struct sr_java_frame)
@@ -50,6 +54,8 @@ struct frame_methods java_frame_methods =
.cmp_distance = (frame_cmp_fn_t) sr_java_frame_cmp_distance,
.frame_append_bthash_text =
(frame_append_bthash_text_fn_t) java_append_bthash_text,
+ .frame_append_duphash_text =
+ (frame_append_duphash_text_fn_t) java_append_duphash_text,
.frame_free = (frame_free_fn_t) sr_java_frame_free,
};
@@ -594,3 +600,16 @@ java_append_bthash_text(struct sr_java_frame *frame, enum sr_bthash_flags flags,
frame->is_exception,
OR_UNKNOWN(frame->message));
}
+
+static void
+java_append_duphash_text(struct sr_java_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf)
+{
+ if (frame->name)
+ sr_strbuf_append_strf(strbuf, "%s\n", frame->name);
+ else
+ sr_strbuf_append_strf(strbuf, "%s/%s:%"PRIu32"\n",
+ OR_UNKNOWN(frame->class_path),
+ OR_UNKNOWN(frame->file_name),
+ frame->file_line);
+}
diff --git a/lib/koops_frame.c b/lib/koops_frame.c
index aecd591..1e00a1f 100644
--- a/lib/koops_frame.c
+++ b/lib/koops_frame.c
@@ -22,6 +22,7 @@
#include "strbuf.h"
#include "json.h"
#include "generic_frame.h"
+#include "thread.h"
#include "stacktrace.h"
#include "internal_utils.h"
#include <stdlib.h>
@@ -34,6 +35,9 @@
static void
koops_append_bthash_text(struct sr_koops_frame *frame, enum sr_bthash_flags flags,
struct sr_strbuf *strbuf);
+static void
+koops_append_duphash_text(struct sr_koops_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf);
DEFINE_NEXT_FUNC(koops_next, struct sr_frame, struct sr_koops_frame)
DEFINE_SET_NEXT_FUNC(koops_set_next, struct sr_frame, struct sr_koops_frame)
@@ -47,6 +51,8 @@ struct frame_methods koops_frame_methods =
.cmp_distance = (frame_cmp_fn_t) sr_koops_frame_cmp_distance,
.frame_append_bthash_text =
(frame_append_bthash_text_fn_t) koops_append_bthash_text,
+ .frame_append_duphash_text =
+ (frame_append_duphash_text_fn_t) koops_append_duphash_text,
.frame_free = (frame_free_fn_t) sr_koops_frame_free,
};
@@ -541,3 +547,13 @@ koops_append_bthash_text(struct sr_koops_frame *frame, enum sr_bthash_flags flag
frame->from_function_length,
OR_UNKNOWN(frame->from_module_name));
}
+
+static void
+koops_append_duphash_text(struct sr_koops_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf)
+{
+ if (frame->function_name)
+ sr_strbuf_append_strf(strbuf, "%s\n", frame->function_name);
+ else
+ sr_strbuf_append_strf(strbuf, "0x%"PRIx64"\n", frame->address);
+}
diff --git a/lib/python_frame.c b/lib/python_frame.c
index 4a6a209..07502a1 100644
--- a/lib/python_frame.c
+++ b/lib/python_frame.c
@@ -23,6 +23,7 @@
#include "strbuf.h"
#include "json.h"
#include "generic_frame.h"
+#include "thread.h"
#include "stacktrace.h"
#include "internal_utils.h"
#include <string.h>
@@ -33,6 +34,9 @@
static void
python_append_bthash_text(struct sr_python_frame *frame, enum sr_bthash_flags flags,
struct sr_strbuf *strbuf);
+static void
+python_append_duphash_text(struct sr_python_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf);
DEFINE_NEXT_FUNC(python_next, struct sr_frame, struct sr_python_frame)
DEFINE_SET_NEXT_FUNC(python_set_next, struct sr_frame, struct sr_python_frame)
@@ -46,6 +50,8 @@ struct frame_methods python_frame_methods =
.cmp_distance = (frame_cmp_fn_t) sr_python_frame_cmp_distance,
.frame_append_bthash_text =
(frame_append_bthash_text_fn_t) python_append_bthash_text,
+ .frame_append_duphash_text =
+ (frame_append_duphash_text_fn_t) python_append_duphash_text,
.frame_free = (frame_free_fn_t) sr_python_frame_free,
};
@@ -366,3 +372,13 @@ python_append_bthash_text(struct sr_python_frame *frame, enum sr_bthash_flags fl
frame->special_function,
OR_UNKNOWN(frame->line_contents));
}
+
+static void
+python_append_duphash_text(struct sr_python_frame *frame, enum sr_duphash_flags flags,
+ struct sr_strbuf *strbuf)
+{
+ /* filename:line */
+ sr_strbuf_append_strf(strbuf, "%s:%"PRIu32"\n",
+ OR_UNKNOWN(frame->file_name),
+ frame->file_line);
+}
--
1.7.11.7
More information about the Crash-catcher
mailing list