[SATYR PATCHv2 5/9] Add type-agnostic API

Martin Milata mmilata at redhat.com
Tue May 28 17:33:42 UTC 2013


Type-agnostic API means that we expose several functions that operate on
frames (or threads or stacktraces) regardless of their problem type.
This is accomplished by looking at the type member of each structure
(introduced in previous patch) and using it to look up the right
function for the type.

Furthermore, the implementations of the type-agnostic functions can
themselves work on multiple structure types, which can prevent some code
duplication.

A sr_stacktrace_to_short_text function is provided as an example,
closing #64. Related to #63 and related to #66 as the requested
functionality should be easier to implement now.

Signed-off-by: Martin Milata <mmilata at redhat.com>
---
 lib/Makefile.am  |   8 ++-
 lib/frame.c      |  90 ++++++++++++++++++++++++
 lib/frame.h      |  64 +++++++++++++++++
 lib/stacktrace.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/stacktrace.h |  87 +++++++++++++++++++++++
 lib/thread.c     | 128 +++++++++++++++++++++++++++++++++
 lib/thread.h     |  70 +++++++++++++++++++
 lib/utils.h      |  12 ++++
 8 files changed, 668 insertions(+), 1 deletion(-)
 create mode 100644 lib/frame.c
 create mode 100644 lib/frame.h
 create mode 100644 lib/stacktrace.c
 create mode 100644 lib/stacktrace.h
 create mode 100644 lib/thread.c
 create mode 100644 lib/thread.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
index 192b0e1..1024e32 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -33,6 +33,9 @@ pkginclude_HEADERS = \
 	strbuf.h \
 	unstrip.h \
 	utils.h \
+	stacktrace.h \
+	thread.h \
+	frame.h \
 	report_type.h
 
 lib_LTLIBRARIES = libsatyr.la
@@ -73,7 +76,10 @@ libsatyr_la_SOURCES = \
 	sha1.c \
 	strbuf.c \
 	unstrip.c \
-	utils.c
+	utils.c \
+	stacktrace.c \
+	thread.c \
+	frame.c
 
 libsatyr_la_CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE $(GLIB_CFLAGS)
 libsatyr_la_LDFLAGS = -version-info 1:0:0 $(GLIB_LIBS)
