- 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 <[email protected]> --- 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
