[SATYR PATCH 6/6] python: add bindings for core stacktraces
Martin Milata
mmilata at redhat.com
Wed Aug 7 15:53:25 UTC 2013
Closes #41.
Signed-off-by: Martin Milata <mmilata at redhat.com>
---
python/Makefile.am | 6 ++
python/py_core_frame.c | 193 ++++++++++++++++++++++++++++++++++++++++
python/py_core_frame.h | 69 ++++++++++++++
python/py_core_stacktrace.c | 212 ++++++++++++++++++++++++++++++++++++++++++++
python/py_core_stacktrace.h | 71 +++++++++++++++
python/py_core_thread.c | 161 +++++++++++++++++++++++++++++++++
python/py_core_thread.h | 66 ++++++++++++++
python/py_module.c | 33 +++++++
tests/python/core.py | 116 ++++++++++++++++++++++++
tests/python_bindings.at | 1 +
10 files changed, 928 insertions(+)
create mode 100644 python/py_core_frame.c
create mode 100644 python/py_core_frame.h
create mode 100644 python/py_core_stacktrace.c
create mode 100644 python/py_core_stacktrace.h
create mode 100644 python/py_core_thread.c
create mode 100644 python/py_core_thread.h
create mode 100755 tests/python/core.py
diff --git a/python/Makefile.am b/python/Makefile.am
index 12f408f..95a81c0 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -14,6 +14,12 @@ _satyr_la_SOURCES = \
py_base_thread.c \
py_base_stacktrace.h \
py_base_stacktrace.c \
+ py_core_frame.h \
+ py_core_frame.c \
+ py_core_thread.h \
+ py_core_thread.c \
+ py_core_stacktrace.h \
+ py_core_stacktrace.c \
py_gdb_frame.h \
py_gdb_frame.c \
py_gdb_sharedlib.h \
diff --git a/python/py_core_frame.c b/python/py_core_frame.c
new file mode 100644
index 0000000..7abeee8
--- /dev/null
+++ b/python/py_core_frame.c
@@ -0,0 +1,193 @@
+/*
+ py_core_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 "py_common.h"
+#include "py_base_frame.h"
+#include "py_core_frame.h"
+
+#include "strbuf.h"
+#include "utils.h"
+#include "core/frame.h"
+
+#define frame_doc "satyr.CoreFrame - class representing a frame in a native executable\n" \
+ "Usage:\n" \
+ "satyr.CoreFrame() - creates an empty frame"
+
+#define f_dup_doc "Usage: frame.dup()\n" \
+ "Returns: satyr.CoreFrame - a new clone of frame\n" \
+ "Clones the frame object. All new structures are independent " \
+ "on the original object."
+
+
+static PyMethodDef
+frame_methods[] =
+{
+ /* methods */
+ { "dup", sr_py_core_frame_dup, METH_NOARGS, f_dup_doc },
+ { NULL },
+};
+
+/* See python/py_common.h and python/py_gdb_frame.c for generic getters/setters documentation. */
+#define GSOFF_PY_STRUCT sr_py_core_frame
+#define GSOFF_PY_MEMBER frame
+#define GSOFF_C_STRUCT sr_core_frame
+GSOFF_START
+GSOFF_MEMBER(address),
+GSOFF_MEMBER(build_id),
+GSOFF_MEMBER(build_id_offset),
+GSOFF_MEMBER(function_name),
+GSOFF_MEMBER(file_name),
+GSOFF_MEMBER(fingerprint),
+GSOFF_MEMBER(fingerprint_hashed)
+GSOFF_END
+
+static PyGetSetDef
+frame_getset[] =
+{
+ SR_ATTRIBUTE_UINT64(address, "Address of the machine code in memory (long)" ),
+ SR_ATTRIBUTE_STRING(build_id, "Build ID of the ELF file (string)" ),
+ SR_ATTRIBUTE_UINT64(build_id_offset, "Offset of the instruction pointer from the start " \
+ "of the executable segment (long)" ),
+ SR_ATTRIBUTE_STRING(function_name, "Function name (string)" ),
+ SR_ATTRIBUTE_STRING(file_name, "Name of the executable or shared library (string)" ),
+ SR_ATTRIBUTE_STRING(fingerprint, "Fingerprint of the current function (string)" ),
+ SR_ATTRIBUTE_BOOL (fingerprint_hashed, "True if fingerprint is already hasheed (bool)" ),
+ { NULL }
+};
+
+PyTypeObject
+sr_py_core_frame_type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "satyr.CoreFrame", /* tp_name */
+ sizeof(struct sr_py_core_frame), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ sr_py_core_frame_free, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ sr_py_core_frame_str, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ frame_doc, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ frame_methods, /* tp_methods */
+ NULL, /* tp_members */
+ frame_getset, /* tp_getset */
+ &sr_py_base_frame_type, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ NULL, /* tp_init */
+ NULL, /* tp_alloc */
+ sr_py_core_frame_new, /* tp_new */
+ NULL, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+};
+
+/* constructor */
+PyObject *
+sr_py_core_frame_new(PyTypeObject *object, PyObject *args, PyObject *kwds)
+{
+ struct sr_py_core_frame *fo = (struct sr_py_core_frame*)
+ PyObject_New(struct sr_py_core_frame, &sr_py_core_frame_type);
+
+ if (!fo)
+ return PyErr_NoMemory();
+
+ fo->frame = sr_core_frame_new();
+
+ return (PyObject*)fo;
+}
+
+/* destructor */
+void
+sr_py_core_frame_free(PyObject *object)
+{
+ struct sr_py_core_frame *this = (struct sr_py_core_frame*)object;
+ sr_core_frame_free(this->frame);
+ PyObject_Del(object);
+}
+
+/* str */
+PyObject *
+sr_py_core_frame_str(PyObject *self)
+{
+ struct sr_py_core_frame *this = (struct sr_py_core_frame*)self;
+ struct sr_strbuf *buf = sr_strbuf_new();
+
+ if (this->frame->address != 0)
+ sr_strbuf_append_strf(buf, "[0x%016"PRIx64"] ", this->frame->address);
+
+ if (this->frame->function_name)
+ sr_strbuf_append_strf(buf, "%s ", this->frame->function_name);
+
+ if (this->frame->build_id)
+ sr_strbuf_append_strf(buf, "%s+0x%"PRIx64" ", this->frame->build_id,
+ this->frame->build_id_offset);
+
+ if (this->frame->file_name)
+ sr_strbuf_append_strf(buf, "[%s] ", this->frame->file_name);
+
+ if (this->frame->fingerprint)
+ sr_strbuf_append_strf(buf, "fingerprint: %s (%shashed)", this->frame->fingerprint,
+ (this->frame->fingerprint_hashed ? "" : "not "));
+
+ char *str = sr_strbuf_free_nobuf(buf);
+ PyObject *result = Py_BuildValue("s", str);
+ free(str);
+ return result;
+}
+
+/* methods */
+PyObject *
+sr_py_core_frame_dup(PyObject *self, PyObject *args)
+{
+ struct sr_py_core_frame *this = (struct sr_py_core_frame*)self;
+ struct sr_py_core_frame *fo = (struct sr_py_core_frame*)
+ PyObject_New(struct sr_py_core_frame, &sr_py_core_frame_type);
+
+ if (!fo)
+ return PyErr_NoMemory();
+
+ fo->frame = sr_core_frame_dup(this->frame, false);
+
+ return (PyObject*)fo;
+}
diff --git a/python/py_core_frame.h b/python/py_core_frame.h
new file mode 100644
index 0000000..dc4a3a2
--- /dev/null
+++ b/python/py_core_frame.h
@@ -0,0 +1,69 @@
+/*
+ py_core_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_PY_CORE_FRAME_H
+#define SATYR_PY_CORE_FRAME_H
+
+/**
+ * @file
+ * @brief Python bindings for core frame.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+#include <structmember.h>
+
+PyTypeObject sr_py_core_frame_type;
+
+/* The beginning of this structure has to have the same layout as
+ * sr_py_base_frame.
+ */
+struct sr_py_core_frame
+{
+ PyObject_HEAD
+ struct sr_core_frame *frame;
+};
+
+/**
+ * Constructor.
+ */
+PyObject *sr_py_core_frame_new(PyTypeObject *object,
+ PyObject *args, PyObject *kwds);
+
+/**
+ * Destructor.
+ */
+void sr_py_core_frame_free(PyObject *object);
+
+/**
+ * str
+ */
+PyObject *sr_py_core_frame_str(PyObject *self);
+
+/* methods */
+PyObject *sr_py_core_frame_dup(PyObject *self, PyObject *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/python/py_core_stacktrace.c b/python/py_core_stacktrace.c
new file mode 100644
index 0000000..976e994
--- /dev/null
+++ b/python/py_core_stacktrace.c
@@ -0,0 +1,212 @@
+/*
+ py_core_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 "py_base_stacktrace.h"
+#include "py_core_stacktrace.h"
+#include "py_core_thread.h"
+#include "py_core_frame.h"
+#include "py_common.h"
+#include "strbuf.h"
+#include "core/stacktrace.h"
+#include "core/thread.h"
+#include "stacktrace.h"
+
+#define stacktrace_doc "satyr.CoreStacktrace - class representing a core stacktrace\n" \
+ "Usage:\n" \
+ "satyr.CoreStacktrace() - creates an empty stacktrace\n" \
+ "satyr.CoreStacktrace(json) - creates stacktrace object from JSON string"
+
+#define b_dup_doc "Usage: stacktrace.dup()\n" \
+ "Returns: satyr.CoreStacktrace - a new clone of core stacktrace\n" \
+ "Clones the stacktrace object. All new structures are independent " \
+ "on the original object."
+
+static PyMethodDef
+core_stacktrace_methods[] =
+{
+ /* methods */
+ { "dup", sr_py_core_stacktrace_dup, METH_NOARGS, b_dup_doc },
+ { NULL },
+};
+
+/* See python/py_common.h and python/py_gdb_frame.c for generic getters/setters documentation. */
+#define GSOFF_PY_STRUCT sr_py_core_stacktrace
+#define GSOFF_PY_MEMBER stacktrace
+#define GSOFF_C_STRUCT sr_core_stacktrace
+GSOFF_START
+GSOFF_MEMBER(signal),
+GSOFF_MEMBER(executable)
+GSOFF_END
+
+static PyGetSetDef
+stacktrace_getset[] =
+{
+ SR_ATTRIBUTE_UINT16(signal, "Signal number (int)" ),
+ SR_ATTRIBUTE_STRING(executable, "Name of the executable (string)" ),
+ { NULL }
+};
+
+PyTypeObject sr_py_core_stacktrace_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "satyr.CoreStacktrace", /* tp_name */
+ sizeof(struct sr_py_core_stacktrace), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ sr_py_core_stacktrace_free, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ sr_py_core_stacktrace_str, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ stacktrace_doc, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ core_stacktrace_methods, /* tp_methods */
+ NULL, /* tp_members */
+ stacktrace_getset, /* tp_getset */
+ &sr_py_multi_stacktrace_type, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ NULL, /* tp_init */
+ NULL, /* tp_alloc */
+ sr_py_core_stacktrace_new, /* tp_new */
+ NULL, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+};
+
+/* constructor */
+PyObject *
+sr_py_core_stacktrace_new(PyTypeObject *object,
+ PyObject *args,
+ PyObject *kwds)
+{
+ struct sr_py_core_stacktrace *bo = (struct sr_py_core_stacktrace*)
+ PyObject_New(struct sr_py_core_stacktrace,
+ &sr_py_core_stacktrace_type);
+
+ if (!bo)
+ return PyErr_NoMemory();
+
+ bo->thread_type = &sr_py_core_thread_type;
+ bo->frame_type = &sr_py_core_frame_type;
+
+ const char *str = NULL;
+ if (!PyArg_ParseTuple(args, "|s", &str))
+ return NULL;
+
+ if (str)
+ {
+ char *error_msg;
+ bo->stacktrace = sr_core_stacktrace_from_json_text(str, &error_msg);
+ if (!bo->stacktrace)
+ {
+ PyErr_SetString(PyExc_ValueError, error_msg);
+ free(error_msg);
+ return NULL;
+ }
+ bo->threads = threads_to_python_list((struct sr_stacktrace *)bo->stacktrace,
+ bo->thread_type, bo->frame_type);
+ if (!bo->threads)
+ return NULL;
+ }
+ else
+ {
+ bo->threads = PyList_New(0);
+ bo->stacktrace = sr_core_stacktrace_new();
+ }
+
+ return (PyObject *)bo;
+}
+
+/* destructor */
+void
+sr_py_core_stacktrace_free(PyObject *object)
+{
+ struct sr_py_core_stacktrace *this = (struct sr_py_core_stacktrace*)object;
+ /* the list will decref all of its elements */
+ Py_DECREF(this->threads);
+ this->stacktrace->threads = NULL;
+ sr_core_stacktrace_free(this->stacktrace);
+ PyObject_Del(object);
+}
+
+/* str */
+PyObject *
+sr_py_core_stacktrace_str(PyObject *self)
+{
+ struct sr_py_core_stacktrace *this = (struct sr_py_core_stacktrace *)self;
+ struct sr_strbuf *buf = sr_strbuf_new();
+ sr_strbuf_append_strf(buf, "Core stacktrace with %zd threads",
+ (ssize_t)(PyList_Size(this->threads)));
+ char *str = sr_strbuf_free_nobuf(buf);
+ PyObject *result = Py_BuildValue("s", str);
+ free(str);
+ return result;
+}
+
+/* methods */
+PyObject *
+sr_py_core_stacktrace_dup(PyObject *self, PyObject *args)
+{
+ struct sr_py_core_stacktrace *this = (struct sr_py_core_stacktrace*)self;
+ if (threads_prepare_linked_list((struct sr_py_multi_stacktrace *)this) < 0)
+ return NULL;
+
+ struct sr_py_core_stacktrace *bo = (struct sr_py_core_stacktrace*)
+ PyObject_New(struct sr_py_core_stacktrace,
+ &sr_py_core_stacktrace_type);
+
+ if (!bo)
+ return PyErr_NoMemory();
+
+ bo->thread_type = &sr_py_core_thread_type;
+ bo->frame_type = &sr_py_core_frame_type;
+
+ bo->stacktrace = sr_core_stacktrace_dup(this->stacktrace);
+ if (!bo->stacktrace)
+ return NULL;
+
+ bo->threads = threads_to_python_list((struct sr_stacktrace *)bo->stacktrace,
+ bo->thread_type, bo->frame_type);
+ if (!bo->threads)
+ return NULL;
+
+ return (PyObject*)bo;
+}
diff --git a/python/py_core_stacktrace.h b/python/py_core_stacktrace.h
new file mode 100644
index 0000000..4cb00ad
--- /dev/null
+++ b/python/py_core_stacktrace.h
@@ -0,0 +1,71 @@
+/*
+ py_core_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_PY_CORE_STACKTRACE_H
+#define SATYR_PY_CORE_STACKTRACE_H
+
+/**
+ * @file
+ * @brief Python bindings for Core stack trace.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+#include <structmember.h>
+
+struct sr_py_core_frame;
+struct sr_py_core_thread;
+
+PyTypeObject sr_py_core_stacktrace_type;
+
+/* The beginning of this structure has to have the same layout as
+ * sr_py_multi_thread_stacktrace.
+ */
+struct sr_py_core_stacktrace
+{
+ PyObject_HEAD
+ struct sr_core_stacktrace *stacktrace;
+ PyObject *threads;
+ PyTypeObject *thread_type;
+ PyTypeObject *frame_type;
+};
+
+/* constructor */
+PyObject *sr_py_core_stacktrace_new(PyTypeObject *object,
+ PyObject *args,
+ PyObject *kwds);
+
+/* destructor */
+void sr_py_core_stacktrace_free(PyObject *object);
+
+/* str */
+PyObject *sr_py_core_stacktrace_str(PyObject *self);
+
+/* methods */
+PyObject *sr_py_core_stacktrace_dup(PyObject *self, PyObject *args);
+PyObject *sr_py_core_stacktrace_normalize(PyObject *self, PyObject *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/python/py_core_thread.c b/python/py_core_thread.c
new file mode 100644
index 0000000..2d27f9f
--- /dev/null
+++ b/python/py_core_thread.c
@@ -0,0 +1,161 @@
+/*
+ py_core_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 "py_common.h"
+#include "py_base_thread.h"
+#include "py_core_thread.h"
+#include "py_core_frame.h"
+#include "strbuf.h"
+#include "core/thread.h"
+#include "core/frame.h"
+#include "utils.h"
+
+#define thread_doc "satyr.CoreThread - class representing a thread in a stacktrace\n" \
+ "Usage:\n" \
+ "satyr.CoreThread() - creates an empty thread"
+
+#define t_dup_doc "Usage: thread.dup()\n" \
+ "Returns: satyr.CoreThread - a new clone of thread\n" \
+ "Clones the thread object. All new structures are independent " \
+ "on the original object."
+
+static PyMethodDef
+core_thread_methods[] =
+{
+ /* methods */
+ { "dup", sr_py_core_thread_dup, METH_NOARGS, t_dup_doc },
+ { NULL },
+};
+
+PyTypeObject sr_py_core_thread_type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "satyr.CoreThread", /* tp_name */
+ sizeof(struct sr_py_core_thread), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ sr_py_core_thread_free, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ sr_py_core_thread_str, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ thread_doc, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ core_thread_methods, /* tp_methods */
+ NULL, /* tp_members */
+ NULL, /* tp_getset */
+ &sr_py_base_thread_type, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ NULL, /* tp_init */
+ NULL, /* tp_alloc */
+ sr_py_core_thread_new, /* tp_new */
+ NULL, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+};
+
+/* constructor */
+PyObject *
+sr_py_core_thread_new(PyTypeObject *object, PyObject *args, PyObject *kwds)
+{
+ struct sr_py_core_thread *to = (struct sr_py_core_thread*)
+ PyObject_New(struct sr_py_core_thread,
+ &sr_py_core_thread_type);
+
+ if (!to)
+ return PyErr_NoMemory();
+
+ to->frame_type = &sr_py_core_frame_type;
+ to->frames = PyList_New(0);
+ to->thread = sr_core_thread_new();
+
+ return (PyObject *)to;
+}
+
+/* destructor */
+void
+sr_py_core_thread_free(PyObject *object)
+{
+ struct sr_py_core_thread *this = (struct sr_py_core_thread *)object;
+ /* the list will decref all of its elements */
+ Py_DECREF(this->frames);
+ this->thread->frames = NULL;
+ sr_core_thread_free(this->thread);
+ PyObject_Del(object);
+}
+
+PyObject *
+sr_py_core_thread_str(PyObject *self)
+{
+ struct sr_py_core_thread *this = (struct sr_py_core_thread *)self;
+ struct sr_strbuf *buf = sr_strbuf_new();
+ sr_strbuf_append_strf(buf, "Thread with %zd frames", (ssize_t)(PyList_Size(this->frames)));
+
+ char *str = sr_strbuf_free_nobuf(buf);
+ PyObject *result = Py_BuildValue("s", str);
+ free(str);
+ return result;
+}
+
+/* methods */
+PyObject *
+sr_py_core_thread_dup(PyObject *self, PyObject *args)
+{
+ struct sr_py_core_thread *this = (struct sr_py_core_thread *)self;
+ if (frames_prepare_linked_list((struct sr_py_base_thread *)this) < 0)
+ return NULL;
+
+ struct sr_py_core_thread *to = (struct sr_py_core_thread*)
+ PyObject_New(struct sr_py_core_thread, &sr_py_core_thread_type);
+
+ if (!to)
+ return PyErr_NoMemory();
+
+ to->frame_type = &sr_py_core_frame_type;
+ to->thread = sr_core_thread_dup(this->thread, false);
+ if (!to->thread)
+ return NULL;
+
+ to->frames = frames_to_python_list((struct sr_thread *)to->thread, to->frame_type);
+
+ return (PyObject *)to;
+}
diff --git a/python/py_core_thread.h b/python/py_core_thread.h
new file mode 100644
index 0000000..2890ff1
--- /dev/null
+++ b/python/py_core_thread.h
@@ -0,0 +1,66 @@
+/*
+ py_core_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_PY_CORE_THREAD_H
+#define SATYR_PY_CORE_THREAD_H
+
+/**
+ * @file
+ * @brief Python bindings for Core thread.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+#include <structmember.h>
+
+PyTypeObject sr_py_core_thread_type;
+
+/* The beginning of this structure has to have the same layout as
+ * sr_py_base_thread.
+ */
+struct sr_py_core_thread
+{
+ PyObject_HEAD
+ struct sr_core_thread *thread;
+ PyObject *frames;
+ PyTypeObject *frame_type;
+};
+
+/* constructor */
+PyObject *sr_py_core_thread_new(PyTypeObject *object,
+ PyObject *args,
+ PyObject *kwds);
+
+/* destructor */
+void sr_py_core_thread_free(PyObject *object);
+
+/* str */
+PyObject *sr_py_core_thread_str(PyObject *self);
+
+/* methods */
+PyObject *sr_py_core_thread_dup(PyObject *self, PyObject *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/python/py_module.c b/python/py_module.c
index f049a03..23c8882 100644
--- a/python/py_module.c
+++ b/python/py_module.c
@@ -14,6 +14,9 @@
#include "py_java_frame.h"
#include "py_java_thread.h"
#include "py_java_stacktrace.h"
+#include "py_core_frame.h"
+#include "py_core_thread.h"
+#include "py_core_stacktrace.h"
#include "py_metrics.h"
#include "distance.h"
@@ -136,6 +139,24 @@ init_satyr()
return;
}
+ if (PyType_Ready(&sr_py_core_frame_type) < 0)
+ {
+ puts("PyType_Ready(&sr_py_core_frame_type) < 0");
+ return;
+ }
+
+ if (PyType_Ready(&sr_py_core_thread_type) < 0)
+ {
+ puts("PyType_Ready(&sr_py_core_thread_type) < 0");
+ return;
+ }
+
+ if (PyType_Ready(&sr_py_core_stacktrace_type) < 0)
+ {
+ puts("PyType_Ready(&sr_py_core_stacktrace_type) < 0");
+ return;
+ }
+
PyObject *module = Py_InitModule("_satyr", module_methods);
if (!module)
@@ -231,4 +252,16 @@ init_satyr()
PyModule_AddObject(module, "JavaStacktrace",
(PyObject *)&sr_py_java_stacktrace_type);
+ Py_INCREF(&sr_py_core_frame_type);
+ PyModule_AddObject(module, "CoreFrame",
+ (PyObject *)&sr_py_core_frame_type);
+
+ Py_INCREF(&sr_py_core_thread_type);
+ PyModule_AddObject(module, "CoreThread",
+ (PyObject *)&sr_py_core_thread_type);
+
+ Py_INCREF(&sr_py_core_stacktrace_type);
+ PyModule_AddObject(module, "CoreStacktrace",
+ (PyObject *)&sr_py_core_stacktrace_type);
+
}
diff --git a/tests/python/core.py b/tests/python/core.py
new file mode 100755
index 0000000..cf09ba0
--- /dev/null
+++ b/tests/python/core.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+
+import unittest
+from test_helpers import *
+
+contents = load_input_contents('../json_files/core-01')
+threads_expected = 2
+frames_expected = 6
+expected_short_text = '''#1 raise in /usr/lib64/libc-2.15.so
+#2 abort in /usr/lib64/libc-2.15.so
+#3 92ebaf825e4f492952c45189cb9ffc6541f8599b+1123 in /usr/bin/will_abort
+#4 __libc_start_main in /usr/lib64/libc-2.15.so
+'''
+
+class TestCoreStacktrace(BindingsTestCase):
+ def setUp(self):
+ self.trace = satyr.CoreStacktrace(contents)
+
+ def test_correct_thread_count(self):
+ self.assertEqual(len(self.trace.threads), threads_expected)
+
+ def test_correct_frame_count(self):
+ self.assertEqual(frame_count(self.trace), frames_expected)
+
+ def test_dup(self):
+ dup = self.trace.dup()
+ self.assertNotEqual(id(dup.threads), id(self.trace.threads))
+ self.assertEqual(dup.threads, self.trace.threads)
+
+ dup.threads = dup.threads[:5]
+ dup2 = dup.dup()
+ self.assertEqual(len(dup.threads), len(dup2.threads))
+ self.assertNotEqual(id(dup.threads), id(dup2.threads))
+
+ def test_prepare_linked_list(self):
+ dup = self.trace.dup()
+ dup.threads = dup.threads[:5]
+ dup2 = dup.dup()
+ self.assertTrue(len(dup.threads) <= 5)
+
+ def test_str(self):
+ out = str(self.trace)
+ self.assertTrue(('Core stacktrace with %d threads' % threads_expected) in out)
+
+ def test_to_short_text(self):
+ self.assertEqual(self.trace.to_short_text(8), expected_short_text)
+
+ def test_bthash(self):
+ self.assertEqual(self.trace.get_bthash(), '6ebee2edb486ee24a3280c18b0db5353bbc22014')
+
+ def test_getset(self):
+ self.assertGetSetCorrect(self.trace, 'signal', 6, 42)
+ self.assertGetSetCorrect(self.trace, 'executable', '/usr/bin/will_abort', '/bin/true')
+
+ def test_crash_thread(self):
+ self.assertTrue(self.trace.crash_thread is self.trace.threads[1])
+
+class TestCoreThread(BindingsTestCase):
+ def setUp(self):
+ self.thread = satyr.CoreStacktrace(contents).threads[0]
+
+ def test_cmp(self):
+ self.assertEqual(self.thread, self.thread)
+ dup = self.thread.dup()
+ self.assertEqual(self.thread, dup)
+ dup.frames[0].build_id = 'wut'
+ self.assertNotEqual(self.thread, dup)
+
+ def test_duphash(self):
+ expected_plain = '''Thread
+92ebaf825e4f492952c45189cb9ffc6541f8599b+0x2a
+92ebaf825e4f492952c45189cb9ffc6541f8599b+0x29ee
+'''
+ self.assertEqual(self.thread.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain)
+ self.assertEqual(self.thread.get_duphash(), 'ad8486fa45ff39ffed7a07f3b68b8f406ebe2550')
+
+class TestCoreFrame(BindingsTestCase):
+ def setUp(self):
+ self.frame = satyr.CoreStacktrace(contents).threads[1].frames[0]
+
+ def test_str(self):
+ out = str(self.frame)
+ self.assertEquals(out, '[0x0000003739a35935] raise cc10c72da62c93033e227ffbe2670f2c4fbbde1a+0x35935 '
+ '[/usr/lib64/libc-2.15.so] '
+ 'fingerprint: f33186a4c862fb0751bca60701f553b829210477 (hashed)')
+
+ def test_dup(self):
+ dup = self.frame.dup()
+ self.assertEqual(dup, self.frame)
+
+ dup.function_name = 'other'
+ self.assertNotEqual(dup, self.frame)
+
+ def test_cmp(self):
+ dup = self.frame.dup()
+ self.assertEqual(dup, dup)
+ self.assertEqual(dup, self.frame)
+ self.assertEqual(dup, self.frame)
+ self.assertNotEqual(id(dup), id(self.frame))
+ dup.function_name = 'another'
+ self.assertNotEqual(dup, self.frame)
+ self.assertFalse(dup > self.frame)
+ self.assertTrue(dup < self.frame)
+
+ def test_getset(self):
+ self.assertGetSetCorrect(self.frame, 'address', 237190207797, 5000)
+ self.assertGetSetCorrect(self.frame, 'build_id', 'cc10c72da62c93033e227ffbe2670f2c4fbbde1a', 'abcdef')
+ self.assertGetSetCorrect(self.frame, 'build_id_offset', 219445, 44)
+ self.assertGetSetCorrect(self.frame, 'function_name', 'raise', 'lower')
+ self.assertGetSetCorrect(self.frame, 'file_name', '/usr/lib64/libc-2.15.so', '/u/l/x')
+ self.assertGetSetCorrect(self.frame, 'fingerprint', 'f33186a4c862fb0751bca60701f553b829210477', 'xxx')
+ self.assertGetSetCorrect(self.frame, 'fingerprint_hashed', True, False)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/python_bindings.at b/tests/python_bindings.at
index c0e12cf..a7ab98d 100644
--- a/tests/python_bindings.at
+++ b/tests/python_bindings.at
@@ -10,4 +10,5 @@ AT_TEST_PYTHON([gdb])
AT_TEST_PYTHON([koops])
AT_TEST_PYTHON([python])
AT_TEST_PYTHON([java])
+AT_TEST_PYTHON([core])
AT_TEST_PYTHON([metrics])
--
1.8.3.1
More information about the Crash-catcher
mailing list