diff --git a/lib/frame.c b/lib/frame.c
new file mode 100644
index 0000000..9d563d8
--- /dev/null
+++ b/lib/frame.c
@@ -0,0 +1,90 @@
+/*
+    stacktrace.h
+
+    Copyright (C) 2013  Red Hat, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "report_type.h"
+#include "utils.h"
+#include "strbuf.h"
+#include "frame.h"
+
+#include "gdb_frame.h"
+#include "core_frame.h"
+#include "python_frame.h"
+#include "koops_frame.h"
+#include "java_frame.h"
+
+#include <stdio.h>
+
+SR_NEXT_FUNC(core_next, struct sr_frame, struct sr_core_frame)
+SR_NEXT_FUNC(python_next, struct sr_frame, struct sr_python_frame)
+SR_NEXT_FUNC(koops_next, struct sr_frame, struct sr_koops_frame)
+SR_NEXT_FUNC(java_next, struct sr_frame, struct sr_java_frame)
+SR_NEXT_FUNC(gdb_next, struct sr_frame, struct sr_gdb_frame)
+
+/* Initialize dispatch table. */
+
+typedef void (*append_to_str_fn_t)(struct sr_frame *, struct sr_strbuf *);
+typedef struct sr_frame* (*next_fn_t)(struct sr_frame *);
+
+struct methods
+{
+    append_to_str_fn_t append_to_str;
+    next_fn_t next;
+};
+
+static struct methods dtable[SR_REPORT_NUM] =
+{
+    [SR_REPORT_CORE] =
+    {
+        .append_to_str = (append_to_str_fn_t) sr_core_frame_append_to_str,
+        .next = (next_fn_t) core_next,
+    },
+    [SR_REPORT_PYTHON] =
+    {
+        .append_to_str = (append_to_str_fn_t) sr_python_frame_append_to_str,
+        .next = (next_fn_t) python_next,
+    },
+    [SR_REPORT_KERNELOOPS] =
+    {
+        .append_to_str = (append_to_str_fn_t) sr_koops_frame_append_to_str,
+        .next = (next_fn_t) koops_next,
+    },
+    [SR_REPORT_JAVA] =
+    {
+        .append_to_str = (append_to_str_fn_t) sr_java_frame_append_to_str,
+        .next = (next_fn_t) java_next,
+    },
+    [SR_REPORT_GDB] =
+    {
+        .append_to_str = (append_to_str_fn_t) sr_gdb_frame_append_to_str,
+        .next = (next_fn_t) gdb_next,
+    },
+};
+
+void
+sr_frame_append_to_str(struct sr_frame *frame, struct sr_strbuf *strbuf)
+{
+    SR_DISPATCH(frame->type, append_to_str)(frame, strbuf);
+}
+
+struct sr_frame *
+sr_frame_next(struct sr_frame *frame)
+{
+    return SR_DISPATCH(frame->type, next)(frame);
+}
diff --git a/lib/frame.h b/lib/frame.h
new file mode 100644
index 0000000..bb23419
--- /dev/null
+++ b/lib/frame.h
@@ -0,0 +1,64 @@
+/*
+    frame.h
+
+    Copyright (C) 2013  Red Hat, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef SATYR_FRAME_H
+#define SATYR_FRAME_H
+
+/**
+ * Functions declared here work with all frame types, i.e.
+ * * sr_core_frame
+ * * sr_python_frame
+ * * sr_koops_frame
+ * * sr_java_frame
+ * * sr_gdb_frame
+ * You may need to explicitly cast the pointer to struct sr_frame in order to
+ * avoid compiler warning.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "report_type.h"
+
+struct sr_strbuf;
+
+struct sr_frame
+{
+   enum sr_report_type type;
+};
+
+/**
+ * Return the next frame linked from this frame (corresponds to reading the
+ * "next" struct member).
+ */
+struct sr_frame *
+sr_frame_next(struct sr_frame *frame);
+
+/**
+ * Appends textual representation of the frame to buffer strbuf.
+ */
+void
+sr_frame_append_to_str(struct sr_frame *frame, struct sr_strbuf *strbuf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/stacktrace.c b/lib/stacktrace.c
new file mode 100644
index 0000000..e7182b6
--- /dev/null
+++ b/lib/stacktrace.c
@@ -0,0 +1,210 @@
+/*
+    stacktrace.c
+
+    Copyright (C) 2013  Red Hat, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "utils.h"
+#include "strbuf.h"
+#include "location.h"
+
+#include "frame.h"
+#include "stacktrace.h"
+#include "thread.h"
+
+#include "gdb_stacktrace.h"
+#include "core_stacktrace.h"
+#include "python_stacktrace.h"
+#include "koops_stacktrace.h"
+#include "java_stacktrace.h"
+
+#include <stdlib.h>
+
+static char *
+gdb_return_null(struct sr_stacktrace *stacktrace)
+{
+    return NULL;
+}
+
+/* In case stacktrace type supports only one thread, return the stacktrace itself. */
+static struct sr_thread *
+one_thread_only(struct sr_stacktrace *stacktrace)
+{
+    return (struct sr_thread *)stacktrace;
+}
+
+static char *
+generic_to_short_text(struct sr_stacktrace *stacktrace, int max_frames)
+{
+    struct sr_thread *thread = sr_stacktrace_find_crash_thread(stacktrace);
+    if (!thread)
+        return NULL;
+
+    struct sr_strbuf *strbuf = sr_strbuf_new();
+    struct sr_frame *frame;
+    int i = 0;
+
+    for (frame = sr_thread_frames(thread); frame; frame = sr_frame_next(frame))
+    {
+        i++;
+        sr_strbuf_append_strf(strbuf, "#%d ", i);
+        sr_frame_append_to_str(frame, strbuf);
+        sr_strbuf_append_char(strbuf, '\n');
+
+        if (max_frames && i >= max_frames)
+            break;
+    }
+
+    return sr_strbuf_free_nobuf(strbuf);
+}
+
+/* Uses the dispatch table, but we don't want to expose it in the API. */
+static struct sr_stacktrace *
+generic_parse_wrapper(enum sr_report_type type, const char **input, char **error_message);
+
+/* Initialize dispatch table. */
+
+typedef struct sr_stacktrace* (*parse_fn_t)(const char **, char **);
+typedef struct sr_stacktrace* (*parse_location_fn_t)(const char **, struct sr_location *);
+typedef char* (*to_short_text_fn_t)(struct sr_stacktrace*, int);
+typedef char* (*to_json_fn_t)(struct sr_stacktrace *);
+typedef char* (*get_reason_fn_t)(struct sr_stacktrace *);
+typedef struct sr_thread* (*find_crash_thread_fn_t)(struct sr_stacktrace *);
+typedef void (*free_fn_t)(struct sr_stacktrace *);
+
+struct methods
+{
+    parse_fn_t parse;
+    parse_location_fn_t parse_location;
+    to_short_text_fn_t to_short_text;
+    to_json_fn_t to_json;
+    get_reason_fn_t get_reason;
+    find_crash_thread_fn_t find_crash_thread;
+    free_fn_t free;
+};
+
+static struct methods dtable[SR_REPORT_NUM] =
+{
+    [SR_REPORT_CORE] =
+    {
+        /* core parser returns error_message directly */
+        .parse = (parse_fn_t) sr_core_stacktrace_from_json_text,
+        .parse_location = (parse_location_fn_t) NULL,
+        .to_short_text = (to_short_text_fn_t) generic_to_short_text,
+        .to_json = (to_json_fn_t) sr_core_stacktrace_to_json,
+        .get_reason = (get_reason_fn_t) sr_core_stacktrace_get_reason,
+        .find_crash_thread =
+            (find_crash_thread_fn_t) sr_core_stacktrace_find_crash_thread,
+        .free = (free_fn_t) sr_core_stacktrace_free,
+    },
+    [SR_REPORT_PYTHON] =
+    {
+        /* for other types, we have to convert location to message first */
+        .parse = (parse_fn_t) generic_parse_wrapper,
+        .parse_location = (parse_location_fn_t) sr_python_stacktrace_parse,
+        .to_short_text = (to_short_text_fn_t) generic_to_short_text,
+        .to_json = (to_json_fn_t) sr_python_stacktrace_to_json,
+        .get_reason = (get_reason_fn_t) sr_python_stacktrace_get_reason,
+        .find_crash_thread = (find_crash_thread_fn_t) one_thread_only,
+        .free = (free_fn_t) sr_python_stacktrace_free,
+    },
+    [SR_REPORT_KERNELOOPS] =
+    {
+        .parse = (parse_fn_t) generic_parse_wrapper,
+        .parse_location = (parse_location_fn_t) sr_koops_stacktrace_parse,
+        .to_short_text = (to_short_text_fn_t) generic_to_short_text,
+        .to_json = (to_json_fn_t) sr_koops_stacktrace_to_json,
+        .get_reason = (get_reason_fn_t) sr_koops_stacktrace_get_reason,
+        .find_crash_thread = (find_crash_thread_fn_t) one_thread_only,
+        .free = (free_fn_t) sr_koops_stacktrace_free,
+    },
+    [SR_REPORT_JAVA] =
+    {
+        .parse = (parse_fn_t) generic_parse_wrapper,
+        .parse_location = (parse_location_fn_t) sr_java_stacktrace_parse,
+        .to_short_text = (to_short_text_fn_t) generic_to_short_text,
+        .to_json = (to_json_fn_t) sr_java_stacktrace_to_json,
+        .get_reason = (get_reason_fn_t) sr_java_stacktrace_get_reason,
+        .find_crash_thread =
+            (find_crash_thread_fn_t) sr_java_find_crash_thread,
+        .free = (free_fn_t) sr_java_stacktrace_free,
+    },
+    [SR_REPORT_GDB] =
+    {
+        .parse = (parse_fn_t) generic_parse_wrapper,
+        .parse_location = (parse_location_fn_t) sr_gdb_stacktrace_parse,
+        .to_short_text = (to_short_text_fn_t) sr_gdb_stacktrace_to_short_text,
+        .to_json = (to_json_fn_t) gdb_return_null,
+        .get_reason = (get_reason_fn_t) gdb_return_null,
+        .find_crash_thread =
+            (find_crash_thread_fn_t) sr_gdb_stacktrace_find_crash_thread,
+        .free = (free_fn_t) sr_gdb_stacktrace_free,
+    },
+};
+
+static struct sr_stacktrace *
+generic_parse_wrapper(enum sr_report_type type, const char **input, char **error_message)
+{
+    struct sr_location location;
+    sr_location_init(&location);
+
+    struct sr_stacktrace *result = SR_DISPATCH(type, parse_location)(input, &location);
+
+    if (!result)
+    {
+        *error_message = sr_location_to_string(&location);
+        return NULL;
+    }
+
+    return result;
+}
+
+struct sr_stacktrace *
+sr_stacktrace_parse(enum sr_report_type type, const char **input, char **error_message)
+{
+    return SR_DISPATCH(type, parse)(input, error_message);
+}
+
+char *
+sr_stacktrace_to_short_text(struct sr_stacktrace *stacktrace, int max_frames)
+{
+    return SR_DISPATCH(stacktrace->type, to_short_text)(stacktrace, max_frames);
+}
+
+char *
+sr_stacktrace_to_json(struct sr_stacktrace *stacktrace)
+{
+    return SR_DISPATCH(stacktrace->type, to_json)(stacktrace);
+}
+
+char *
+sr_stacktrace_get_reason(struct sr_stacktrace *stacktrace)
+{
+    return SR_DISPATCH(stacktrace->type, get_reason)(stacktrace);
+}
+
+struct sr_thread *
+sr_stacktrace_find_crash_thread(struct sr_stacktrace *stacktrace)
+{
+    return SR_DISPATCH(stacktrace->type, find_crash_thread)(stacktrace);
+}
+
+void
+sr_stacktrace_free(struct sr_stacktrace *stacktrace)
+{
+    SR_DISPATCH(stacktrace->type, free)(stacktrace);
+}
diff --git a/lib/stacktrace.h b/lib/stacktrace.h
new file mode 100644
index 0000000..c611e73
--- /dev/null
+++ b/lib/stacktrace.h
@@ -0,0 +1,87 @@
+/*
+    stacktrace.h
+
+    Copyright (C) 2013  Red Hat, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef SATYR_STACKTRACE_H
+#define SATYR_STACKTRACE_H
+
+/**
+ * Functions declared here work with all stacktrace types:
+ * * sr_core_stacktrace
+ * * sr_python_stacktrace
+ * * sr_koops_stacktrace
+ * * sr_java_stacktrace
+ * * sr_gdb_stacktrace
+ * You may need to explicitly cast the pointer to struct sr_stacktrace in order
+ * to avoid compiler warning.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "report_type.h"
+
+struct sr_stacktrace
+{
+    enum sr_report_type type;
+};
+
+/**
+ * Parses the stacktrace pointed to by input. You need to provide the correct
+ * stacktrace type in the first parameter.
+ */
+struct sr_stacktrace *
+sr_stacktrace_parse(enum sr_report_type type, const char **input, char **error_message);
+
+/**
+ * Returns short textual representation of given stacktrace. At most max_frames
+ * are printed. Caller needs to free the result using free() afterwards.
+ */
+char *
+sr_stacktrace_to_short_text(struct sr_stacktrace *stacktrace, int max_frames);
+
+/**
+ * Returns the thread structure that (probably) caused the crash.
+ */
+struct sr_thread *
+sr_stacktrace_find_crash_thread(struct sr_stacktrace *stacktrace);
+
+/**
+ * Convert stacktrace to json and return it as text.
+ */
+char *
+sr_stacktrace_to_json(struct sr_stacktrace *stacktrace);
+
+/**
+ * Returns brief, human-readable explanation of the stacktrace.
+ */
+char *
+sr_stacktrace_get_reason(struct sr_stacktrace *stacktrace);
+
+/**
+ * Releases all the memory associated with the stacktrace pointer.
+ */
+void
+sr_stacktrace_free(struct sr_stacktrace *stacktrace);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/thread.c b/lib/thread.c
new file mode 100644
index 0000000..191bce3
--- /dev/null
+++ b/lib/thread.c
@@ -0,0 +1,128 @@
+/*
+    stacktrace.h
+
+    Copyright (C) 2013  Red Hat, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "report_type.h"
+#include "utils.h"
+#include "thread.h"
+#include "frame.h"
+
+#include "gdb_thread.h"
+#include "core_thread.h"
+#include "python_stacktrace.h"
+#include "koops_stacktrace.h"
+#include "java_thread.h"
+
+#include <stdio.h>
+
+/* Macro to generate accessors for the "frames" member. */
+#define SR_FRAMES_FUNC(name, concrete_t)                        \
+    static struct sr_frame *                                    \
+    name(struct sr_frame *node)                                 \
+    {                                                           \
+        return (struct sr_frame *)((concrete_t *)node)->frames; \
+    }                                                           \
+
+/* Note that python and koops do not have multiple threads, thus the functions
+ * here operate directly on the stacktrace structures. */
+SR_FRAMES_FUNC(core_frames, struct sr_core_thread)
+SR_FRAMES_FUNC(python_frames, struct sr_python_stacktrace)
+SR_FRAMES_FUNC(koops_frames, struct sr_koops_stacktrace)
+SR_FRAMES_FUNC(java_frames, struct sr_java_thread)
+SR_FRAMES_FUNC(gdb_frames, struct sr_gdb_thread)
+
+SR_NEXT_FUNC(core_next, struct sr_thread, struct sr_core_thread)
+SR_NEXT_FUNC(java_next, struct sr_thread, struct sr_java_thread)
+SR_NEXT_FUNC(gdb_next, struct sr_thread, struct sr_gdb_thread)
+
+static struct sr_thread *
+no_next_thread(struct sr_thread *thread)
+{
+    return NULL;
+}
+
+/* Initialize dispatch table. */
+
+typedef struct sr_frame* (*frames_fn_t)(struct sr_thread*);
+typedef int (*cmp_fn_t)(struct sr_thread*, struct sr_thread*);
+typedef struct sr_thread* (*next_fn_t)(struct sr_thread*);
+
+struct methods
+{
+    frames_fn_t frames;
+    cmp_fn_t cmp;
+    next_fn_t next;
+};
+
+/* Table that maps type-specific functions to the corresponding report types.
+ */
+static struct methods dtable[SR_REPORT_NUM] =
+{
+    [SR_REPORT_CORE] =
+    {
+        .frames = (frames_fn_t) core_frames,
+        .cmp = (cmp_fn_t) sr_core_thread_cmp,
+        .next = (next_fn_t) core_next,
+    },
+    [SR_REPORT_PYTHON] =
+    {
+        .frames = (frames_fn_t) python_frames,
+        .cmp = (cmp_fn_t) NULL,
+        .next = (next_fn_t) no_next_thread,
+    },
+    [SR_REPORT_KERNELOOPS] =
+    {
+        .frames = (frames_fn_t) koops_frames,
+        .cmp = (cmp_fn_t) NULL,
+        .next = (next_fn_t) no_next_thread,
+    },
+    [SR_REPORT_JAVA] =
+    {
+        .frames = (frames_fn_t) java_frames,
+        .cmp = (cmp_fn_t) sr_java_thread_cmp,
+        .next = (next_fn_t) java_next,
+    },
+    [SR_REPORT_GDB] =
+    {
+        .frames = (frames_fn_t) gdb_frames,
+        .cmp = (cmp_fn_t) sr_gdb_thread_cmp,
+        .next = (next_fn_t) gdb_next,
+    },
+};
+
+struct sr_frame *
+sr_thread_frames(struct sr_thread *thread)
+{
+    return SR_DISPATCH(thread->type, frames)(thread);
+}
+
+int
+sr_thread_cmp(struct sr_thread *t1, struct sr_thread *t2)
+{
+    if (t1->type != t2->type)
+        return t1->type - t2->type;
+
+    return SR_DISPATCH(t1->type, cmp)(t1, t2);
+}
+
+struct sr_thread *
+sr_thread_next(struct sr_thread *thread)
+{
+    return SR_DISPATCH(thread->type, next)(thread);
+}
diff --git a/lib/thread.h b/lib/thread.h
new file mode 100644
index 0000000..1ee7c35
--- /dev/null
+++ b/lib/thread.h
@@ -0,0 +1,70 @@
+/*
+    thread.h
+
+    Copyright (C) 2013  Red Hat, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef SATYR_THREAD_H
+#define SATYR_THREAD_H
+
+/**
+ * Functions declared here work with all thread types. Furthermore, for problem
+ * types that do not have a thread structure because they are always
+ * single-threaded, you can pass the stacktrace structure directly:
+ * * sr_core_thread
+ * * sr_python_stacktrace
+ * * sr_koops_stacktrace
+ * * sr_java_thread
+ * * sr_gdb_thread
+ * You may need to explicitly cast the pointer to struct sr_thread in order to
+ * avoid compiler warning.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "report_type.h"
+
+struct sr_thread
+{
+   enum sr_report_type type;
+};
+
+/**
+ * Returns pointer to the first frame in thread.
+ */
+struct sr_frame *
+sr_thread_frames(struct sr_thread *thread);
+
+/**
+ * Compares two threads. Returns 0 on equality. Threads of distinct type are
+ * always unequal.
+ */
+int
+sr_thread_cmp(struct sr_thread *t1, struct sr_thread *t2);
+
+/**
+ * Next thread in linked list (same as reading the "next" structure member).
+ */
+struct sr_thread *
+sr_thread_next(struct sr_thread *thread);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/utils.h b/lib/utils.h
index fcd39de..263cb8f 100644
--- a/lib/utils.h
+++ b/lib/utils.h
@@ -35,6 +35,7 @@ extern "C" {
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <assert.h>
 
 #define SR_lower "abcdefghijklmnopqrstuvwxyz"
 #define SR_upper "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -45,6 +46,17 @@ extern "C" {
 
 #define __sr_printf(x, y) __attribute__((format(printf, (x), (y))))
 
+#define SR_DISPATCH(type, method) \
+    (assert((type > 0) && (type) < SR_REPORT_NUM && dtable[type].method), \
+    dtable[type].method)
+
+#define SR_NEXT_FUNC(name, abstract_t, concrete_t)       \
+    static abstract_t *                                  \
+    name(abstract_t *node)                               \
+    {                                                    \
+        return (abstract_t *)((concrete_t *)node)->next; \
+    }                                                    \
+
 /**
  * Debugging output to stdout while parsing.
  * Default value is false.
-- 
1.7.11.7



More information about the Crash-catcher mailing list