[SATYR PATCH 2/2] Move "method tables" to files where the methods are defined

Martin Milata mmilata at redhat.com
Thu Jun 13 09:51:13 UTC 2013


- added new header internal_utils.h with private declarations that don't
  fit into any other header
- stacktrace.c was split to generic_stacktrace.c and
  generic_stacktrace.h, the same was done with thread.c and frame.c.

  The generic_*.h headers contain the method table types and declaration
  for platform-agnostic functions that should not be called directly by
  the library user.

Signed-off-by: Martin Milata <mmilata at redhat.com>
---
 include/utils.h          |  11 ---
 lib/Makefile.am          |  12 ++-
 lib/core_frame.c         |  14 ++++
 lib/core_stacktrace.c    |  19 +++++
 lib/core_thread.c        |  17 ++++
 lib/frame.c              |  90 --------------------
 lib/gdb_frame.c          |  14 ++++
 lib/gdb_stacktrace.c     |  25 ++++++
 lib/gdb_thread.c         |  18 +++-
 lib/generic_frame.c      |  45 ++++++++++
 lib/generic_frame.h      |  33 ++++++++
 lib/generic_stacktrace.c | 124 ++++++++++++++++++++++++++++
 lib/generic_stacktrace.h |  57 +++++++++++++
 lib/generic_thread.c     |  90 ++++++++++++++++++++
 lib/generic_thread.h     |  51 ++++++++++++
 lib/internal_utils.h     |  33 ++++++++
 lib/java_frame.c         |  14 ++++
 lib/java_stacktrace.c    |  18 ++++
 lib/java_thread.c        |  17 ++++
 lib/koops_frame.c        |  14 ++++
 lib/koops_stacktrace.c   |  28 +++++++
 lib/python_frame.c       |  14 ++++
 lib/python_stacktrace.c  |  28 +++++++
 lib/stacktrace.c         | 210 -----------------------------------------------
 lib/thread.c             | 155 ----------------------------------
 25 files changed, 680 insertions(+), 471 deletions(-)
 delete mode 100644 lib/frame.c
 create mode 100644 lib/generic_frame.c
 create mode 100644 lib/generic_frame.h
 create mode 100644 lib/generic_stacktrace.c
 create mode 100644 lib/generic_stacktrace.h
 create mode 100644 lib/generic_thread.c
 create mode 100644 lib/generic_thread.h
 create mode 100644 lib/internal_utils.h
 delete mode 100644 lib/stacktrace.c
 delete mode 100644 lib/thread.c

