Related to https://github.com/abrt/satyr/issues/66, duphash implementation will follow.
Martin Milata (3): Higher-level function for SHA1 hashes in hex encoding Implement bthashes python: bindings for bthash
include/stacktrace.h | 22 ++++++++++++++++++ lib/core_fingerprint.c | 10 +------- lib/core_frame.c | 23 +++++++++++++++++++ lib/core_stacktrace.c | 15 ++++++++++++ lib/core_thread.c | 3 +++ lib/gdb_frame.c | 24 +++++++++++++++++++ lib/gdb_stacktrace.c | 21 +++++++++++++++++ lib/gdb_thread.c | 14 ++++++++++++ lib/generic_frame.c | 9 ++++++++ lib/generic_frame.h | 9 ++++++++ lib/generic_stacktrace.c | 43 ++++++++++++++++++++++++++++++++++ lib/generic_stacktrace.h | 4 ++++ lib/generic_thread.c | 16 +++++++++++++ lib/generic_thread.h | 14 ++++++++++++ lib/internal_utils.h | 3 +++ lib/java_frame.c | 22 ++++++++++++++++++ lib/java_stacktrace.c | 9 ++++++++ lib/java_thread.c | 13 +++++++++++ lib/koops_frame.c | 27 ++++++++++++++++++++++ lib/koops_stacktrace.c | 34 +++++++++++++++++++++++++++ lib/python_frame.c | 21 +++++++++++++++++ lib/python_stacktrace.c | 16 +++++++++++++ lib/sha1.c | 16 +++++++++++++ lib/sha1.h | 5 ++++ python/py_base_stacktrace.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ python/py_base_stacktrace.h | 2 ++ python/py_module.c | 4 ++++ tests/python/gdb.py | 3 +++ tests/python/java.py | 2 ++ tests/python/koops.py | 3 +++ tests/python/python.py | 3 +++ 31 files changed, 457 insertions(+), 9 deletions(-)
Signed-off-by: Martin Milata mmilata@redhat.com --- lib/core_fingerprint.c | 10 +--------- lib/sha1.c | 16 ++++++++++++++++ lib/sha1.h | 5 +++++ 3 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/lib/core_fingerprint.c b/lib/core_fingerprint.c index 5e52c30..aeea837 100644 --- a/lib/core_fingerprint.c +++ b/lib/core_fingerprint.c @@ -562,15 +562,7 @@ hash_frame (struct sr_core_frame *frame) if (!frame->fingerprint) return;
- struct sr_sha1_state ctx; - char bin_hash[SR_SHA1_RESULT_BIN_LEN]; - char *hash = sr_malloc(SR_SHA1_RESULT_LEN); - - sr_sha1_begin(&ctx); - sr_sha1_hash(&ctx, frame->fingerprint, strlen(frame->fingerprint)); - sr_sha1_end(&ctx, bin_hash); - sr_bin2hex(hash, bin_hash, sizeof(bin_hash))[0] = '\0'; - + char *hash = sr_sha1_hash_string(frame->fingerprint); free(frame->fingerprint); frame->fingerprint = hash; frame->fingerprint_hashed = true; diff --git a/lib/sha1.c b/lib/sha1.c index 3c781ed..0f21fe8 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -27,6 +27,7 @@ stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor */ #include "sha1.h" +#include "utils.h"
#if defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ # define SHA1_BIG_ENDIAN 1 @@ -236,3 +237,18 @@ common64_end(struct sr_sha1_state *state, bufpos = 0; } } + +char * +sr_sha1_hash_string(const char *str) +{ + struct sr_sha1_state ctx; + char bin_hash[SR_SHA1_RESULT_BIN_LEN]; + char *hex_hash = sr_malloc(SR_SHA1_RESULT_LEN); + + sr_sha1_begin(&ctx); + sr_sha1_hash(&ctx, str, strlen(str)); + sr_sha1_end(&ctx, bin_hash); + sr_bin2hex(hex_hash, bin_hash, sizeof(bin_hash))[0] = '\0'; + + return hex_hash; +} diff --git a/lib/sha1.h b/lib/sha1.h index 6220c15..0a647c8 100644 --- a/lib/sha1.h +++ b/lib/sha1.h @@ -76,6 +76,11 @@ sr_sha1_hash(struct sr_sha1_state *state, void sr_sha1_end(struct sr_sha1_state *state, void *resbuf);
+/* High level function that hashes C string and returns hexadecimal encoding of + * the hash. */ +char * +sr_sha1_hash_string(const char *str); + #ifdef __cplusplus } #endif
BTHASH is computed from (almost) everything that is contained in a stacktrace and therefore should be unique (as much as a hash can be). Related to #66.
Signed-off-by: Martin Milata mmilata@redhat.com --- include/stacktrace.h | 22 ++++++++++++++++++++++ lib/core_frame.c | 23 +++++++++++++++++++++++ lib/core_stacktrace.c | 15 +++++++++++++++ lib/core_thread.c | 3 +++ lib/gdb_frame.c | 24 ++++++++++++++++++++++++ lib/gdb_stacktrace.c | 21 +++++++++++++++++++++ lib/gdb_thread.c | 14 ++++++++++++++ lib/generic_frame.c | 9 +++++++++ lib/generic_frame.h | 9 +++++++++ lib/generic_stacktrace.c | 43 +++++++++++++++++++++++++++++++++++++++++++ lib/generic_stacktrace.h | 4 ++++ lib/generic_thread.c | 16 ++++++++++++++++ lib/generic_thread.h | 14 ++++++++++++++ lib/internal_utils.h | 3 +++ lib/java_frame.c | 22 ++++++++++++++++++++++ lib/java_stacktrace.c | 9 +++++++++ lib/java_thread.c | 13 +++++++++++++ lib/koops_frame.c | 27 +++++++++++++++++++++++++++ lib/koops_stacktrace.c | 34 ++++++++++++++++++++++++++++++++++ lib/python_frame.c | 21 +++++++++++++++++++++ lib/python_stacktrace.c | 16 ++++++++++++++++ 21 files changed, 362 insertions(+)
diff --git a/include/stacktrace.h b/include/stacktrace.h index d16a1a9..d23b32a 100644 --- a/include/stacktrace.h +++ b/include/stacktrace.h @@ -42,6 +42,19 @@ struct sr_stacktrace enum sr_report_type type; };
+/* Flags that influence how the bthash is computed. + */ +enum sr_bthash_flags +{ + /* Default hashing process. + */ + SR_BTHASH_NORMAL = 1 << 0, + + /* Return the plaintext that would be hashed. Useful mainly for debugging. + */ + SR_BTHASH_NOHASH = 1 << 1, +}; + /** * Parses the stacktrace pointed to by input. You need to provide the correct * stacktrace type in the first parameter. @@ -87,6 +100,15 @@ char * sr_stacktrace_get_reason(struct sr_stacktrace *stacktrace);
/** + * Returns hash of a backtrace. This is a hash in the usual sense that the same + * stacktraces always have the same hash while two distinct stacktraces have + * negligible probability of having the same hash. The string is allocated by + * malloc(). + */ +char * +sr_stacktrace_get_bthash(struct sr_stacktrace *stacktrace, enum sr_bthash_flags flags); + +/** * Releases all the memory associated with the stacktrace pointer. */ void diff --git a/lib/core_frame.c b/lib/core_frame.c index 074de56..2833b8a 100644 --- a/lib/core_frame.c +++ b/lib/core_frame.c @@ -22,11 +22,16 @@ #include "strbuf.h" #include "json.h" #include "generic_frame.h" +#include "stacktrace.h" #include "internal_utils.h" #include <string.h>
/* Method table */
+static void +core_append_bthash_text(struct sr_core_frame *frame, enum sr_bthash_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)
@@ -37,6 +42,8 @@ struct frame_methods core_frame_methods = .set_next = (set_next_frame_fn_t) core_set_next, .cmp = (frame_cmp_fn_t) sr_core_frame_cmp, .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, };
/* Public functions */ @@ -404,3 +411,19 @@ sr_core_frame_append_to_str(struct sr_core_frame *frame, sr_strbuf_append_strf(dest, " in %s", frame->file_name); } } + +static void +core_append_bthash_text(struct sr_core_frame *frame, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + if (frame->address) + sr_strbuf_append_strf(strbuf, "0x%"PRIx64", ", frame->address); + else + sr_strbuf_append_str(strbuf, "<unknown>, "); + + sr_strbuf_append_strf(strbuf, "%s+0x%"PRIx64", %s, %s\n", + OR_UNKNOWN(frame->build_id), + frame->build_id_offset, + OR_UNKNOWN(frame->file_name), + OR_UNKNOWN(frame->fingerprint)); +} diff --git a/lib/core_stacktrace.c b/lib/core_stacktrace.c index 172ade2..2b5997c 100644 --- a/lib/core_stacktrace.c +++ b/lib/core_stacktrace.c @@ -40,6 +40,10 @@
/* Method table */
+static void +core_append_bthash_text(struct sr_core_stacktrace *stacktrace, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf); + DEFINE_THREADS_FUNC(core_threads, struct sr_core_stacktrace) DEFINE_SET_THREADS_FUNC(core_set_threads, struct sr_core_stacktrace)
@@ -56,6 +60,8 @@ struct stacktrace_methods core_stacktrace_methods = .threads = (threads_fn_t) core_threads, .set_threads = (set_threads_fn_t) core_set_threads, .free = (free_fn_t) sr_core_stacktrace_free, + .stacktrace_append_bthash_text = + (stacktrace_append_bthash_text_fn_t) core_append_bthash_text, };
/* Public functions */ @@ -393,3 +399,12 @@ sr_core_stacktrace_get_reason(struct sr_core_stacktrace *stacktrace)
return sr_asprintf("Program %s was terminated by signal %"PRIu16, prog, stacktrace->signal); } + +static void +core_append_bthash_text(struct sr_core_stacktrace *stacktrace, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + sr_strbuf_append_strf(strbuf, "Executable: %s\n", OR_UNKNOWN(stacktrace->executable)); + sr_strbuf_append_strf(strbuf, "Signal: %"PRIu16"\n", stacktrace->signal); + sr_strbuf_append_char(strbuf, '\n'); +} diff --git a/lib/core_thread.c b/lib/core_thread.c index dd41a78..5844ce9 100644 --- a/lib/core_thread.c +++ b/lib/core_thread.c @@ -23,6 +23,7 @@ #include "strbuf.h" #include "json.h" #include "generic_thread.h" +#include "stacktrace.h" #include "internal_utils.h" #include <string.h>
@@ -41,6 +42,8 @@ struct thread_methods core_thread_methods = .frame_count = (frame_count_fn_t) thread_frame_count, .next = (next_thread_fn_t) core_next, .set_next = (set_next_thread_fn_t) core_set_next, + .thread_append_bthash_text = + (thread_append_bthash_text_fn_t) thread_no_bthash_text, };
/* Public functions */ diff --git a/lib/gdb_frame.c b/lib/gdb_frame.c index b04dbb7..46acd4d 100644 --- a/lib/gdb_frame.c +++ b/lib/gdb_frame.c @@ -22,14 +22,20 @@ #include "strbuf.h" #include "location.h" #include "generic_frame.h" +#include "stacktrace.h" #include "internal_utils.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdarg.h> +#include <inttypes.h>
/* Method table */
+static void +gdb_append_bthash_text(struct sr_gdb_frame *frame, enum sr_bthash_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)
@@ -46,6 +52,8 @@ struct frame_methods gdb_frame_methods = .set_next = (set_next_frame_fn_t) gdb_set_next, .cmp = (frame_cmp_fn_t) frame_cmp_without_number, .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, };
/* Public functions */ @@ -1114,3 +1122,19 @@ sr_gdb_frame_remove_func_prefix(struct sr_gdb_frame *frame, 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) +{ + sr_strbuf_append_strf(strbuf, + "%s, %s, %" PRIu32 ", %s, %" PRIu32 ", %d, 0x%" PRIx64 ", %s\n", + OR_UNKNOWN(frame->function_name), + OR_UNKNOWN(frame->function_type), + frame->number, + OR_UNKNOWN(frame->source_file), + frame->source_line, + frame->signal_handler_called, + frame->address, + OR_UNKNOWN(frame->library_name)); +} diff --git a/lib/gdb_stacktrace.c b/lib/gdb_stacktrace.c index b77898b..6ccebab 100644 --- a/lib/gdb_stacktrace.c +++ b/lib/gdb_stacktrace.c @@ -34,6 +34,10 @@
/* Method table */
+static void +gdb_append_bthash_text(struct sr_gdb_stacktrace *stacktrace, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf); + /* for not used/implemented methods */ static char * gdb_return_null(struct sr_stacktrace *stacktrace) @@ -57,6 +61,8 @@ struct stacktrace_methods gdb_stacktrace_methods = .threads = (threads_fn_t) gdb_threads, .set_threads = (set_threads_fn_t) gdb_set_threads, .free = (free_fn_t) sr_gdb_stacktrace_free, + .stacktrace_append_bthash_text = + (stacktrace_append_bthash_text_fn_t) gdb_append_bthash_text, };
/* Public functions */ @@ -528,3 +534,18 @@ sr_gdb_stacktrace_to_short_text(struct sr_gdb_stacktrace *stacktrace, sr_gdb_thread_free(optimized_thread); return sr_strbuf_free_nobuf(strbuf); } + +static void +gdb_append_bthash_text(struct sr_gdb_stacktrace *stacktrace, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + for (struct sr_gdb_sharedlib *lib = stacktrace->libs; + lib; + lib = lib->next) + { + sr_strbuf_append_strf(strbuf, "%"PRIx64"-%"PRIx64", %s\n", lib->from, lib->to, + OR_UNKNOWN(lib->soname)); + } + + sr_strbuf_append_char(strbuf, '\n'); +} diff --git a/lib/gdb_thread.c b/lib/gdb_thread.c index b957155..45da010 100644 --- a/lib/gdb_thread.c +++ b/lib/gdb_thread.c @@ -25,6 +25,7 @@ #include "utils.h" #include "strbuf.h" #include "generic_thread.h" +#include "stacktrace.h" #include "internal_utils.h" #include <assert.h> #include <stdlib.h> @@ -32,6 +33,10 @@
/* Method table */
+static void +gdb_append_bthash_text(struct sr_gdb_thread *thread, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf); + DEFINE_FRAMES_FUNC(gdb_frames, struct sr_gdb_thread) DEFINE_SET_FRAMES_FUNC(gdb_set_frames, struct sr_gdb_thread) DEFINE_NEXT_FUNC(gdb_next, struct sr_thread, struct sr_gdb_thread) @@ -45,6 +50,8 @@ struct thread_methods gdb_thread_methods = .frame_count = (frame_count_fn_t) thread_frame_count, .next = (next_thread_fn_t) gdb_next, .set_next = (set_next_thread_fn_t) gdb_set_next, + .thread_append_bthash_text = + (thread_append_bthash_text_fn_t) gdb_append_bthash_text, };
/* Public functions */ @@ -550,3 +557,10 @@ sr_gdb_thread_get_optimized(struct sr_gdb_thread *thread,
return thread; } + +static void +gdb_append_bthash_text(struct sr_gdb_thread *thread, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + sr_strbuf_append_strf(strbuf, "Thread %"PRIu32"\n", thread->number); +} diff --git a/lib/generic_frame.c b/lib/generic_frame.c index fd83bd4..04a8407 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 "stacktrace.h"
/* Initialize dispatch table. */ static struct frame_methods* dtable[SR_REPORT_NUM] = @@ -70,3 +71,11 @@ sr_frame_cmp_distance(struct sr_frame *frame1, struct sr_frame *frame2)
return DISPATCH(dtable, frame1->type, cmp_distance)(frame1, frame2); } + +void +frame_append_bthash_text(struct sr_frame *frame, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + DISPATCH(dtable, frame->type, frame_append_bthash_text) + (frame, flags, strbuf); +} diff --git a/lib/generic_frame.h b/lib/generic_frame.h index e6fdaca..584112e 100644 --- a/lib/generic_frame.h +++ b/lib/generic_frame.h @@ -20,10 +20,14 @@
#include "frame.h"
+enum sr_bthash_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 *); 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*);
struct frame_methods { @@ -32,7 +36,12 @@ struct frame_methods set_next_frame_fn_t set_next; frame_cmp_fn_t cmp; frame_cmp_fn_t cmp_distance; + frame_append_bthash_text_fn_t frame_append_bthash_text; };
extern struct frame_methods core_frame_methods, python_frame_methods, koops_frame_methods, gdb_frame_methods, java_frame_methods; + +void +frame_append_bthash_text(struct sr_frame *frame, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf); diff --git a/lib/generic_stacktrace.c b/lib/generic_stacktrace.c index d7f7ca4..bba7f5f 100644 --- a/lib/generic_stacktrace.c +++ b/lib/generic_stacktrace.c @@ -23,10 +23,13 @@ #include "internal_utils.h" #include "strbuf.h" #include "location.h" +#include "sha1.h"
#include "frame.h" #include "thread.h" #include "generic_stacktrace.h" +#include "generic_thread.h" +#include "generic_frame.h"
/* Initialize dispatch table. */ static struct stacktrace_methods* dtable[SR_REPORT_NUM] = @@ -137,3 +140,43 @@ sr_stacktrace_free(struct sr_stacktrace *stacktrace) { DISPATCH(dtable, stacktrace->type, free)(stacktrace); } + +char * +sr_stacktrace_get_bthash(struct sr_stacktrace *stacktrace, enum sr_bthash_flags flags) +{ + char *ret; + struct sr_strbuf *strbuf = sr_strbuf_new(); + + /* Append data contained in the stacktrace structure. */ + DISPATCH(dtable, stacktrace->type, stacktrace_append_bthash_text) + (stacktrace, flags, strbuf); + + for (struct sr_thread *thread = sr_stacktrace_threads(stacktrace); + thread; + thread = sr_thread_next(thread)) + { + /* Data containted in the thread structure (if any). */ + thread_append_bthash_text(thread, flags, strbuf); + + for (struct sr_frame *frame = sr_thread_frames(thread); + frame; + frame = sr_frame_next(frame)) + { + frame_append_bthash_text(frame, flags, strbuf); + } + + /* Blank line in between threads. */ + if (sr_thread_next(thread)) + sr_strbuf_append_char(strbuf, '\n'); + } + + if (flags & SR_BTHASH_NOHASH) + ret = sr_strbuf_free_nobuf(strbuf); + else + { + ret = sr_sha1_hash_string(strbuf->buf); + sr_strbuf_free(strbuf); + } + + return ret; +} diff --git a/lib/generic_stacktrace.h b/lib/generic_stacktrace.h index bb6ba9f..5615998 100644 --- a/lib/generic_stacktrace.h +++ b/lib/generic_stacktrace.h @@ -20,6 +20,7 @@
#include "stacktrace.h" #include "thread.h" +#include "strbuf.h"
typedef struct sr_stacktrace* (*parse_fn_t)(const char **, char **); typedef struct sr_stacktrace* (*parse_location_fn_t)(const char **, struct sr_location *); @@ -30,6 +31,8 @@ typedef struct sr_thread* (*find_crash_thread_fn_t)(struct sr_stacktrace *); typedef struct sr_thread* (*threads_fn_t)(struct sr_stacktrace *); typedef void (*set_threads_fn_t)(struct sr_stacktrace *, struct sr_thread *); typedef void (*free_fn_t)(struct sr_stacktrace *); +typedef void (*stacktrace_append_bthash_text_fn_t)(struct sr_stacktrace *, enum sr_bthash_flags, + struct sr_strbuf *);
struct stacktrace_methods { @@ -42,6 +45,7 @@ struct stacktrace_methods threads_fn_t threads; set_threads_fn_t set_threads; free_fn_t free; + stacktrace_append_bthash_text_fn_t stacktrace_append_bthash_text; };
extern struct stacktrace_methods core_stacktrace_methods, python_stacktrace_methods, diff --git a/lib/generic_thread.c b/lib/generic_thread.c index 24e590a..b0b3861 100644 --- a/lib/generic_thread.c +++ b/lib/generic_thread.c @@ -21,6 +21,7 @@ #include "report_type.h" #include "internal_utils.h" #include "frame.h" +#include "stacktrace.h" #include "generic_thread.h"
#include <stdio.h> @@ -50,6 +51,13 @@ thread_no_next_thread(struct sr_thread *thread) return NULL; }
+void +thread_no_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + /* nop */ +} + /* Initialize dispatch table. */
/* Table that maps type-specific functions to the corresponding report types. @@ -103,3 +111,11 @@ sr_thread_set_next(struct sr_thread *cur, struct sr_thread *next) assert(next == NULL || cur->type == next->type); DISPATCH(dtable, cur->type, set_next)(cur, next); } + +void +thread_append_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + DISPATCH(dtable, thread->type, thread_append_bthash_text) + (thread, flags, strbuf); +} diff --git a/lib/generic_thread.h b/lib/generic_thread.h index 334994d..6022fb5 100644 --- a/lib/generic_thread.h +++ b/lib/generic_thread.h @@ -21,12 +21,16 @@ #include "thread.h" #include "internal_utils.h"
+enum sr_bthash_flags; + typedef struct sr_frame* (*frames_fn_t)(struct sr_thread*); typedef void (*set_frames_fn_t)(struct sr_thread*, struct sr_frame*); typedef int (*thread_cmp_fn_t)(struct sr_thread*, struct sr_thread*); typedef int (*frame_count_fn_t)(struct sr_thread*); typedef struct sr_thread* (*next_thread_fn_t)(struct sr_thread*); typedef void (*set_next_thread_fn_t)(struct sr_thread*, struct sr_thread*); +typedef void (*thread_append_bthash_text_fn_t)(struct sr_thread*, enum sr_bthash_flags, + struct sr_strbuf*);
struct thread_methods { @@ -36,6 +40,7 @@ struct thread_methods frame_count_fn_t frame_count; next_thread_fn_t next; set_next_thread_fn_t set_next; + thread_append_bthash_text_fn_t thread_append_bthash_text; };
extern struct thread_methods core_thread_methods, python_thread_methods, @@ -53,3 +58,12 @@ thread_frame_count(struct sr_thread *thread);
struct sr_thread * thread_no_next_thread(struct sr_thread *thread); + +void +thread_no_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf); + +/* Uses dispatch table but not intended for public use. */ +void +thread_append_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf); diff --git a/lib/internal_utils.h b/lib/internal_utils.h index a237064..2236f58 100644 --- a/lib/internal_utils.h +++ b/lib/internal_utils.h @@ -40,3 +40,6 @@
#define DEFINE_NEXT_FUNC(name, abstract_t, concrete_t) DEFINE_GETTER(name, next, abstract_t, concrete_t, abstract_t) #define DEFINE_SET_NEXT_FUNC(name, abstract_t, concrete_t) DEFINE_SETTER(name, next, abstract_t, concrete_t, abstract_t) + +/* beware the side effects */ +#define OR_UNKNOWN(s) ((s) ? (s) : "<unknown>") diff --git a/lib/java_frame.c b/lib/java_frame.c index 9477bc9..71881ca 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 "stacktrace.h" #include "internal_utils.h" #include <string.h> #include <inttypes.h> @@ -33,6 +34,10 @@
/* Method table */
+static void +java_append_bthash_text(struct sr_java_frame *frame, enum sr_bthash_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)
@@ -43,6 +48,8 @@ struct frame_methods java_frame_methods = .set_next = (set_next_frame_fn_t) java_set_next, .cmp = (frame_cmp_fn_t) sr_java_frame_cmp, .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, };
/* Public functions */ @@ -571,3 +578,18 @@ sr_java_frame_to_json(struct sr_java_frame *frame) sr_strbuf_append_str(strbuf, "}"); return sr_strbuf_free_nobuf(strbuf); } + +static void +java_append_bthash_text(struct sr_java_frame *frame, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + sr_strbuf_append_strf(strbuf, + "%s, %s, %"PRIu32", %s, %d, %d, %s\n", + OR_UNKNOWN(frame->name), + OR_UNKNOWN(frame->file_name), + frame->file_line, + OR_UNKNOWN(frame->class_path), + frame->is_native, + frame->is_exception, + OR_UNKNOWN(frame->message)); +} diff --git a/lib/java_stacktrace.c b/lib/java_stacktrace.c index b3231e7..d0b9152 100644 --- a/lib/java_stacktrace.c +++ b/lib/java_stacktrace.c @@ -31,6 +31,13 @@
/* Method table */
+static void +java_append_bthash_text(struct sr_java_stacktrace *stacktrace, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + /* nop */ +} + DEFINE_THREADS_FUNC(java_threads, struct sr_java_stacktrace) DEFINE_SET_THREADS_FUNC(java_set_threads, struct sr_java_stacktrace) DEFINE_PARSE_WRAPPER_FUNC(java_parse, SR_REPORT_JAVA) @@ -47,6 +54,8 @@ struct stacktrace_methods java_stacktrace_methods = .threads = (threads_fn_t) java_threads, .set_threads = (set_threads_fn_t) java_set_threads, .free = (free_fn_t) sr_java_stacktrace_free, + .stacktrace_append_bthash_text = + (stacktrace_append_bthash_text_fn_t) java_append_bthash_text, };
/* Public functions */ diff --git a/lib/java_thread.c b/lib/java_thread.c index 70b01b3..c3a697a 100644 --- a/lib/java_thread.c +++ b/lib/java_thread.c @@ -25,6 +25,7 @@ #include "strbuf.h" #include "json.h" #include "generic_thread.h" +#include "stacktrace.h" #include "internal_utils.h" #include <assert.h> #include <stdlib.h> @@ -32,6 +33,10 @@
/* Method table */
+static void +java_append_bthash_text(struct sr_java_thread *thread, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf); + DEFINE_FRAMES_FUNC(java_frames, struct sr_java_thread) DEFINE_SET_FRAMES_FUNC(java_set_frames, struct sr_java_thread) DEFINE_NEXT_FUNC(java_next, struct sr_thread, struct sr_java_thread) @@ -45,6 +50,8 @@ struct thread_methods java_thread_methods = .frame_count = (frame_count_fn_t) thread_frame_count, .next = (next_thread_fn_t) java_next, .set_next = (set_next_thread_fn_t) java_set_next, + .thread_append_bthash_text = + (thread_append_bthash_text_fn_t) java_append_bthash_text, };
/* Public functions */ @@ -394,3 +401,9 @@ sr_java_thread_to_json(struct sr_java_thread *thread) return sr_strbuf_free_nobuf(strbuf); }
+static void +java_append_bthash_text(struct sr_java_thread *thread, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + sr_strbuf_append_strf(strbuf, "Thread %s\n", OR_UNKNOWN(thread->name)); +} diff --git a/lib/koops_frame.c b/lib/koops_frame.c index 2dfdad9..7ae3ece 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 "stacktrace.h" #include "internal_utils.h" #include <stdlib.h> #include <stdio.h> @@ -30,6 +31,10 @@
/* Method table */
+static void +koops_append_bthash_text(struct sr_koops_frame *frame, enum sr_bthash_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)
@@ -40,6 +45,8 @@ struct frame_methods koops_frame_methods = .set_next = (set_next_frame_fn_t) koops_set_next, .cmp = (frame_cmp_fn_t) sr_koops_frame_cmp, .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, };
/* Public functions */ @@ -513,3 +520,23 @@ sr_koops_frame_append_to_str(struct sr_koops_frame *frame, if (frame->module_name) sr_strbuf_append_strf(str, " in %s", frame->module_name); } + +static void +koops_append_bthash_text(struct sr_koops_frame *frame, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + sr_strbuf_append_strf(strbuf, + "0x%"PRIx64", %d, %s, 0x%"PRIx64", 0x%"PRIx64", %s, " + "0x%"PRIx64", %s, 0x%"PRIx64", 0x%"PRIx64", %s\n", + frame->address, + frame->reliable, + OR_UNKNOWN(frame->function_name), + frame->function_offset, + frame->function_length, + OR_UNKNOWN(frame->module_name), + frame->from_address, + OR_UNKNOWN(frame->from_function_name), + frame->from_function_offset, + frame->from_function_length, + OR_UNKNOWN(frame->from_module_name)); +} diff --git a/lib/koops_stacktrace.c b/lib/koops_stacktrace.c index 5ac3fdf..95ae344 100644 --- a/lib/koops_stacktrace.c +++ b/lib/koops_stacktrace.c @@ -56,6 +56,10 @@ struct sr_taint_flag sr_flags[] = {
/* Method tables */
+static void +koops_append_bthash_text(struct sr_koops_stacktrace *stacktrace, + enum sr_bthash_flags flags, struct sr_strbuf *strbuf); + DEFINE_FRAMES_FUNC(koops_frames, struct sr_koops_stacktrace) DEFINE_SET_FRAMES_FUNC(koops_set_frames, struct sr_koops_stacktrace) DEFINE_PARSE_WRAPPER_FUNC(koops_parse, SR_REPORT_KERNELOOPS) @@ -68,6 +72,7 @@ struct thread_methods koops_thread_methods = .frame_count = (frame_count_fn_t) thread_frame_count, .next = (next_thread_fn_t) thread_no_next_thread, .set_next = (set_next_thread_fn_t) NULL, + .thread_append_bthash_text = (thread_append_bthash_text_fn_t) thread_no_bthash_text, };
struct stacktrace_methods koops_stacktrace_methods = @@ -81,6 +86,8 @@ struct stacktrace_methods koops_stacktrace_methods = .threads = (threads_fn_t) stacktrace_one_thread_only, .set_threads = (set_threads_fn_t) NULL, .free = (free_fn_t) sr_koops_stacktrace_free, + .stacktrace_append_bthash_text = + (stacktrace_append_bthash_text_fn_t) koops_append_bthash_text, };
/* Public functions */ @@ -525,3 +532,30 @@ sr_koops_stacktrace_get_reason(struct sr_koops_stacktrace *stacktrace)
return result; } + +static void +koops_append_bthash_text(struct sr_koops_stacktrace *stacktrace, + enum sr_bthash_flags flags, struct sr_strbuf *strbuf) +{ + sr_strbuf_append_strf(strbuf, "Version: %s\n", OR_UNKNOWN(stacktrace->version)); + + sr_strbuf_append_str(strbuf, "Flags: "); + for (struct sr_taint_flag *f = sr_flags; f->letter; f++) + { + bool val = *(bool *)((void *)stacktrace + f->member_offset); + if (val == false) + continue; + } + sr_strbuf_append_char(strbuf, '\n'); + + sr_strbuf_append_str(strbuf, "Modules: "); + for (char **mod = stacktrace->modules; mod && *mod; mod++) + { + sr_strbuf_append_str(strbuf, *mod); + if (*(mod+1)) + sr_strbuf_append_str(strbuf, ", "); + } + sr_strbuf_append_char(strbuf, '\n'); + + sr_strbuf_append_char(strbuf, '\n'); +} diff --git a/lib/python_frame.c b/lib/python_frame.c index 077c391..8ac4b90 100644 --- a/lib/python_frame.c +++ b/lib/python_frame.c @@ -23,12 +23,17 @@ #include "strbuf.h" #include "json.h" #include "generic_frame.h" +#include "stacktrace.h" #include "internal_utils.h" #include <string.h> #include <inttypes.h>
/* Method table */
+static void +python_append_bthash_text(struct sr_python_frame *frame, enum sr_bthash_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)
@@ -39,6 +44,8 @@ struct frame_methods python_frame_methods = .set_next = (set_next_frame_fn_t) python_set_next, .cmp = (frame_cmp_fn_t) sr_python_frame_cmp, .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, };
/* Public functions */ @@ -344,3 +351,17 @@ sr_python_frame_append_to_str(struct sr_python_frame *frame, } } } + +static void +python_append_bthash_text(struct sr_python_frame *frame, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + sr_strbuf_append_strf(strbuf, + "%s, %d, %"PRIu32", %s, %d, %s\n", + OR_UNKNOWN(frame->file_name), + frame->special_file, + frame->file_line, + OR_UNKNOWN(frame->function_name), + frame->special_function, + OR_UNKNOWN(frame->line_contents)); +} diff --git a/lib/python_stacktrace.c b/lib/python_stacktrace.c index 3c1d030..300bd0b 100644 --- a/lib/python_stacktrace.c +++ b/lib/python_stacktrace.c @@ -34,6 +34,10 @@
/* Method tables */
+static void +python_append_bthash_text(struct sr_python_stacktrace *stacktrace, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf); + DEFINE_FRAMES_FUNC(python_frames, struct sr_python_stacktrace) DEFINE_SET_FRAMES_FUNC(python_set_frames, struct sr_python_stacktrace) DEFINE_PARSE_WRAPPER_FUNC(python_parse, SR_REPORT_PYTHON) @@ -46,6 +50,8 @@ struct thread_methods python_thread_methods = .frame_count = (frame_count_fn_t) thread_frame_count, .next = (next_thread_fn_t) thread_no_next_thread, .set_next = (set_next_thread_fn_t) NULL, + .thread_append_bthash_text = + (thread_append_bthash_text_fn_t) thread_no_bthash_text, };
struct stacktrace_methods python_stacktrace_methods = @@ -59,6 +65,8 @@ struct stacktrace_methods python_stacktrace_methods = .threads = (threads_fn_t) stacktrace_one_thread_only, .set_threads = (set_threads_fn_t) NULL, .free = (free_fn_t) sr_python_stacktrace_free, + .stacktrace_append_bthash_text = + (stacktrace_append_bthash_text_fn_t) python_append_bthash_text, };
/* Public functions */ @@ -236,3 +244,11 @@ sr_python_stacktrace_get_reason(struct sr_python_stacktrace *stacktrace)
return sr_asprintf("%s in %s:%"PRIu32, exc, file, line); } + +static void +python_append_bthash_text(struct sr_python_stacktrace *stacktrace, enum sr_bthash_flags flags, + struct sr_strbuf *strbuf) +{ + sr_strbuf_append_strf(strbuf, "Exception: %s\n", OR_UNKNOWN(stacktrace->exception_name)); + sr_strbuf_append_char(strbuf, '\n'); +}
Signed-off-by: Martin Milata mmilata@redhat.com --- python/py_base_stacktrace.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ python/py_base_stacktrace.h | 2 ++ python/py_module.c | 4 ++++ tests/python/gdb.py | 3 +++ tests/python/java.py | 2 ++ tests/python/koops.py | 3 +++ tests/python/python.py | 3 +++ 7 files changed, 73 insertions(+)
diff --git a/python/py_base_stacktrace.c b/python/py_base_stacktrace.c index c729335..5739e3c 100644 --- a/python/py_base_stacktrace.c +++ b/python/py_base_stacktrace.c @@ -31,12 +31,17 @@ "Returns short text representation of the stacktrace. If max_frames is\n" \ "specified, the result includes only that much topmost frames.\n"
+#define get_bthash_doc "Usage: stacktrace.get_bthash([flags])\n" \ + "Returns: string - hash of the stacktrace\n" \ + "flags: integer - bitwise sum of flags (BTHASH_NORMAL, BTHASH_NOHASH)" + #define threads_doc "A list containing the objects representing threads in the stacktrace."
static PyMethodDef single_methods[] = { { "to_short_text", sr_py_single_stacktrace_to_short_text, METH_VARARGS, to_short_text_doc }, + { "get_bthash", sr_py_single_stacktrace_get_bthash, METH_VARARGS, get_bthash_doc }, { NULL }, };
@@ -100,6 +105,7 @@ static PyMethodDef multi_methods[] = { { "to_short_text", sr_py_multi_stacktrace_to_short_text, METH_VARARGS, to_short_text_doc }, + { "get_bthash", sr_py_multi_stacktrace_get_bthash, METH_VARARGS, get_bthash_doc }, { NULL }, };
@@ -291,3 +297,53 @@ sr_py_multi_stacktrace_to_short_text(PyObject *self, PyObject *args) free(text); return result; } + +/* TODO: these two functions (and the two above) are almost the same - there + * should be a way to not repeat the code */ +PyObject * +sr_py_single_stacktrace_get_bthash(PyObject *self, PyObject *args) +{ + int flags = 0; + if (!PyArg_ParseTuple(args, "|i", &flags)) + return NULL; + + struct sr_py_base_thread *this = + (struct sr_py_base_thread *)self; + if (frames_prepare_linked_list(this) < 0) + return NULL; + + char *hash = sr_stacktrace_get_bthash((struct sr_stacktrace *)this->thread, flags); + if (!hash) + { + PyErr_SetString(PyExc_RuntimeError, "cannot obtain bthash"); + return NULL; + } + + PyObject *result = PyString_FromString(hash); + free(hash); + return result; +} + +PyObject * +sr_py_multi_stacktrace_get_bthash(PyObject *self, PyObject *args) +{ + int flags = 0; + if (!PyArg_ParseTuple(args, "|i", &flags)) + return NULL; + + struct sr_py_multi_stacktrace *this = + (struct sr_py_multi_stacktrace *)self; + if (threads_prepare_linked_list(this) < 0) + return NULL; + + char *hash = sr_stacktrace_get_bthash((struct sr_stacktrace *)this->stacktrace, flags); + if (!hash) + { + PyErr_SetString(PyExc_RuntimeError, "cannot obtain bthash"); + return NULL; + } + + PyObject *result = PyString_FromString(hash); + free(hash); + return result; +} diff --git a/python/py_base_stacktrace.h b/python/py_base_stacktrace.h index a0d5e65..6b12fa4 100644 --- a/python/py_base_stacktrace.h +++ b/python/py_base_stacktrace.h @@ -56,6 +56,8 @@ PyObject *threads_to_python_list(struct sr_stacktrace *stacktrace, /* methods */ PyObject *sr_py_single_stacktrace_to_short_text(PyObject *self, PyObject *args); PyObject *sr_py_multi_stacktrace_to_short_text(PyObject *self, PyObject *args); +PyObject *sr_py_single_stacktrace_get_bthash(PyObject *self, PyObject *args); +PyObject *sr_py_multi_stacktrace_get_bthash(PyObject *self, PyObject *args);
#ifdef __cplusplus } diff --git a/python/py_module.c b/python/py_module.c index 8fb77cc..36c4e0f 100644 --- a/python/py_module.c +++ b/python/py_module.c @@ -17,6 +17,7 @@ #include "py_metrics.h"
#include "distance.h" +#include "stacktrace.h" #include "gdb/sharedlib.h"
static PyMethodDef @@ -158,6 +159,9 @@ init_satyr() PyModule_AddObject(module, "MultiThreadStacktrace", (PyObject *)&sr_py_multi_stacktrace_type);
+ PyModule_AddIntConstant(module, "BTHASH_NORMAL", SR_BTHASH_NORMAL); + PyModule_AddIntConstant(module, "BTHASH_NOHASH", SR_BTHASH_NOHASH); + Py_INCREF(&sr_py_gdb_frame_type); PyModule_AddObject(module, "GdbFrame", (PyObject *)&sr_py_gdb_frame_type); diff --git a/tests/python/gdb.py b/tests/python/gdb.py index 6e57c17..06565b4 100755 --- a/tests/python/gdb.py +++ b/tests/python/gdb.py @@ -61,6 +61,9 @@ class TestGdbStacktrace(BindingsTestCase): def test_to_short_text(self): self.assertEqual(self.trace.to_short_text(5), expected_short_text)
+ def test_bthash(self): + self.assertEqual(self.trace.get_bthash(), 'd0fcdc87161ccb093f7efeff12218321d8fd5298') + class TestGdbThread(BindingsTestCase): def setUp(self): self.thread = satyr.GdbStacktrace(contents).threads[0] diff --git a/tests/python/java.py b/tests/python/java.py index 1c7fc5f..dfd5eb0 100755 --- a/tests/python/java.py +++ b/tests/python/java.py @@ -57,6 +57,8 @@ class TestJavaStacktrace(BindingsTestCase): def test_to_short_text(self): self.assertEqual(self.trace.to_short_text(8), expected_short_text)
+ def test_bthash(self): + self.assertEqual(self.trace.get_bthash(), '184370433901aa9f14bfc85c29576e24ebca2c2e')
class TestJavaThread(BindingsTestCase): def setUp(self): diff --git a/tests/python/koops.py b/tests/python/koops.py index 81e67b9..10cba82 100755 --- a/tests/python/koops.py +++ b/tests/python/koops.py @@ -67,6 +67,9 @@ class TestKerneloops(BindingsTestCase): def test_to_short_text(self): self.assertEqual(self.koops.to_short_text(7), expected_short_text)
+ def test_bthash(self): + self.assertEqual(self.koops.get_bthash(), '73c7ce83d5ba90a1acbcc7915a62595914321f97') + class TestKoopsFrame(BindingsTestCase): def setUp(self): self.frame = satyr.Kerneloops(contents).frames[0] diff --git a/tests/python/python.py b/tests/python/python.py index 1ae36eb..0421935 100755 --- a/tests/python/python.py +++ b/tests/python/python.py @@ -84,6 +84,9 @@ class TestPythonStacktrace(BindingsTestCase): def test_to_short_text(self): self.assertEqual(self.trace.to_short_text(6), expected_short_text)
+ def test_bthash(self): + self.assertEqual(self.trace.get_bthash(), 'fa0a7ff4b65f18661a6ce102eb787ff0d77ff12f') + class TestPythonFrame(BindingsTestCase): def setUp(self): self.frame = satyr.PythonStacktrace(contents).frames[-1]
Signed-off-by: Martin Milata mmilata@redhat.com --- include/koops/stacktrace.h | 9 --------- lib/internal_utils.h | 10 ++++++++++ python/py_koops_stacktrace.c | 1 + 3 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/include/koops/stacktrace.h b/include/koops/stacktrace.h index 580610f..4aa545e 100644 --- a/include/koops/stacktrace.h +++ b/include/koops/stacktrace.h @@ -160,15 +160,6 @@ char * sr_koops_stacktrace_to_json(struct sr_koops_stacktrace *stacktrace);
-/* TODO: this needs to go in a _private_ header and should not be exported */ -struct sr_taint_flag -{ - char letter; - size_t member_offset; - char *name; -}; -extern struct sr_taint_flag sr_flags[]; - #ifdef __cplusplus } #endif diff --git a/lib/internal_utils.h b/lib/internal_utils.h index 2236f58..7a2d2cf 100644 --- a/lib/internal_utils.h +++ b/lib/internal_utils.h @@ -18,6 +18,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+#include <stddef.h> #include <assert.h>
#define DISPATCH(table, type, method) \ @@ -43,3 +44,12 @@
/* beware the side effects */ #define OR_UNKNOWN(s) ((s) ? (s) : "<unknown>") + +/* kerneloops taint flag structure and global table declaration */ +struct sr_taint_flag +{ + char letter; + size_t member_offset; + char *name; +}; +extern struct sr_taint_flag sr_flags[]; diff --git a/python/py_koops_stacktrace.c b/python/py_koops_stacktrace.c index 97a38ef..c748721 100644 --- a/python/py_koops_stacktrace.c +++ b/python/py_koops_stacktrace.c @@ -8,6 +8,7 @@ #include "location.h" #include "normalize.h" #include "stacktrace.h" +#include "internal_utils.h"
#define stacktrace_doc "satyr.Kerneloops - class representing a kerneloops stacktrace\n" \ "Usage:\n" \
Signed-off-by: Martin Milata mmilata@redhat.com --- lib/generic_frame.h | 4 ++++ lib/generic_stacktrace.h | 4 ++++ lib/generic_thread.h | 4 ++++ lib/internal_utils.h | 4 ++++ 4 files changed, 16 insertions(+)
diff --git a/lib/generic_frame.h b/lib/generic_frame.h index 584112e..69f1fa8 100644 --- a/lib/generic_frame.h +++ b/lib/generic_frame.h @@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifndef SATYR_GENERIC_FRAME_H +#define SATYR_GENERIC_FRAME_H
#include "frame.h"
@@ -45,3 +47,5 @@ extern struct frame_methods core_frame_methods, python_frame_methods, void frame_append_bthash_text(struct sr_frame *frame, enum sr_bthash_flags flags, struct sr_strbuf *strbuf); + +#endif diff --git a/lib/generic_stacktrace.h b/lib/generic_stacktrace.h index 5615998..829b680 100644 --- a/lib/generic_stacktrace.h +++ b/lib/generic_stacktrace.h @@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifndef SATYR_GENERIC_STACKTRACE_H +#define SATYR_GENERIC_STACKTRACE_H
#include "stacktrace.h" #include "thread.h" @@ -74,3 +76,5 @@ stacktrace_to_short_text(struct sr_stacktrace *stacktrace, int max_frames);
struct sr_thread * stacktrace_one_thread_only(struct sr_stacktrace *stacktrace); + +#endif diff --git a/lib/generic_thread.h b/lib/generic_thread.h index 6022fb5..d3232d6 100644 --- a/lib/generic_thread.h +++ b/lib/generic_thread.h @@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifndef SATYR_GENERIC_THREAD_H +#define SATYR_GENERIC_THREAD_H
#include "thread.h" #include "internal_utils.h" @@ -67,3 +69,5 @@ thread_no_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, void thread_append_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, struct sr_strbuf *strbuf); + +#endif diff --git a/lib/internal_utils.h b/lib/internal_utils.h index 7a2d2cf..faa42be 100644 --- a/lib/internal_utils.h +++ b/lib/internal_utils.h @@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifndef SATYR_INTERNAL_UTILS_H +#define SATYR_INTERNAL_UTILS_H
#include <stddef.h> #include <assert.h> @@ -53,3 +55,5 @@ struct sr_taint_flag char *name; }; extern struct sr_taint_flag sr_flags[]; + +#endif
Signed-off-by: Martin Milata mmilata@redhat.com --- include/utils.h | 7 +++++++ lib/core_fingerprint.c | 10 ++-------- lib/normalize.c | 8 +------- lib/utils.c | 6 ++++++ 4 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/include/utils.h b/include/utils.h index 68e763b..5684620 100644 --- a/include/utils.h +++ b/include/utils.h @@ -106,6 +106,13 @@ int sr_strcmp0(const char *s1, const char *s2);
/** + * A wrapper around sr_strcmp0 that takes pointers to strings. Can be used as a + * paramter to qsort or bsearch. + */ +int +sr_ptrstrcmp(const void *s1, const void *s2); + +/** * A strchr() variant providing line and column in the string s * indicating where the char c was found. * @param line diff --git a/lib/core_fingerprint.c b/lib/core_fingerprint.c index aeea837..af33a93 100644 --- a/lib/core_fingerprint.c +++ b/lib/core_fingerprint.c @@ -280,12 +280,6 @@ get_libcalls(char ***symbol_list, return true; }
-static int -strcmp_wrapper(const char **s1, const char **s2) -{ - return strcmp(*s1, *s2); -} - static bool fp_libcalls(struct sr_strbuf *fingerprint, uint64_t function_start_address, @@ -310,7 +304,7 @@ fp_libcalls(struct sr_strbuf *fingerprint, return false;
qsort(symbol_list, symbol_list_size, - sizeof(char*), (comparison_fn_t)strcmp_wrapper); + sizeof(char*), (comparison_fn_t)sr_ptrstrcmp);
/* Make it unique. */ sr_struniq(symbol_list, &symbol_list_size); @@ -349,7 +343,7 @@ fp_calltree_leaves(struct sr_strbuf *fingerprint, return false;
qsort(symbol_list, symbol_list_size, - sizeof(char*), (comparison_fn_t)strcmp_wrapper); + sizeof(char*), (comparison_fn_t)sr_ptrstrcmp);
/* Make it unique. */ sr_struniq(symbol_list, &symbol_list_size); diff --git a/lib/normalize.c b/lib/normalize.c index 9582a5f..7cd8144 100644 --- a/lib/normalize.c +++ b/lib/normalize.c @@ -380,12 +380,6 @@ sr_normalize_gdb_stacktrace(struct sr_gdb_stacktrace *stacktrace) } }
-static int -ptrstrcmp(const void *s1, const void *s2) -{ - return sr_strcmp0(*(const char**)s1, *(const char**)s2); -} - void sr_normalize_koops_stacktrace(struct sr_koops_stacktrace *stacktrace) { @@ -433,7 +427,7 @@ sr_normalize_koops_stacktrace(struct sr_koops_stacktrace *stacktrace) blacklist, sizeof(blacklist) / sizeof(blacklist[0]), sizeof(blacklist[0]), - ptrstrcmp); + sr_ptrstrcmp);
/* do not drop frames belonging to a module */ if (!frame->module_name && in_blacklist) diff --git a/lib/utils.c b/lib/utils.c index 1b9d982..ac56c7e 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -157,6 +157,12 @@ sr_strcmp0(const char *s1, const char *s2) return s2 ? -1 : 0; }
+int +sr_ptrstrcmp(const void *s1, const void *s2) +{ + return sr_strcmp0(*(const char**)s1, *(const char**)s2); +} + char * sr_strchr_location(const char *s, int c, int *line, int *column) {
The gdb normalization is left in normalize.c as some of the code/data may be shared with core normalization when it is implemented.
Signed-off-by: Martin Milata mmilata@redhat.com --- include/koops/stacktrace.h | 3 +++ include/normalize.h | 7 ------ lib/koops_stacktrace.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ lib/normalize.c | 62 ---------------------------------------------- 4 files changed, 63 insertions(+), 69 deletions(-)
diff --git a/include/koops/stacktrace.h b/include/koops/stacktrace.h index 4aa545e..9d76cab 100644 --- a/include/koops/stacktrace.h +++ b/include/koops/stacktrace.h @@ -159,6 +159,9 @@ sr_koops_stacktrace_get_reason(struct sr_koops_stacktrace *stacktrace); char * sr_koops_stacktrace_to_json(struct sr_koops_stacktrace *stacktrace);
+void +sr_normalize_koops_stacktrace(struct sr_koops_stacktrace *stacktrace); +
#ifdef __cplusplus } diff --git a/include/normalize.h b/include/normalize.h index c93595f..a595cb9 100644 --- a/include/normalize.h +++ b/include/normalize.h @@ -36,10 +36,6 @@ extern "C" { struct sr_gdb_frame; struct sr_gdb_thread; struct sr_gdb_stacktrace; -struct sr_core_frame; -struct sr_core_thread; -struct sr_core_stacktrace; -struct sr_koops_stacktrace;
void sr_normalize_gdb_thread(struct sr_gdb_thread *thread); @@ -47,9 +43,6 @@ sr_normalize_gdb_thread(struct sr_gdb_thread *thread); void sr_normalize_gdb_stacktrace(struct sr_gdb_stacktrace *stacktrace);
-void -sr_normalize_koops_stacktrace(struct sr_koops_stacktrace *stacktrace); - // TODO: move to gdb_stacktrace.h /** * Checks whether the thread it contains some function used to exit diff --git a/lib/koops_stacktrace.c b/lib/koops_stacktrace.c index 95ae344..0533034 100644 --- a/lib/koops_stacktrace.c +++ b/lib/koops_stacktrace.c @@ -559,3 +559,63 @@ koops_append_bthash_text(struct sr_koops_stacktrace *stacktrace,
sr_strbuf_append_char(strbuf, '\n'); } + +void +sr_normalize_koops_stacktrace(struct sr_koops_stacktrace *stacktrace) +{ + /* Normalize function names by removing the suffixes identified by + * the dot character. + */ + struct sr_koops_frame *frame = stacktrace->frames; + while (frame) + { + if (frame->function_name) + { + char *dot = strchr(frame->function_name, '.'); + if (dot) + *dot = '\0'; + } + + frame = frame->next; + } + + /* Remove blacklisted frames. */ + /* !!! MUST BE SORTED !!! */ + const char *blacklist[] = { + "do_softirq", + "do_vfs_ioctl", + "flush_kthread_worker", + "gs_change", + "irq_exit", + "kernel_thread_helper", + "kthread", + "process_one_work", + "system_call_fastpath", + "warn_slowpath_common", + "warn_slowpath_fmt", + "warn_slowpath_fmt_taint", + "warn_slowpath_null", + "worker_thread" + }; + + frame = stacktrace->frames; + while (frame) + { + struct sr_koops_frame *next_frame = frame->next; + + bool in_blacklist = bsearch(&frame->function_name, + blacklist, + sizeof(blacklist) / sizeof(blacklist[0]), + sizeof(blacklist[0]), + sr_ptrstrcmp); + + /* do not drop frames belonging to a module */ + if (!frame->module_name && in_blacklist) + { + bool success = sr_koops_stacktrace_remove_frame(stacktrace, frame); + assert(success || !"failed to remove frame"); + } + + frame = next_frame; + } +} diff --git a/lib/normalize.c b/lib/normalize.c index 7cd8144..6a8c351 100644 --- a/lib/normalize.c +++ b/lib/normalize.c @@ -21,8 +21,6 @@ #include "gdb/frame.h" #include "gdb/thread.h" #include "gdb/stacktrace.h" -#include "koops/frame.h" -#include "koops/stacktrace.h" #include "utils.h" #include <string.h> #include <assert.h> @@ -380,66 +378,6 @@ sr_normalize_gdb_stacktrace(struct sr_gdb_stacktrace *stacktrace) } }
-void -sr_normalize_koops_stacktrace(struct sr_koops_stacktrace *stacktrace) -{ - /* Normalize function names by removing the suffixes identified by - * the dot character. - */ - struct sr_koops_frame *frame = stacktrace->frames; - while (frame) - { - if (frame->function_name) - { - char *dot = strchr(frame->function_name, '.'); - if (dot) - *dot = '\0'; - } - - frame = frame->next; - } - - /* Remove blacklisted frames. */ - /* !!! MUST BE SORTED !!! */ - const char *blacklist[] = { - "do_softirq", - "do_vfs_ioctl", - "flush_kthread_worker", - "gs_change", - "irq_exit", - "kernel_thread_helper", - "kthread", - "process_one_work", - "system_call_fastpath", - "warn_slowpath_common", - "warn_slowpath_fmt", - "warn_slowpath_fmt_taint", - "warn_slowpath_null", - "worker_thread" - }; - - frame = stacktrace->frames; - while (frame) - { - struct sr_koops_frame *next_frame = frame->next; - - bool in_blacklist = bsearch(&frame->function_name, - blacklist, - sizeof(blacklist) / sizeof(blacklist[0]), - sizeof(blacklist[0]), - sr_ptrstrcmp); - - /* do not drop frames belonging to a module */ - if (!frame->module_name && in_blacklist) - { - bool success = sr_koops_stacktrace_remove_frame(stacktrace, frame); - assert(success || !"failed to remove frame"); - } - - frame = next_frame; - } -} - static bool next_functions_similar(struct sr_gdb_frame *frame1, struct sr_gdb_frame *frame2)
Signed-off-by: Martin Milata mmilata@redhat.com --- include/frame.h | 3 ++ include/thread.h | 37 ++++++++++++++++++++++ lib/core_frame.c | 1 + lib/core_stacktrace.c | 2 +- lib/core_thread.c | 6 ++++ lib/gdb_frame.c | 1 + lib/gdb_stacktrace.c | 2 +- lib/gdb_thread.c | 6 ++++ lib/generic_frame.c | 8 +++++ lib/generic_frame.h | 2 ++ lib/generic_stacktrace.c | 5 ++- lib/generic_stacktrace.h | 4 +-- lib/generic_thread.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/generic_thread.h | 22 +++++++++++++ lib/java_frame.c | 1 + lib/java_stacktrace.c | 2 +- lib/java_thread.c | 6 ++++ lib/koops_frame.c | 1 + lib/koops_stacktrace.c | 7 ++++- lib/python_frame.c | 1 + lib/python_stacktrace.c | 7 ++++- 21 files changed, 198 insertions(+), 8 deletions(-)
diff --git a/include/frame.h b/include/frame.h index 706522a..db8ea98 100644 --- a/include/frame.h +++ b/include/frame.h @@ -77,6 +77,9 @@ sr_frame_cmp(struct sr_frame *t1, struct sr_frame *t2); int sr_frame_cmp_distance(struct sr_frame *t1, struct sr_frame *t2);
+void +sr_frame_free(struct sr_frame *frame); + #ifdef __cplusplus } #endif diff --git a/include/thread.h b/include/thread.h index 1f39c2a..56bf1b5 100644 --- a/include/thread.h +++ b/include/thread.h @@ -37,6 +37,8 @@ extern "C" { #endif
+#include <stdbool.h> + #include "report_type.h"
struct sr_thread @@ -81,6 +83,41 @@ sr_thread_next(struct sr_thread *thread); void sr_thread_set_next(struct sr_thread *cur, struct sr_thread *next);
+/** + * Releases the memory held by the thread. The thread siblings are not + * released. + * @param thread + * If thread is NULL, no operation is performed. + */ +void +sr_thread_free(struct sr_thread *thread); + +/** + * Removes the frame from the thread and then deletes it. + * @returns + * True if the frame was found in the thread and removed and deleted. + * False if the frame was not found in the thread. + */ +bool +sr_thread_remove_frame(struct sr_thread *thread, struct sr_frame *frame); + +/** + * Removes all the frames from the thread that are above certain + * frame. + * @returns + * True if the frame was found, and all the frames that were above the + * frame in the thread were removed from the thread and then deleted. + * False if the frame was not found in the thread. + */ +bool +sr_thread_remove_frames_above(struct sr_thread *thread, struct sr_frame *frame); + +/** + * Return a copy of the thread (without its siblings). + */ +struct sr_thread * +sr_thread_dup(struct sr_thread *thread); + #ifdef __cplusplus } #endif diff --git a/lib/core_frame.c b/lib/core_frame.c index 2833b8a..4ae8e8c 100644 --- a/lib/core_frame.c +++ b/lib/core_frame.c @@ -44,6 +44,7 @@ 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_free = (frame_free_fn_t) sr_core_frame_free, };
/* Public functions */ diff --git a/lib/core_stacktrace.c b/lib/core_stacktrace.c index 2b5997c..ff34221 100644 --- a/lib/core_stacktrace.c +++ b/lib/core_stacktrace.c @@ -59,7 +59,7 @@ struct stacktrace_methods core_stacktrace_methods = (find_crash_thread_fn_t) sr_core_stacktrace_find_crash_thread, .threads = (threads_fn_t) core_threads, .set_threads = (set_threads_fn_t) core_set_threads, - .free = (free_fn_t) sr_core_stacktrace_free, + .stacktrace_free = (stacktrace_free_fn_t) sr_core_stacktrace_free, .stacktrace_append_bthash_text = (stacktrace_append_bthash_text_fn_t) core_append_bthash_text, }; diff --git a/lib/core_thread.c b/lib/core_thread.c index 5844ce9..d6e62b2 100644 --- a/lib/core_thread.c +++ b/lib/core_thread.c @@ -33,6 +33,7 @@ DEFINE_FRAMES_FUNC(core_frames, struct sr_core_thread) DEFINE_SET_FRAMES_FUNC(core_set_frames, struct sr_core_thread) DEFINE_NEXT_FUNC(core_next, struct sr_thread, struct sr_core_thread) DEFINE_SET_NEXT_FUNC(core_set_next, struct sr_thread, struct sr_core_thread) +DEFINE_DUP_WRAPPER_FUNC(core_dup, struct sr_core_thread, sr_core_thread_dup)
struct thread_methods core_thread_methods = { @@ -44,6 +45,11 @@ struct thread_methods core_thread_methods = .set_next = (set_next_thread_fn_t) core_set_next, .thread_append_bthash_text = (thread_append_bthash_text_fn_t) thread_no_bthash_text, + .thread_free = (thread_free_fn_t) sr_core_thread_free, + .remove_frame = (remove_frame_fn_t) thread_remove_frame, + .remove_frames_above = + (remove_frames_above_fn_t) thread_remove_frames_above, + .thread_dup = (thread_dup_fn_t) core_dup, };
/* Public functions */ diff --git a/lib/gdb_frame.c b/lib/gdb_frame.c index 46acd4d..6deb1a3 100644 --- a/lib/gdb_frame.c +++ b/lib/gdb_frame.c @@ -54,6 +54,7 @@ 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_free = (frame_free_fn_t) sr_gdb_frame_free, };
/* Public functions */ diff --git a/lib/gdb_stacktrace.c b/lib/gdb_stacktrace.c index 6ccebab..9950c69 100644 --- a/lib/gdb_stacktrace.c +++ b/lib/gdb_stacktrace.c @@ -60,7 +60,7 @@ struct stacktrace_methods gdb_stacktrace_methods = (find_crash_thread_fn_t) sr_gdb_stacktrace_find_crash_thread, .threads = (threads_fn_t) gdb_threads, .set_threads = (set_threads_fn_t) gdb_set_threads, - .free = (free_fn_t) sr_gdb_stacktrace_free, + .stacktrace_free = (stacktrace_free_fn_t) sr_gdb_stacktrace_free, .stacktrace_append_bthash_text = (stacktrace_append_bthash_text_fn_t) gdb_append_bthash_text, }; diff --git a/lib/gdb_thread.c b/lib/gdb_thread.c index 45da010..dc34320 100644 --- a/lib/gdb_thread.c +++ b/lib/gdb_thread.c @@ -41,6 +41,7 @@ DEFINE_FRAMES_FUNC(gdb_frames, struct sr_gdb_thread) DEFINE_SET_FRAMES_FUNC(gdb_set_frames, struct sr_gdb_thread) DEFINE_NEXT_FUNC(gdb_next, struct sr_thread, struct sr_gdb_thread) DEFINE_SET_NEXT_FUNC(gdb_set_next, struct sr_thread, struct sr_gdb_thread) +DEFINE_DUP_WRAPPER_FUNC(gdb_dup, struct sr_gdb_thread, sr_gdb_thread_dup)
struct thread_methods gdb_thread_methods = { @@ -52,6 +53,11 @@ struct thread_methods gdb_thread_methods = .set_next = (set_next_thread_fn_t) gdb_set_next, .thread_append_bthash_text = (thread_append_bthash_text_fn_t) gdb_append_bthash_text, + .thread_free = (thread_free_fn_t) sr_gdb_thread_free, + .remove_frame = (remove_frame_fn_t) thread_remove_frame, + .remove_frames_above = + (remove_frames_above_fn_t) thread_remove_frames_above, + .thread_dup = (thread_dup_fn_t) gdb_dup, };
/* Public functions */ diff --git a/lib/generic_frame.c b/lib/generic_frame.c index 04a8407..b3a5f3c 100644 --- a/lib/generic_frame.c +++ b/lib/generic_frame.c @@ -79,3 +79,11 @@ frame_append_bthash_text(struct sr_frame *frame, enum sr_bthash_flags flags, DISPATCH(dtable, frame->type, frame_append_bthash_text) (frame, flags, strbuf); } + +void sr_frame_free(struct sr_frame *frame) +{ + if (!frame) + return; + + DISPATCH(dtable, frame->type, frame_free)(frame); +} diff --git a/lib/generic_frame.h b/lib/generic_frame.h index 69f1fa8..7a02bbe 100644 --- a/lib/generic_frame.h +++ b/lib/generic_frame.h @@ -30,6 +30,7 @@ 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_free_fn_t)(struct sr_frame*);
struct frame_methods { @@ -39,6 +40,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_free_fn_t frame_free; };
extern struct frame_methods core_frame_methods, python_frame_methods, diff --git a/lib/generic_stacktrace.c b/lib/generic_stacktrace.c index bba7f5f..de393e4 100644 --- a/lib/generic_stacktrace.c +++ b/lib/generic_stacktrace.c @@ -138,7 +138,10 @@ sr_stacktrace_set_threads(struct sr_stacktrace *stacktrace, struct sr_thread *th void sr_stacktrace_free(struct sr_stacktrace *stacktrace) { - DISPATCH(dtable, stacktrace->type, free)(stacktrace); + if (!stacktrace) + return; + + DISPATCH(dtable, stacktrace->type, stacktrace_free)(stacktrace); }
char * diff --git a/lib/generic_stacktrace.h b/lib/generic_stacktrace.h index 829b680..f08bdfc 100644 --- a/lib/generic_stacktrace.h +++ b/lib/generic_stacktrace.h @@ -32,7 +32,7 @@ typedef char* (*get_reason_fn_t)(struct sr_stacktrace *); typedef struct sr_thread* (*find_crash_thread_fn_t)(struct sr_stacktrace *); typedef struct sr_thread* (*threads_fn_t)(struct sr_stacktrace *); typedef void (*set_threads_fn_t)(struct sr_stacktrace *, struct sr_thread *); -typedef void (*free_fn_t)(struct sr_stacktrace *); +typedef void (*stacktrace_free_fn_t)(struct sr_stacktrace *); typedef void (*stacktrace_append_bthash_text_fn_t)(struct sr_stacktrace *, enum sr_bthash_flags, struct sr_strbuf *);
@@ -46,7 +46,7 @@ struct stacktrace_methods find_crash_thread_fn_t find_crash_thread; threads_fn_t threads; set_threads_fn_t set_threads; - free_fn_t free; + stacktrace_free_fn_t stacktrace_free; stacktrace_append_bthash_text_fn_t stacktrace_append_bthash_text; };
diff --git a/lib/generic_thread.c b/lib/generic_thread.c index b0b3861..c9ff98a 100644 --- a/lib/generic_thread.c +++ b/lib/generic_thread.c @@ -45,6 +45,59 @@ thread_frame_count(struct sr_thread *thread) return count; }
+bool +thread_remove_frame(struct sr_thread *thread, struct sr_frame *frame) +{ + struct sr_frame *loop_frame = sr_thread_frames(thread), + *prev_frame = NULL; + + while (loop_frame) + { + if (loop_frame == frame) + { + if (prev_frame) + sr_frame_set_next(prev_frame, sr_frame_next(loop_frame)); + else + sr_thread_set_frames(thread, sr_frame_next(loop_frame)); + + sr_frame_free(loop_frame); + return true; + } + + prev_frame = loop_frame; + loop_frame = sr_frame_next(loop_frame); + } + + return false; +} + +bool +thread_remove_frames_above(struct sr_thread *thread, struct sr_frame *frame) +{ + /* Check that the frame is present in the thread. */ + struct sr_frame *loop_frame = sr_thread_frames(thread); + while (loop_frame) + { + if (loop_frame == frame) + break; + + loop_frame = sr_frame_next(loop_frame); + } + + if (!loop_frame) + return false; + + /* Delete all the frames up to the frame. */ + while (sr_thread_frames(thread) != frame) + { + loop_frame = sr_frame_next(sr_thread_frames(thread)); + sr_frame_free(sr_thread_frames(thread)); + sr_thread_set_frames(thread, loop_frame); + } + + return true; +} + struct sr_thread * thread_no_next_thread(struct sr_thread *thread) { @@ -119,3 +172,32 @@ thread_append_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, DISPATCH(dtable, thread->type, thread_append_bthash_text) (thread, flags, strbuf); } + +void +sr_thread_free(struct sr_thread *thread) +{ + if (!thread) + return; + + DISPATCH(dtable, thread->type, thread_free)(thread); +} + +bool +sr_thread_remove_frame(struct sr_thread *thread, struct sr_frame *frame) +{ + assert(thread->type == frame->type); + return DISPATCH(dtable, thread->type, remove_frame)(thread, frame); +} + +bool +sr_thread_remove_frames_above(struct sr_thread *thread, struct sr_frame *frame) +{ + assert(thread->type == frame->type); + return DISPATCH(dtable, thread->type, remove_frames_above)(thread, frame); +} + +struct sr_thread* +sr_thread_dup(struct sr_thread *thread) +{ + return DISPATCH(dtable, thread->type, thread_dup)(thread); +} diff --git a/lib/generic_thread.h b/lib/generic_thread.h index d3232d6..3914212 100644 --- a/lib/generic_thread.h +++ b/lib/generic_thread.h @@ -33,6 +33,10 @@ typedef struct sr_thread* (*next_thread_fn_t)(struct sr_thread*); typedef void (*set_next_thread_fn_t)(struct sr_thread*, struct sr_thread*); typedef void (*thread_append_bthash_text_fn_t)(struct sr_thread*, enum sr_bthash_flags, struct sr_strbuf*); +typedef void (*thread_free_fn_t)(struct sr_thread*); +typedef bool (*remove_frame_fn_t)(struct sr_thread*, struct sr_frame*); +typedef bool (*remove_frames_above_fn_t)(struct sr_thread*, struct sr_frame*); +typedef struct sr_thread* (*thread_dup_fn_t)(struct sr_thread*);
struct thread_methods { @@ -43,6 +47,10 @@ struct thread_methods next_thread_fn_t next; set_next_thread_fn_t set_next; thread_append_bthash_text_fn_t thread_append_bthash_text; + thread_free_fn_t thread_free; + remove_frame_fn_t remove_frame; + remove_frames_above_fn_t remove_frames_above; + thread_dup_fn_t thread_dup; };
extern struct thread_methods core_thread_methods, python_thread_methods, @@ -55,9 +63,23 @@ extern struct thread_methods core_thread_methods, python_thread_methods, #define DEFINE_SET_FRAMES_FUNC(name, concrete_t) \ DEFINE_SETTER(name, frames, struct sr_thread, concrete_t, struct sr_frame)
+/* _dup wrapper for thread fucntions that accept 'sibling' argument */ +#define DEFINE_DUP_WRAPPER_FUNC(name, concrete_t, wrappee) \ + static concrete_t * \ + name(concrete_t *thread) \ + { \ + return wrappee(thread, false); \ + } + int thread_frame_count(struct sr_thread *thread);
+bool +thread_remove_frame(struct sr_thread *thread, struct sr_frame *frame); + +bool +thread_remove_frames_above(struct sr_thread *thread, struct sr_frame *frame); + struct sr_thread * thread_no_next_thread(struct sr_thread *thread);
diff --git a/lib/java_frame.c b/lib/java_frame.c index 71881ca..4e61332 100644 --- a/lib/java_frame.c +++ b/lib/java_frame.c @@ -50,6 +50,7 @@ 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_free = (frame_free_fn_t) sr_java_frame_free, };
/* Public functions */ diff --git a/lib/java_stacktrace.c b/lib/java_stacktrace.c index d0b9152..f8ef874 100644 --- a/lib/java_stacktrace.c +++ b/lib/java_stacktrace.c @@ -53,7 +53,7 @@ struct stacktrace_methods java_stacktrace_methods = (find_crash_thread_fn_t) sr_java_find_crash_thread, .threads = (threads_fn_t) java_threads, .set_threads = (set_threads_fn_t) java_set_threads, - .free = (free_fn_t) sr_java_stacktrace_free, + .stacktrace_free = (stacktrace_free_fn_t) sr_java_stacktrace_free, .stacktrace_append_bthash_text = (stacktrace_append_bthash_text_fn_t) java_append_bthash_text, }; diff --git a/lib/java_thread.c b/lib/java_thread.c index c3a697a..644ac34 100644 --- a/lib/java_thread.c +++ b/lib/java_thread.c @@ -41,6 +41,7 @@ DEFINE_FRAMES_FUNC(java_frames, struct sr_java_thread) DEFINE_SET_FRAMES_FUNC(java_set_frames, struct sr_java_thread) DEFINE_NEXT_FUNC(java_next, struct sr_thread, struct sr_java_thread) DEFINE_SET_NEXT_FUNC(java_set_next, struct sr_thread, struct sr_java_thread) +DEFINE_DUP_WRAPPER_FUNC(java_dup, struct sr_java_thread, sr_java_thread_dup)
struct thread_methods java_thread_methods = { @@ -52,6 +53,11 @@ struct thread_methods java_thread_methods = .set_next = (set_next_thread_fn_t) java_set_next, .thread_append_bthash_text = (thread_append_bthash_text_fn_t) java_append_bthash_text, + .thread_free = (thread_free_fn_t) sr_java_thread_free, + .remove_frame = (remove_frame_fn_t) thread_remove_frame, + .remove_frames_above = + (remove_frames_above_fn_t) thread_remove_frames_above, + .thread_dup = (thread_dup_fn_t) java_dup, };
/* Public functions */ diff --git a/lib/koops_frame.c b/lib/koops_frame.c index 7ae3ece..aecd591 100644 --- a/lib/koops_frame.c +++ b/lib/koops_frame.c @@ -47,6 +47,7 @@ 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_free = (frame_free_fn_t) sr_koops_frame_free, };
/* Public functions */ diff --git a/lib/koops_stacktrace.c b/lib/koops_stacktrace.c index 0533034..ab62598 100644 --- a/lib/koops_stacktrace.c +++ b/lib/koops_stacktrace.c @@ -73,6 +73,11 @@ struct thread_methods koops_thread_methods = .next = (next_thread_fn_t) thread_no_next_thread, .set_next = (set_next_thread_fn_t) NULL, .thread_append_bthash_text = (thread_append_bthash_text_fn_t) thread_no_bthash_text, + .thread_free = (thread_free_fn_t) sr_koops_stacktrace_free, + .remove_frame = (remove_frame_fn_t) thread_remove_frame, + .remove_frames_above = + (remove_frames_above_fn_t) thread_remove_frames_above, + .thread_dup = (thread_dup_fn_t) sr_koops_stacktrace_dup, };
struct stacktrace_methods koops_stacktrace_methods = @@ -85,7 +90,7 @@ struct stacktrace_methods koops_stacktrace_methods = .find_crash_thread = (find_crash_thread_fn_t) stacktrace_one_thread_only, .threads = (threads_fn_t) stacktrace_one_thread_only, .set_threads = (set_threads_fn_t) NULL, - .free = (free_fn_t) sr_koops_stacktrace_free, + .stacktrace_free = (stacktrace_free_fn_t) sr_koops_stacktrace_free, .stacktrace_append_bthash_text = (stacktrace_append_bthash_text_fn_t) koops_append_bthash_text, }; diff --git a/lib/python_frame.c b/lib/python_frame.c index 8ac4b90..4a6a209 100644 --- a/lib/python_frame.c +++ b/lib/python_frame.c @@ -46,6 +46,7 @@ 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_free = (frame_free_fn_t) sr_python_frame_free, };
/* Public functions */ diff --git a/lib/python_stacktrace.c b/lib/python_stacktrace.c index 300bd0b..15bb41c 100644 --- a/lib/python_stacktrace.c +++ b/lib/python_stacktrace.c @@ -52,6 +52,11 @@ struct thread_methods python_thread_methods = .set_next = (set_next_thread_fn_t) NULL, .thread_append_bthash_text = (thread_append_bthash_text_fn_t) thread_no_bthash_text, + .thread_free = (thread_free_fn_t) sr_python_stacktrace_free, + .remove_frame = (remove_frame_fn_t) thread_remove_frame, + .remove_frames_above = + (remove_frames_above_fn_t) thread_remove_frames_above, + .thread_dup = (thread_dup_fn_t) sr_python_stacktrace_dup, };
struct stacktrace_methods python_stacktrace_methods = @@ -64,7 +69,7 @@ struct stacktrace_methods python_stacktrace_methods = .find_crash_thread = (find_crash_thread_fn_t) stacktrace_one_thread_only, .threads = (threads_fn_t) stacktrace_one_thread_only, .set_threads = (set_threads_fn_t) NULL, - .free = (free_fn_t) sr_python_stacktrace_free, + .stacktrace_free = (stacktrace_free_fn_t) sr_python_stacktrace_free, .stacktrace_append_bthash_text = (stacktrace_append_bthash_text_fn_t) python_append_bthash_text, };
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@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;
Signed-off-by: Martin Milata mmilata@redhat.com --- include/thread.h | 7 +++++++ lib/core_thread.c | 2 ++ lib/gdb_thread.c | 1 + lib/generic_thread.c | 12 ++++++++++++ lib/generic_thread.h | 5 +++++ lib/java_thread.c | 1 + lib/koops_stacktrace.c | 1 + lib/python_stacktrace.c | 1 + 8 files changed, 30 insertions(+)
diff --git a/include/thread.h b/include/thread.h index 56bf1b5..c62c08f 100644 --- a/include/thread.h +++ b/include/thread.h @@ -118,6 +118,13 @@ sr_thread_remove_frames_above(struct sr_thread *thread, struct sr_frame *frame); struct sr_thread * sr_thread_dup(struct sr_thread *thread);
+/** + * Normalizes thread for deduplication/clustering. The normalization consists + * of removing useless frames and changing names of others. + */ +void +sr_thread_normalize(struct sr_thread *thread); + #ifdef __cplusplus } #endif diff --git a/lib/core_thread.c b/lib/core_thread.c index d6e62b2..fc5f9e7 100644 --- a/lib/core_thread.c +++ b/lib/core_thread.c @@ -25,6 +25,7 @@ #include "generic_thread.h" #include "stacktrace.h" #include "internal_utils.h" +#include "normalize.h" #include <string.h>
/* Method table */ @@ -50,6 +51,7 @@ struct thread_methods core_thread_methods = .remove_frames_above = (remove_frames_above_fn_t) thread_remove_frames_above, .thread_dup = (thread_dup_fn_t) core_dup, + .normalize = (normalize_fn_t) sr_normalize_core_thread, };
/* Public functions */ diff --git a/lib/gdb_thread.c b/lib/gdb_thread.c index dc34320..ec08609 100644 --- a/lib/gdb_thread.c +++ b/lib/gdb_thread.c @@ -58,6 +58,7 @@ struct thread_methods gdb_thread_methods = .remove_frames_above = (remove_frames_above_fn_t) thread_remove_frames_above, .thread_dup = (thread_dup_fn_t) gdb_dup, + .normalize = (normalize_fn_t) sr_normalize_gdb_thread, };
/* Public functions */ diff --git a/lib/generic_thread.c b/lib/generic_thread.c index c9ff98a..4b17a63 100644 --- a/lib/generic_thread.c +++ b/lib/generic_thread.c @@ -111,6 +111,12 @@ thread_no_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, /* nop */ }
+void +thread_no_normalization(struct sr_thread *thread) +{ + /* nop */ +} + /* Initialize dispatch table. */
/* Table that maps type-specific functions to the corresponding report types. @@ -201,3 +207,9 @@ sr_thread_dup(struct sr_thread *thread) { return DISPATCH(dtable, thread->type, thread_dup)(thread); } + +void +sr_thread_normalize(struct sr_thread *thread) +{ + DISPATCH(dtable, thread->type, normalize)(thread); +} diff --git a/lib/generic_thread.h b/lib/generic_thread.h index 3914212..005e5ac 100644 --- a/lib/generic_thread.h +++ b/lib/generic_thread.h @@ -34,6 +34,7 @@ typedef void (*set_next_thread_fn_t)(struct sr_thread*, struct sr_thread*); typedef void (*thread_append_bthash_text_fn_t)(struct sr_thread*, enum sr_bthash_flags, struct sr_strbuf*); typedef void (*thread_free_fn_t)(struct sr_thread*); +typedef void (*normalize_fn_t)(struct sr_thread*); typedef bool (*remove_frame_fn_t)(struct sr_thread*, struct sr_frame*); typedef bool (*remove_frames_above_fn_t)(struct sr_thread*, struct sr_frame*); typedef struct sr_thread* (*thread_dup_fn_t)(struct sr_thread*); @@ -48,6 +49,7 @@ struct thread_methods set_next_thread_fn_t set_next; thread_append_bthash_text_fn_t thread_append_bthash_text; thread_free_fn_t thread_free; + normalize_fn_t normalize; remove_frame_fn_t remove_frame; remove_frames_above_fn_t remove_frames_above; thread_dup_fn_t thread_dup; @@ -87,6 +89,9 @@ void thread_no_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, struct sr_strbuf *strbuf);
+void +thread_no_normalization(struct sr_thread *thread); + /* Uses dispatch table but not intended for public use. */ void thread_append_bthash_text(struct sr_thread *thread, enum sr_bthash_flags flags, diff --git a/lib/java_thread.c b/lib/java_thread.c index 644ac34..9f6145d 100644 --- a/lib/java_thread.c +++ b/lib/java_thread.c @@ -58,6 +58,7 @@ struct thread_methods java_thread_methods = .remove_frames_above = (remove_frames_above_fn_t) thread_remove_frames_above, .thread_dup = (thread_dup_fn_t) java_dup, + .normalize = (normalize_fn_t) thread_no_normalization, };
/* Public functions */ diff --git a/lib/koops_stacktrace.c b/lib/koops_stacktrace.c index ab62598..4ba74db 100644 --- a/lib/koops_stacktrace.c +++ b/lib/koops_stacktrace.c @@ -78,6 +78,7 @@ struct thread_methods koops_thread_methods = .remove_frames_above = (remove_frames_above_fn_t) thread_remove_frames_above, .thread_dup = (thread_dup_fn_t) sr_koops_stacktrace_dup, + .normalize = (normalize_fn_t) sr_normalize_koops_stacktrace, };
struct stacktrace_methods koops_stacktrace_methods = diff --git a/lib/python_stacktrace.c b/lib/python_stacktrace.c index 15bb41c..b7c69cf 100644 --- a/lib/python_stacktrace.c +++ b/lib/python_stacktrace.c @@ -57,6 +57,7 @@ struct thread_methods python_thread_methods = .remove_frames_above = (remove_frames_above_fn_t) thread_remove_frames_above, .thread_dup = (thread_dup_fn_t) sr_python_stacktrace_dup, + .normalize = (normalize_fn_t) thread_no_normalization, };
struct stacktrace_methods python_stacktrace_methods =
Related to #66.
Signed-off-by: Martin Milata mmilata@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); +}
Closes #66.
Signed-off-by: Martin Milata mmilata@redhat.com --- python/py_base_thread.c | 39 ++++++++++++++++++++++++++++++++++++++- python/py_base_thread.h | 1 + python/py_module.c | 5 +++++ tests/python/gdb.py | 5 +++++ tests/python/java.py | 9 +++++++++ tests/python/koops.py | 5 +++++ tests/python/python.py | 9 +++++++++ 7 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/python/py_base_thread.c b/python/py_base_thread.c index 8053878..5bbbade 100644 --- a/python/py_base_thread.c +++ b/python/py_base_thread.c @@ -34,11 +34,19 @@ " DISTANCE_JACCARD or DISTANCE_DAMERAU_LEVENSHTEIN\n"\ "Returns: positive float - distance between the two threads"
+#define get_duphash_doc "Usage: thread.get_duphash(frames=0, flags=DUPHASH_NORMAL, prefix='')\n"\ + "Returns: string - thread's duplication hash\n"\ + "frames: integer - number of frames to use (default 0 means use all)\n"\ + "flags: integer - bitwise sum of flags (DUPHASH_NORMAL, DUPHASH_NOHASH,\n"\ + " DUPHASH_NONORMALIZE)\n"\ + "prefix: string - string to be prepended in front of the text before hashing" + static PyMethodDef thread_methods[] = { /* methods */ - { "distance", (PyCFunction)sr_py_base_thread_distance, METH_VARARGS|METH_KEYWORDS, distance_doc }, + { "distance", (PyCFunction)sr_py_base_thread_distance, METH_VARARGS|METH_KEYWORDS, distance_doc }, + { "get_duphash", (PyCFunction)sr_py_base_thread_get_duphash, METH_VARARGS|METH_KEYWORDS, get_duphash_doc }, { NULL }, };
@@ -242,3 +250,32 @@ sr_py_base_thread_distance(PyObject *self, PyObject *args, PyObject *kwds) float dist = sr_distance(dist_type, t1->thread, t2->thread); return PyFloat_FromDouble((double)dist); } + +PyObject * +sr_py_base_thread_get_duphash(PyObject *self, PyObject *args, PyObject *kwds) +{ + const char *prefix = NULL; + int frames = 0, flags = 0; + + static const char *kwlist[] = { "frames", "flags", "prefix", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iis", (char **)kwlist, + &frames, &flags, &prefix)) + return NULL; + + struct sr_py_base_thread *this = + (struct sr_py_base_thread *)self; + if (frames_prepare_linked_list(this) < 0) + return NULL; + + char *hash = sr_thread_get_duphash((struct sr_thread *)this->thread, + frames, (char *)prefix, flags); + if (!hash) + { + PyErr_SetString(PyExc_RuntimeError, "cannot obtain duphash"); + return NULL; + } + + PyObject *result = PyString_FromString(hash); + free(hash); + return result; +} diff --git a/python/py_base_thread.h b/python/py_base_thread.h index 663555c..e9f1af7 100644 --- a/python/py_base_thread.h +++ b/python/py_base_thread.h @@ -51,6 +51,7 @@ int sr_py_base_thread_cmp(struct sr_py_base_thread *self, struct sr_py_base_thre
/* methods */ PyObject *sr_py_base_thread_distance(PyObject *self, PyObject *args, PyObject *kwds); +PyObject *sr_py_base_thread_get_duphash(PyObject *self, PyObject *args, PyObject *kwds);
#ifdef __cplusplus } diff --git a/python/py_module.c b/python/py_module.c index 36c4e0f..f049a03 100644 --- a/python/py_module.c +++ b/python/py_module.c @@ -17,6 +17,7 @@ #include "py_metrics.h"
#include "distance.h" +#include "thread.h" #include "stacktrace.h" #include "gdb/sharedlib.h"
@@ -151,6 +152,10 @@ init_satyr() PyModule_AddObject(module, "BaseThread", (PyObject *)&sr_py_base_thread_type);
+ PyModule_AddIntConstant(module, "DUPHASH_NORMAL", SR_DUPHASH_NORMAL); + PyModule_AddIntConstant(module, "DUPHASH_NOHASH", SR_DUPHASH_NOHASH); + PyModule_AddIntConstant(module, "DUPHASH_NONORMALIZE", SR_DUPHASH_NONORMALIZE); + Py_INCREF(&sr_py_single_stacktrace_type); PyModule_AddObject(module, "SingleThreadStacktrace", (PyObject *)&sr_py_single_stacktrace_type); diff --git a/tests/python/gdb.py b/tests/python/gdb.py index 06565b4..2752771 100755 --- a/tests/python/gdb.py +++ b/tests/python/gdb.py @@ -78,6 +78,11 @@ class TestGdbThread(BindingsTestCase): dup.number = 9000 self.assertNotEqual(self.thread, dup)
+ def test_duphash(self): + expected_plain = 'Thread\n write\n virNetSocketWriteWire\n virNetSocketWrite\n' + self.assertEqual(self.thread.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain) + self.assertEqual(self.thread.get_duphash(), '4ff2e92d89425e18e82b94c214c7ccfec8b31793') + class TestGdbSharedlib(BindingsTestCase): def setUp(self): self.shlib = satyr.GdbStacktrace(contents).libs[0] diff --git a/tests/python/java.py b/tests/python/java.py index dfd5eb0..eaa3d48 100755 --- a/tests/python/java.py +++ b/tests/python/java.py @@ -74,6 +74,15 @@ class TestJavaThread(BindingsTestCase): dup.name = ' 45678987\n\n\n\n' self.assertNotEqual(self.thread, dup)
+ def test_duphash(self): + expected_plain = '''Thread +org.hibernate.exception.ConstraintViolationException +org.hibernate.exception.SQLStateConverter.convert +org.hibernate.exception.JDBCExceptionHelper.convert +''' + self.assertEqual(self.thread.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain) + self.assertEqual(self.thread.get_duphash(), '81450a80a9d9307624b08e80dc244beb63d91138') + class TestJavaSharedlib(BindingsTestCase): def setUp(self): self.shlib = satyr.JavaStacktrace(contents).libs[0] diff --git a/tests/python/koops.py b/tests/python/koops.py index 10cba82..f1de360 100755 --- a/tests/python/koops.py +++ b/tests/python/koops.py @@ -70,6 +70,11 @@ class TestKerneloops(BindingsTestCase): def test_bthash(self): self.assertEqual(self.koops.get_bthash(), '73c7ce83d5ba90a1acbcc7915a62595914321f97')
+ def test_duphash(self): + expected_plain = 'Thread\n__alloc_pages_nodemask\nip_copy_metadata\nip_forward_options\n' + self.assertEqual(self.koops.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain) + self.assertEqual(self.koops.get_duphash(), '53f62f9d6f7de093f50653863d200f4789ace7ef') + class TestKoopsFrame(BindingsTestCase): def setUp(self): self.frame = satyr.Kerneloops(contents).frames[0] diff --git a/tests/python/python.py b/tests/python/python.py index 0421935..1fcd49d 100755 --- a/tests/python/python.py +++ b/tests/python/python.py @@ -87,6 +87,15 @@ class TestPythonStacktrace(BindingsTestCase): def test_bthash(self): self.assertEqual(self.trace.get_bthash(), 'fa0a7ff4b65f18661a6ce102eb787ff0d77ff12f')
+ def test_duphash(self): + expected_plain = '''Thread +/usr/share/PackageKit/helpers/yum/yumBackend.py:2534 +/usr/share/PackageKit/helpers/yum/yumBackend.py:2593 +/usr/share/PackageKit/helpers/yum/yumBackend.py:2551 +''' + self.assertEqual(self.trace.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain) + self.assertEqual(self.trace.get_duphash(), '2c8e509a33966a08df1dd8b2348e850d1bc5b776') + class TestPythonFrame(BindingsTestCase): def setUp(self): self.frame = satyr.PythonStacktrace(contents).frames[-1]
Looks alright, pushed.
On Wed, 2013-06-26 at 22:14 +0200, Martin Milata wrote:
Signed-off-by: Martin Milata mmilata@redhat.com
include/koops/stacktrace.h | 9 --------- lib/internal_utils.h | 10 ++++++++++ python/py_koops_stacktrace.c | 1 + 3 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/include/koops/stacktrace.h b/include/koops/stacktrace.h index 580610f..4aa545e 100644 --- a/include/koops/stacktrace.h +++ b/include/koops/stacktrace.h @@ -160,15 +160,6 @@ char * sr_koops_stacktrace_to_json(struct sr_koops_stacktrace *stacktrace);
-/* TODO: this needs to go in a _private_ header and should not be exported */ -struct sr_taint_flag -{
- char letter;
- size_t member_offset;
- char *name;
-}; -extern struct sr_taint_flag sr_flags[];
#ifdef __cplusplus } #endif diff --git a/lib/internal_utils.h b/lib/internal_utils.h index 2236f58..7a2d2cf 100644 --- a/lib/internal_utils.h +++ b/lib/internal_utils.h @@ -18,6 +18,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+#include <stddef.h> #include <assert.h>
#define DISPATCH(table, type, method) \ @@ -43,3 +44,12 @@
/* beware the side effects */ #define OR_UNKNOWN(s) ((s) ? (s) : "<unknown>")
+/* kerneloops taint flag structure and global table declaration */ +struct sr_taint_flag +{
- char letter;
- size_t member_offset;
- char *name;
+}; +extern struct sr_taint_flag sr_flags[]; diff --git a/python/py_koops_stacktrace.c b/python/py_koops_stacktrace.c index 97a38ef..c748721 100644 --- a/python/py_koops_stacktrace.c +++ b/python/py_koops_stacktrace.c @@ -8,6 +8,7 @@ #include "location.h" #include "normalize.h" #include "stacktrace.h" +#include "internal_utils.h"
#define stacktrace_doc "satyr.Kerneloops - class representing a kerneloops stacktrace\n" \ "Usage:\n" \
I don't see anything wrong in this patch set :) Pushed.
On Wed, 2013-06-26 at 16:13 +0200, Martin Milata wrote:
Related to https://github.com/abrt/satyr/issues/66, duphash implementation will follow.
Martin Milata (3): Higher-level function for SHA1 hashes in hex encoding Implement bthashes python: bindings for bthash
include/stacktrace.h | 22 ++++++++++++++++++ lib/core_fingerprint.c | 10 +------- lib/core_frame.c | 23 +++++++++++++++++++ lib/core_stacktrace.c | 15 ++++++++++++ lib/core_thread.c | 3 +++ lib/gdb_frame.c | 24 +++++++++++++++++++ lib/gdb_stacktrace.c | 21 +++++++++++++++++ lib/gdb_thread.c | 14 ++++++++++++ lib/generic_frame.c | 9 ++++++++ lib/generic_frame.h | 9 ++++++++ lib/generic_stacktrace.c | 43 ++++++++++++++++++++++++++++++++++ lib/generic_stacktrace.h | 4 ++++ lib/generic_thread.c | 16 +++++++++++++ lib/generic_thread.h | 14 ++++++++++++ lib/internal_utils.h | 3 +++ lib/java_frame.c | 22 ++++++++++++++++++ lib/java_stacktrace.c | 9 ++++++++ lib/java_thread.c | 13 +++++++++++ lib/koops_frame.c | 27 ++++++++++++++++++++++ lib/koops_stacktrace.c | 34 +++++++++++++++++++++++++++ lib/python_frame.c | 21 +++++++++++++++++ lib/python_stacktrace.c | 16 +++++++++++++ lib/sha1.c | 16 +++++++++++++ lib/sha1.h | 5 ++++ python/py_base_stacktrace.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ python/py_base_stacktrace.h | 2 ++ python/py_module.c | 4 ++++ tests/python/gdb.py | 3 +++ tests/python/java.py | 2 ++ tests/python/koops.py | 3 +++ tests/python/python.py | 3 +++ 31 files changed, 457 insertions(+), 9 deletions(-)
crash-catcher@lists.fedorahosted.org