diff --git a/include/utils.h b/include/utils.h
index 9dff404..68e763b 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -46,17 +46,6 @@ extern "C" {
 
 #define __sr_printf(x, y) __attribute__((format(printf, (x), (y))))
 
-#define SR_DISPATCH(type, method) \
-    (assert((type > SR_REPORT_INVALID) && (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.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index c3ed3ea..277f53d 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -20,10 +20,17 @@ libsatyr_la_SOURCES = \
 	disasm.c \
 	distance.c \
 	elves.c \
+	generic_stacktrace.c \
+	generic_stacktrace.h \
+	generic_thread.c \
+	generic_thread.h \
+	generic_frame.c \
+	generic_frame.h \
 	gdb_stacktrace.c \
 	gdb_frame.c \
 	gdb_sharedlib.c \
 	gdb_thread.c \
+	internal_utils.h \
 	java_frame.c \
 	java_thread.c \
 	java_stacktrace.c \
@@ -41,10 +48,7 @@ libsatyr_la_SOURCES = \
 	sha1.c \
 	strbuf.c \
 	unstrip.c \
-	utils.c \
-	stacktrace.c \
-	thread.c \
-	frame.c
+	utils.c
 
 libsatyr_la_CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -I$(top_srcdir)/include $(GLIB_CFLAGS)
 libsatyr_la_LDFLAGS = -version-info 1:0:0 $(GLIB_LIBS)
diff --git a/lib/core_frame.c b/lib/core_frame.c
index 37d2b8b..a2d1ef0 100644
--- a/lib/core_frame.c
+++ b/lib/core_frame.c
@@ -21,8 +21,22 @@
 #include "utils.h"
 #include "strbuf.h"
 #include "json.h"
+#include "generic_frame.h"
+#include "internal_utils.h"
 #include <string.h>
 
+/* Method table */
+
+DEFINE_NEXT_FUNC(core_next, struct sr_frame, struct sr_core_frame)
+
+struct frame_methods core_frame_methods =
+{
+    .append_to_str = (append_to_str_fn_t) sr_core_frame_append_to_str,
+    .next = (next_frame_fn_t) core_next,
+};
+
+/* Public functions */
+
 struct sr_core_frame *
 sr_core_frame_new()
 {
diff --git a/lib/core_stacktrace.c b/lib/core_stacktrace.c
index c0978d4..46bdcc7 100644
--- a/lib/core_stacktrace.c
+++ b/lib/core_stacktrace.c
@@ -29,6 +29,8 @@
 #include "strbuf.h"
 #include "unstrip.h"
 #include "json.h"
+#include "generic_stacktrace.h"
+#include "internal_utils.h"
 #include <ctype.h>
 #include <inttypes.h>
 #include <stdint.h>
@@ -36,6 +38,23 @@
 #include <string.h>
 #include <assert.h>
 
+/* Method table */
+
+struct stacktrace_methods core_stacktrace_methods =
+{
+    /* 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) stacktrace_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,
+};
+
+/* Public functions */
+
 struct sr_core_stacktrace *
 sr_core_stacktrace_new()
 {
diff --git a/lib/core_thread.c b/lib/core_thread.c
index a48a3c3..3ebf1d9 100644
--- a/lib/core_thread.c
+++ b/lib/core_thread.c
@@ -22,8 +22,25 @@
 #include "utils.h"
 #include "strbuf.h"
 #include "json.h"
+#include "generic_thread.h"
+#include "internal_utils.h"
 #include <string.h>
 
+/* Method table */
+
+DEFINE_THREAD_FUNC(core_frames, struct sr_core_thread)
+DEFINE_NEXT_FUNC(core_next, struct sr_thread, struct sr_core_thread)
+
+struct thread_methods core_thread_methods =
+{
+    .frames = (frames_fn_t) core_frames,
+    .cmp = (cmp_fn_t) sr_core_thread_cmp,
+    .frame_count = (frame_count_fn_t) thread_frame_count,
+    .next = (next_thread_fn_t) core_next,
+};
+
+/* Public functions */
+
 struct sr_core_thread *
 sr_core_thread_new()
 {
diff --git a/lib/frame.c b/lib/frame.c
deleted file mode 100644
index da4f070..0000000
--- a/lib/frame.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-    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/gdb_frame.c b/lib/gdb_frame.c
index 630e9a2..e3b30fb 100644
--- a/lib/gdb_frame.c
+++ b/lib/gdb_frame.c
@@ -21,11 +21,25 @@
 #include "utils.h"
 #include "strbuf.h"
 #include "location.h"
+#include "generic_frame.h"
+#include "internal_utils.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 
+/* Method table */
+
+DEFINE_NEXT_FUNC(gdb_next, struct sr_frame, struct sr_gdb_frame)
+
+struct frame_methods gdb_frame_methods =
+{
+    .append_to_str = (append_to_str_fn_t) sr_gdb_frame_append_to_str,
+    .next = (next_frame_fn_t) gdb_next,
+};
+
+/* Public functions */
+
 struct sr_gdb_frame *
 sr_gdb_frame_new()
 {
diff --git a/lib/gdb_stacktrace.c b/lib/gdb_stacktrace.c
index 0fe2faa..1ef33dd 100644
--- a/lib/gdb_stacktrace.c
+++ b/lib/gdb_stacktrace.c
@@ -25,11 +25,36 @@
 #include "strbuf.h"
 #include "location.h"
 #include "normalize.h"
+#include "generic_stacktrace.h"
+#include "internal_utils.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
 
+/* Method table */
+
+/* for not used/implemented methods */
+static char *
+gdb_return_null(struct sr_stacktrace *stacktrace)
+{
+    return NULL;
+}
+
+struct stacktrace_methods gdb_stacktrace_methods =
+{
+    .parse = (parse_fn_t) stacktrace_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,
+};
+
+/* Public functions */
+
 struct sr_gdb_stacktrace *
 sr_gdb_stacktrace_new()
 {
diff --git a/lib/gdb_thread.c b/lib/gdb_thread.c
index c01c32a..21acca3 100644
--- a/lib/gdb_thread.c
+++ b/lib/gdb_thread.c
@@ -24,11 +24,27 @@
 #include "location.h"
 #include "utils.h"
 #include "strbuf.h"
-#include "thread.h"
+#include "generic_thread.h"
+#include "internal_utils.h"
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
+/* Method table */
+
+DEFINE_THREAD_FUNC(gdb_frames, struct sr_gdb_thread)
+DEFINE_NEXT_FUNC(gdb_next, struct sr_thread, struct sr_gdb_thread)
+
+struct thread_methods gdb_thread_methods =
+{
+    .frames = (frames_fn_t) gdb_frames,
+    .cmp = (cmp_fn_t) sr_gdb_thread_cmp,
+    .frame_count = (frame_count_fn_t) thread_frame_count,
+    .next = (next_thread_fn_t) gdb_next,
+};
+
+/* Public functions */
+
 struct sr_gdb_thread *
 sr_gdb_thread_new()
 {
diff --git a/lib/generic_frame.c b/lib/generic_frame.c
new file mode 100644
index 0000000..9041037
--- /dev/null
+++ b/lib/generic_frame.c
@@ -0,0 +1,45 @@
+/*
+    generic_frame.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 "report_type.h"
+#include "internal_utils.h"
+#include "generic_frame.h"
+
+/* Initialize dispatch table. */
+static struct frame_methods* dtable[SR_REPORT_NUM] =
+{
+    [SR_REPORT_CORE] = &core_frame_methods,
+    [SR_REPORT_PYTHON] = &python_frame_methods,
+    [SR_REPORT_KERNELOOPS] = &koops_frame_methods,
+    [SR_REPORT_JAVA] = &java_frame_methods,
+    [SR_REPORT_GDB] = &gdb_frame_methods,
+};
+
+void
+sr_frame_append_to_str(struct sr_frame *frame, struct sr_strbuf *strbuf)
+{
+    DISPATCH(dtable, frame->type, append_to_str)(frame, strbuf);
+}
+
+struct sr_frame *
+sr_frame_next(struct sr_frame *frame)
+{
+    return DISPATCH(dtable, frame->type, next)(frame);
+}
diff --git a/lib/generic_frame.h b/lib/generic_frame.h
new file mode 100644
index 0000000..5e28817
--- /dev/null
+++ b/lib/generic_frame.h
@@ -0,0 +1,33 @@
+/*
+    generic_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.
+*/
+
+#include "frame.h"
+
+typedef void (*append_to_str_fn_t)(struct sr_frame *, struct sr_strbuf *);
+typedef struct sr_frame* (*next_frame_fn_t)(struct sr_frame *);
+
+struct frame_methods
+{
+    append_to_str_fn_t append_to_str;
+    next_frame_fn_t next;
+};
+
+extern struct frame_methods core_frame_methods, python_frame_methods,
+       koops_frame_methods, gdb_frame_methods, java_frame_methods;
diff --git a/lib/generic_stacktrace.c b/lib/generic_stacktrace.c
new file mode 100644
index 0000000..9352001
--- /dev/null
+++ b/lib/generic_stacktrace.c
@@ -0,0 +1,124 @@
+/*
+    generic_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 "internal_utils.h"
+#include "strbuf.h"
+#include "location.h"
+
+#include "frame.h"
+#include "thread.h"
+#include "generic_stacktrace.h"
+
+/* Initialize dispatch table. */
+static struct stacktrace_methods* dtable[SR_REPORT_NUM] =
+{
+    [SR_REPORT_CORE] = &core_stacktrace_methods,
+    [SR_REPORT_PYTHON] = &python_stacktrace_methods,
+    [SR_REPORT_KERNELOOPS] = &koops_stacktrace_methods,
+    [SR_REPORT_JAVA] = &java_stacktrace_methods,
+    [SR_REPORT_GDB] = &gdb_stacktrace_methods,
+};
+
+/* In case stacktrace type supports only one thread, return the stacktrace itself. */
+struct sr_thread *
+stacktrace_one_thread_only(struct sr_stacktrace *stacktrace)
+{
+    return (struct sr_thread *)stacktrace;
+}
+
+char *
+stacktrace_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 should not be exposed to library users directly. */
+struct sr_stacktrace *
+stacktrace_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 = DISPATCH(dtable, type, parse_location)(input, &location);
+
+    if (!result)
+    {
+        *error_message = sr_location_to_string(&location);
+        return NULL;
+    }
+
+    return result;
+}
+
+/* Wrappers of polymorphic functions. */
+struct sr_stacktrace *
+sr_stacktrace_parse(enum sr_report_type type, const char **input, char **error_message)
+{
+    return DISPATCH(dtable, type, parse)(input, error_message);
+}
+
+char *
+sr_stacktrace_to_short_text(struct sr_stacktrace *stacktrace, int max_frames)
+{
+    return DISPATCH(dtable, stacktrace->type, to_short_text)(stacktrace, max_frames);
+}
+
+char *
+sr_stacktrace_to_json(struct sr_stacktrace *stacktrace)
+{
+    return DISPATCH(dtable, stacktrace->type, to_json)(stacktrace);
+}
+
+char *
+sr_stacktrace_get_reason(struct sr_stacktrace *stacktrace)
+{
+    return DISPATCH(dtable, stacktrace->type, get_reason)(stacktrace);
+}
+
+struct sr_thread *
+sr_stacktrace_find_crash_thread(struct sr_stacktrace *stacktrace)
+{
+    return DISPATCH(dtable, stacktrace->type, find_crash_thread)(stacktrace);
+}
+
+void
+sr_stacktrace_free(struct sr_stacktrace *stacktrace)
+{
+    DISPATCH(dtable, stacktrace->type, free)(stacktrace);
+}
diff --git a/lib/generic_stacktrace.h b/lib/generic_stacktrace.h
new file mode 100644
index 0000000..7aa675d
--- /dev/null
+++ b/lib/generic_stacktrace.h
@@ -0,0 +1,57 @@
+/*
+    generic_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 "stacktrace.h"
+#include "thread.h"
+
+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 stacktrace_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;
+};
+
+extern struct stacktrace_methods core_stacktrace_methods, python_stacktrace_methods,
+       koops_stacktrace_methods, gdb_stacktrace_methods, java_stacktrace_methods;
+
+/* XXX generic functions */
+struct sr_stacktrace *
+stacktrace_parse_wrapper(enum sr_report_type type, const char **input, char **error_message);
+
+char *
+stacktrace_to_short_text(struct sr_stacktrace *stacktrace, int max_frames);
+
+struct sr_thread *
+stacktrace_one_thread_only(struct sr_stacktrace *stacktrace);
+
+struct sr_stacktrace *
+stacktrace_parse_wrapper(enum sr_report_type type, const char **input, char **error_message);
diff --git a/lib/generic_thread.c b/lib/generic_thread.c
new file mode 100644
index 0000000..17fa778
--- /dev/null
+++ b/lib/generic_thread.c
@@ -0,0 +1,90 @@
+/*
+    generic_thread.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 "report_type.h"
+#include "internal_utils.h"
+#include "frame.h"
+#include "generic_thread.h"
+
+#include <stdio.h>
+
+//XXX
+/* Note that python and koops do not have multiple threads, thus the functions
+ * here operate directly on the stacktrace structures. */
+
+int
+thread_frame_count(struct sr_thread *thread)
+{
+    struct sr_frame *frame = sr_thread_frames(thread);
+    int count = 0;
+    while (frame)
+    {
+        frame = sr_frame_next(frame);
+        ++count;
+    }
+
+    return count;
+}
+
+struct sr_thread *
+thread_no_next_thread(struct sr_thread *thread)
+{
+    return NULL;
+}
+
+/* Initialize dispatch table. */
+
+/* Table that maps type-specific functions to the corresponding report types.
+ */
+static struct thread_methods* dtable[SR_REPORT_NUM] =
+{
+    [SR_REPORT_CORE] = &core_thread_methods,
+    [SR_REPORT_PYTHON] = &python_thread_methods,
+    [SR_REPORT_KERNELOOPS] = &koops_thread_methods,
+    [SR_REPORT_JAVA] = &java_thread_methods,
+    [SR_REPORT_GDB] = &gdb_thread_methods,
+};
+
+struct sr_frame *
+sr_thread_frames(struct sr_thread *thread)
+{
+    return DISPATCH(dtable, thread->type, frames)(thread);
+}
+
+int
+sr_thread_frame_count(struct sr_thread *thread)
+{
+    return DISPATCH(dtable, thread->type, frame_count)(thread);
+}
+
+int
+sr_thread_cmp(struct sr_thread *t1, struct sr_thread *t2)
+{
+    if (t1->type != t2->type)
+        return t1->type - t2->type;
+
+    return DISPATCH(dtable, t1->type, cmp)(t1, t2);
+}
+
+struct sr_thread *
+sr_thread_next(struct sr_thread *thread)
+{
+    return DISPATCH(dtable, thread->type, next)(thread);
+}
diff --git a/lib/generic_thread.h b/lib/generic_thread.h
new file mode 100644
index 0000000..e1e5f0a
--- /dev/null
+++ b/lib/generic_thread.h
@@ -0,0 +1,51 @@
+/*
+    generic_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 "thread.h"
+
+typedef struct sr_frame* (*frames_fn_t)(struct sr_thread*);
+typedef int (*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*);
+
+struct thread_methods
+{
+    frames_fn_t frames;
+    cmp_fn_t cmp;
+    frame_count_fn_t frame_count;
+    next_thread_fn_t next;
+};
+
+extern struct thread_methods core_thread_methods, python_thread_methods,
+       koops_thread_methods, gdb_thread_methods, java_thread_methods;
+
+/* Macro to generate accessors for the "frames" member. */
+#define DEFINE_THREAD_FUNC(name, concrete_t)                    \
+    static struct sr_frame *                                    \
+    name(struct sr_frame *node)                                 \
+    {                                                           \
+        return (struct sr_frame *)((concrete_t *)node)->frames; \
+    }                                                           \
+
+int
+thread_frame_count(struct sr_thread *thread);
+
+struct sr_thread *
+thread_no_next_thread(struct sr_thread *thread);
diff --git a/lib/internal_utils.h b/lib/internal_utils.h
new file mode 100644
index 0000000..459b5b8
--- /dev/null
+++ b/lib/internal_utils.h
@@ -0,0 +1,33 @@
+/*
+    internal_utils.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 <assert.h>
+
+#define DISPATCH(table, type, method) \
+    (assert((type > SR_REPORT_INVALID) && (type) < SR_REPORT_NUM && table[type]->method), \
+    table[type]->method)
+
+#define DEFINE_NEXT_FUNC(name, abstract_t, concrete_t)   \
+    static abstract_t *                                  \
+    name(abstract_t *node)                               \
+    {                                                    \
+        return (abstract_t *)((concrete_t *)node)->next; \
+    }
+
diff --git a/lib/java_frame.c b/lib/java_frame.c
index 9580138..fc8ae29 100644
--- a/lib/java_frame.c
+++ b/lib/java_frame.c
@@ -23,12 +23,26 @@
 #include "location.h"
 #include "utils.h"
 #include "json.h"
+#include "generic_frame.h"
+#include "internal_utils.h"
 #include <string.h>
 #include <inttypes.h>
 
 #define SR_JF_MARK_NATIVE_METHOD "Native Method"
 #define SR_JF_MARK_UNKNOWN_SOURCE "Unknown Source"
 
+/* Method table */
+
+DEFINE_NEXT_FUNC(java_next, struct sr_frame, struct sr_java_frame)
+
+struct frame_methods java_frame_methods =
+{
+    .append_to_str = (append_to_str_fn_t) sr_java_frame_append_to_str,
+    .next = (next_frame_fn_t) java_next,
+};
+
+/* Public functions */
+
 struct sr_java_frame *
 sr_java_frame_new()
 {
diff --git a/lib/java_stacktrace.c b/lib/java_stacktrace.c
index e05c0c6..b9f8ecb 100644
--- a/lib/java_stacktrace.c
+++ b/lib/java_stacktrace.c
@@ -23,10 +23,28 @@
 #include "java/frame.h"
 #include "utils.h"
 #include "strbuf.h"
+#include "generic_stacktrace.h"
+#include "internal_utils.h"
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
 
+/* Method table */
+
+struct stacktrace_methods java_stacktrace_methods =
+{
+    .parse = (parse_fn_t) stacktrace_parse_wrapper,
+    .parse_location = (parse_location_fn_t) sr_java_stacktrace_parse,
+    .to_short_text = (to_short_text_fn_t) stacktrace_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,
+};
+
+/* Public functions */
+
 struct sr_java_stacktrace *
 sr_java_stacktrace_new()
 {
diff --git a/lib/java_thread.c b/lib/java_thread.c
index c578e74..ef5f73c 100644
--- a/lib/java_thread.c
+++ b/lib/java_thread.c
@@ -24,10 +24,27 @@
 #include "utils.h"
 #include "strbuf.h"
 #include "json.h"
+#include "generic_thread.h"
+#include "internal_utils.h"
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
+/* Method table */
+
+DEFINE_THREAD_FUNC(java_frames, struct sr_java_thread)
+DEFINE_NEXT_FUNC(java_next, struct sr_thread, struct sr_java_thread)
+
+struct thread_methods java_thread_methods =
+{
+    .frames = (frames_fn_t) java_frames,
+    .cmp = (cmp_fn_t) sr_java_thread_cmp,
+    .frame_count = (frame_count_fn_t) thread_frame_count,
+    .next = (next_thread_fn_t) java_next,
+};
+
+/* Public functions */
+
 struct sr_java_thread *
 sr_java_thread_new()
 {
diff --git a/lib/koops_frame.c b/lib/koops_frame.c
index 15d6473..76f5027 100644
--- a/lib/koops_frame.c
+++ b/lib/koops_frame.c
@@ -21,11 +21,25 @@
 #include "utils.h"
 #include "strbuf.h"
 #include "json.h"
+#include "generic_frame.h"
+#include "internal_utils.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
 
+/* Method table */
+
+DEFINE_NEXT_FUNC(koops_next, struct sr_frame, struct sr_koops_frame)
+
+struct frame_methods koops_frame_methods =
+{
+    .append_to_str = (append_to_str_fn_t) sr_koops_frame_append_to_str,
+    .next = (next_frame_fn_t) koops_next,
+};
+
+/* Public functions */
+
 struct sr_koops_frame *
 sr_koops_frame_new()
 {
diff --git a/lib/koops_stacktrace.c b/lib/koops_stacktrace.c
index c9a249a..16d96a3 100644
--- a/lib/koops_stacktrace.c
+++ b/lib/koops_stacktrace.c
@@ -23,6 +23,9 @@
 #include "json.h"
 #include "strbuf.h"
 #include "normalize.h"
+#include "generic_thread.h"
+#include "generic_stacktrace.h"
+#include "internal_utils.h"
 #include <string.h>
 #include <stddef.h>
 
@@ -51,6 +54,31 @@ struct sr_taint_flag sr_flags[] = {
 #undef FLAG
 #undef FLAG_OFFSET
 
+/* Method tables */
+
+DEFINE_THREAD_FUNC(koops_frames, struct sr_koops_stacktrace)
+
+struct thread_methods koops_thread_methods =
+{
+    .frames = (frames_fn_t) koops_frames,
+    .cmp = (cmp_fn_t) NULL,
+    .frame_count = (frame_count_fn_t) thread_frame_count,
+    .next = (next_thread_fn_t) thread_no_next_thread,
+};
+
+struct stacktrace_methods koops_stacktrace_methods =
+{
+    .parse = (parse_fn_t) stacktrace_parse_wrapper,
+    .parse_location = (parse_location_fn_t) sr_koops_stacktrace_parse,
+    .to_short_text = (to_short_text_fn_t) stacktrace_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) stacktrace_one_thread_only,
+    .free = (free_fn_t) sr_koops_stacktrace_free,
+};
+
+/* Public functions */
+
 struct sr_koops_stacktrace *
 sr_koops_stacktrace_new()
 {
diff --git a/lib/python_frame.c b/lib/python_frame.c
index 4f43ad4..86ecb4e 100644
--- a/lib/python_frame.c
+++ b/lib/python_frame.c
@@ -22,9 +22,23 @@
 #include "location.h"
 #include "strbuf.h"
 #include "json.h"
+#include "generic_frame.h"
+#include "internal_utils.h"
 #include <string.h>
 #include <inttypes.h>
 
+/* Method table */
+
+DEFINE_NEXT_FUNC(python_next, struct sr_frame, struct sr_python_frame)
+
+struct frame_methods python_frame_methods =
+{
+    .append_to_str = (append_to_str_fn_t) sr_python_frame_append_to_str,
+    .next = (next_frame_fn_t) python_next,
+};
+
+/* Public functions */
+
 struct sr_python_frame *
 sr_python_frame_new()
 {
diff --git a/lib/python_stacktrace.c b/lib/python_stacktrace.c
index bdc162b..278d175 100644
--- a/lib/python_stacktrace.c
+++ b/lib/python_stacktrace.c
@@ -25,10 +25,38 @@
 #include "sha1.h"
 #include "report_type.h"
 #include "strbuf.h"
+#include "generic_stacktrace.h"
+#include "generic_thread.h"
+#include "internal_utils.h"
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
 
+/* Method tables */
+
+DEFINE_THREAD_FUNC(python_frames, struct sr_python_stacktrace)
+
+struct thread_methods python_thread_methods =
+{
+    .frames = (frames_fn_t) python_frames,
+    .cmp = (cmp_fn_t) NULL,
+    .frame_count = (frame_count_fn_t) thread_frame_count,
+    .next = (next_thread_fn_t) thread_no_next_thread,
+};
+
+struct stacktrace_methods python_stacktrace_methods =
+{
+    .parse = (parse_fn_t) stacktrace_parse_wrapper,
+    .parse_location = (parse_location_fn_t) sr_python_stacktrace_parse,
+    .to_short_text = (to_short_text_fn_t) stacktrace_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) stacktrace_one_thread_only,
+    .free = (free_fn_t) sr_python_stacktrace_free,
+};
+
+/* Public functions */
+
 struct sr_python_stacktrace *
 sr_python_stacktrace_new()
 {
diff --git a/lib/stacktrace.c b/lib/stacktrace.c
deleted file mode 100644
index 0f22e58..0000000
--- a/lib/stacktrace.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
-    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/thread.c b/lib/thread.c
deleted file mode 100644
index c2cc2ca..0000000
--- a/lib/thread.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-    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 int
-generic_frame_count(struct sr_thread *thread)
-{
-    struct sr_frame *frame = sr_thread_frames(thread);
-    int count = 0;
-    while (frame)
-    {
-        frame = sr_frame_next(frame);
-        ++count;
-    }
-
-    return count;
-}
-
-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 int (*frame_count_fn_t)(struct sr_thread*);
-typedef struct sr_thread* (*next_fn_t)(struct sr_thread*);
-
-struct methods
-{
-    frames_fn_t frames;
-    cmp_fn_t cmp;
-    frame_count_fn_t frame_count;
-    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,
-        .frame_count = (frame_count_fn_t) generic_frame_count,
-        .next = (next_fn_t) core_next,
-    },
-    [SR_REPORT_PYTHON] =
-    {
-        .frames = (frames_fn_t) python_frames,
-        .cmp = (cmp_fn_t) NULL,
-        .frame_count = (frame_count_fn_t) generic_frame_count,
-        .next = (next_fn_t) no_next_thread,
-    },
-    [SR_REPORT_KERNELOOPS] =
-    {
-        .frames = (frames_fn_t) koops_frames,
-        .cmp = (cmp_fn_t) NULL,
-        .frame_count = (frame_count_fn_t) generic_frame_count,
-        .next = (next_fn_t) no_next_thread,
-    },
-    [SR_REPORT_JAVA] =
-    {
-        .frames = (frames_fn_t) java_frames,
-        .cmp = (cmp_fn_t) sr_java_thread_cmp,
-        .frame_count = (frame_count_fn_t) generic_frame_count,
-        .next = (next_fn_t) java_next,
-    },
-    [SR_REPORT_GDB] =
-    {
-        .frames = (frames_fn_t) gdb_frames,
-        .cmp = (cmp_fn_t) sr_gdb_thread_cmp,
-        .frame_count = (frame_count_fn_t) generic_frame_count,
-        .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_frame_count(struct sr_thread *thread)
-{
-    return SR_DISPATCH(thread->type, frame_count)(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);
-}
-- 
1.7.11.7



More information about the Crash-catcher mailing list