[SATYR PATCH 4/6] python: expose crash thread lookup
Martin Milata
mmilata at redhat.com
Wed Aug 7 15:53:23 UTC 2013
GDB-specific crash thread finding code was removed.
Signed-off-by: Martin Milata <mmilata at redhat.com>
---
python/py_base_stacktrace.c | 87 +++++++++++++++++++++++++++++++++++++++++++--
python/py_base_stacktrace.h | 5 +++
python/py_gdb_stacktrace.c | 54 ----------------------------
python/py_gdb_stacktrace.h | 2 --
tests/python/gdb.py | 3 ++
tests/python/koops.py | 3 ++
tests/python/python.py | 3 ++
7 files changed, 99 insertions(+), 58 deletions(-)
diff --git a/python/py_base_stacktrace.c b/python/py_base_stacktrace.c
index 72d96f0..399acd9 100644
--- a/python/py_base_stacktrace.c
+++ b/python/py_base_stacktrace.c
@@ -35,6 +35,8 @@
"Returns: string - hash of the stacktrace\n" \
"flags: integer - bitwise sum of flags (BTHASH_NORMAL, BTHASH_NOHASH)"
+#define crash_thread_doc "Reference to the thread that caused the crash, if known"
+
#define threads_doc "A list containing the objects representing threads in the stacktrace."
static PyMethodDef
@@ -45,6 +47,13 @@ single_methods[] =
{ NULL },
};
+static PyGetSetDef
+single_getset[] =
+{
+ { (char *)"crash_thread", sr_py_single_stacktrace_get_crash, sr_py_single_stacktrace_set_crash, (char *)crash_thread_doc, NULL },
+ { NULL },
+};
+
PyTypeObject sr_py_single_stacktrace_type = {
PyObject_HEAD_INIT(NULL)
0,
@@ -76,7 +85,7 @@ PyTypeObject sr_py_single_stacktrace_type = {
NULL, /* tp_iternext */
single_methods, /* tp_methods */
NULL, /* tp_members */
- NULL, /* tp_getset */
+ single_getset, /* tp_getset */
&sr_py_base_thread_type, /* tp_base */
NULL, /* tp_dict */
NULL, /* tp_descr_get */
@@ -109,6 +118,13 @@ multi_methods[] =
{ NULL },
};
+static PyGetSetDef
+multi_getset[] =
+{
+ { (char *)"crash_thread", sr_py_multi_stacktrace_get_crash, sr_py_multi_stacktrace_set_crash, (char *)crash_thread_doc, NULL },
+ { NULL },
+};
+
PyTypeObject sr_py_multi_stacktrace_type = {
PyObject_HEAD_INIT(NULL)
0,
@@ -140,7 +156,7 @@ PyTypeObject sr_py_multi_stacktrace_type = {
NULL, /* tp_iternext */
multi_methods, /* tp_methods */
multi_members, /* tp_members */
- NULL, /* tp_getset */
+ multi_getset, /* tp_getset */
NULL, /* tp_base */
NULL, /* tp_dict */
NULL, /* tp_descr_get */
@@ -330,3 +346,70 @@ sr_py_multi_stacktrace_get_bthash(PyObject *self, PyObject *args)
free(hash);
return result;
}
+
+PyObject *
+sr_py_single_stacktrace_get_crash(PyObject *self, void *unused)
+{
+ return self;
+}
+
+int
+sr_py_single_stacktrace_set_crash(PyObject *self, PyObject *value, void *unused)
+{
+ PyErr_SetString(PyExc_AttributeError,
+ "Cannot set crash thread of single threaded stacktrace.");
+ return -1;
+}
+
+PyObject *
+sr_py_multi_stacktrace_get_crash(PyObject *self, void *unused)
+{
+ struct sr_py_multi_stacktrace *this = (struct sr_py_multi_stacktrace *)self;
+
+ if (threads_prepare_linked_list(this) < 0)
+ return NULL;
+
+ struct sr_thread *crash_thread = sr_stacktrace_find_crash_thread(this->stacktrace);
+ if (crash_thread == NULL)
+ Py_RETURN_NONE;
+
+ if (!PyList_Check(this->threads))
+ {
+ PyErr_SetString(PyExc_TypeError, "Attribute 'threads' is not a list.");
+ return NULL;
+ }
+
+ int i;
+ PyObject *item;
+ for (i = 0; i < PyList_Size(this->threads); ++i)
+ {
+ item = PyList_GetItem(this->threads, i);
+ if (!item)
+ return NULL;
+
+ if (!PyObject_TypeCheck(item, this->thread_type))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "List of threads contains object that is not a thread.");
+ return NULL;
+ }
+
+ struct sr_py_base_thread *thread = (struct sr_py_base_thread *)item;
+ if (thread->thread == crash_thread)
+ {
+ /* TODO incref? */
+ return item;
+ }
+ }
+
+ /* Something went wrong - sr_stacktrace_find_crash_thread returned non-NULL
+ * but we don't have such thread in the list. */
+ Py_RETURN_NONE;
+}
+
+int
+sr_py_multi_stacktrace_set_crash(PyObject *self, PyObject *value, void *unused)
+{
+ PyErr_SetString(PyExc_NotImplementedError, "Setting crash thread is not implemented.");
+ return -1;
+}
diff --git a/python/py_base_stacktrace.h b/python/py_base_stacktrace.h
index 41eee62..c7945f0 100644
--- a/python/py_base_stacktrace.h
+++ b/python/py_base_stacktrace.h
@@ -58,6 +58,11 @@ PyObject *sr_py_multi_stacktrace_to_short_text(PyObject *self, PyObject *args);
PyObject *sr_py_single_stacktrace_get_bthash(PyObject *self, PyObject *args);
PyObject *sr_py_multi_stacktrace_get_bthash(PyObject *self, PyObject *args);
+PyObject *sr_py_single_stacktrace_get_crash(PyObject *self, void *unused);
+int sr_py_single_stacktrace_set_crash(PyObject *self, PyObject *value, void *unused);
+PyObject *sr_py_multi_stacktrace_get_crash(PyObject *self, void *unused);
+int sr_py_multi_stacktrace_set_crash(PyObject *self, PyObject *value, void *unused);
+
#ifdef __cplusplus
}
#endif
diff --git a/python/py_gdb_stacktrace.c b/python/py_gdb_stacktrace.c
index 4b47b94..2de69c9 100644
--- a/python/py_gdb_stacktrace.c
+++ b/python/py_gdb_stacktrace.c
@@ -26,11 +26,6 @@
"Finds crash frame in the stacktrace. Also sets the " \
"stacktrace.crashframe field."
-#define b_find_crash_thread_doc "Usage: stacktrace.find_crash_thread()\n" \
- "Returns: satyr.Thread - crash thread\n" \
- "Finds crash thread in the stacktrace. Also sets the " \
- "stacktrace.crashthread field."
-
#define b_limit_frame_depth_doc "Usage: stacktrace.limit_frame_depth(N)\n" \
"N: positive integer - frame depth\n" \
"Crops all threads to only contain first N frames."
@@ -63,10 +58,6 @@
"calling the find_crash_frame method, a reference to " \
"satyr.Frame object is stored into the field."
-#define b_crashthread_doc (char *)"Readonly. By default the field contains None. After " \
- "calling the find_crash_thread method, a reference to " \
- "satyr.Thread object is stored into the field."
-
#define b_threads_doc (char *)"A list containing the satyr.Thread objects " \
"representing threads in the stacktrace."
@@ -79,7 +70,6 @@ gdb_stacktrace_methods[] =
/* methods */
{ "dup", sr_py_gdb_stacktrace_dup, METH_NOARGS, b_dup_doc },
{ "find_crash_frame", sr_py_gdb_stacktrace_find_crash_frame, METH_NOARGS, b_find_crash_frame_doc },
- { "find_crash_thread", sr_py_gdb_stacktrace_find_crash_thread, METH_NOARGS, b_find_crash_thread_doc },
{ "limit_frame_depth", sr_py_gdb_stacktrace_limit_frame_depth, METH_VARARGS, b_limit_frame_depth_doc },
{ "quality_simple", sr_py_gdb_stacktrace_quality_simple, METH_NOARGS, b_quality_simple_doc },
{ "quality_complex", sr_py_gdb_stacktrace_quality_complex, METH_NOARGS, b_quality_complex_doc },
@@ -94,7 +84,6 @@ static PyMemberDef
gdb_stacktrace_members[] =
{
{ (char *)"crashframe", T_OBJECT_EX, offsetof(struct sr_py_gdb_stacktrace, crashframe), READONLY, b_crashframe_doc },
- { (char *)"crashthread", T_OBJECT_EX, offsetof(struct sr_py_gdb_stacktrace, crashthread), READONLY, b_crashthread_doc },
{ (char *)"libs", T_OBJECT_EX, offsetof(struct sr_py_gdb_stacktrace, libs), 0, b_libs_doc },
{ NULL },
};
@@ -303,7 +292,6 @@ sr_py_gdb_stacktrace_new(PyTypeObject *object,
bo->thread_type = &sr_py_gdb_thread_type;
bo->frame_type = &sr_py_gdb_frame_type;
bo->crashframe = (struct sr_py_gdb_frame*)Py_None;
- bo->crashthread = (struct sr_py_gdb_thread*)Py_None;
if (str)
{
/* ToDo parse */
@@ -389,15 +377,6 @@ sr_py_gdb_stacktrace_dup(PyObject *self, PyObject *args)
if (!bo->libs)
return NULL;
- if (PyObject_TypeCheck(this->crashthread, &sr_py_gdb_thread_type))
- {
- bo->crashthread = (struct sr_py_gdb_thread *)sr_py_gdb_thread_dup((PyObject*)this->crashthread, PyTuple_New(0));
- if (!bo->crashthread)
- return NULL;
- }
- else
- bo->crashthread = (struct sr_py_gdb_thread*)Py_None;
-
if (PyObject_TypeCheck(this->crashframe, &sr_py_gdb_frame_type))
{
bo->crashframe = (struct sr_py_gdb_frame*)sr_py_gdb_thread_dup((PyObject*)this->crashframe, PyTuple_New(0));
@@ -441,39 +420,6 @@ sr_py_gdb_stacktrace_find_crash_frame(PyObject *self, PyObject *args)
}
PyObject *
-sr_py_gdb_stacktrace_find_crash_thread(PyObject *self, PyObject *args)
-{
- struct sr_py_gdb_stacktrace *this = (struct sr_py_gdb_stacktrace*)self;
- if (gdb_prepare_linked_lists(this) < 0)
- return NULL;
-
- /* destroys linked list - need to rebuild python list */
- struct sr_gdb_thread *thread = sr_gdb_stacktrace_find_crash_thread(this->stacktrace);
- if (!thread)
- {
- PyErr_SetString(PyExc_LookupError, "Crash thread not found");
- return NULL;
- }
-
- struct sr_py_gdb_thread *result = (struct sr_py_gdb_thread*)
- PyObject_New(struct sr_py_gdb_thread, &sr_py_gdb_thread_type);
-
- if (!result)
- return PyErr_NoMemory();
-
- result->frame_type = &sr_py_gdb_frame_type;
- result->thread = sr_gdb_thread_dup(thread, false);
- result->frames = frames_to_python_list((struct sr_thread *)result->thread,
- result->frame_type);
- this->crashthread = result;
-
- if (stacktrace_rebuild_thread_python_list(this) < 0)
- return NULL;
-
- return (PyObject *)result;
-}
-
-PyObject *
sr_py_gdb_stacktrace_limit_frame_depth(PyObject *self, PyObject *args)
{
struct sr_py_gdb_stacktrace *this = (struct sr_py_gdb_stacktrace*)self;
diff --git a/python/py_gdb_stacktrace.h b/python/py_gdb_stacktrace.h
index 5c7e1f1..f5a1765 100644
--- a/python/py_gdb_stacktrace.h
+++ b/python/py_gdb_stacktrace.h
@@ -48,7 +48,6 @@ struct sr_py_gdb_stacktrace
PyTypeObject *thread_type;
PyTypeObject *frame_type;
struct sr_py_gdb_frame *crashframe;
- struct sr_py_gdb_thread *crashthread;
PyObject *libs;
};
@@ -66,7 +65,6 @@ PyObject *sr_py_gdb_stacktrace_str(PyObject *self);
/* methods */
PyObject *sr_py_gdb_stacktrace_dup(PyObject *self, PyObject *args);
PyObject *sr_py_gdb_stacktrace_find_crash_frame(PyObject *self, PyObject *args);
-PyObject *sr_py_gdb_stacktrace_find_crash_thread(PyObject *self, PyObject *args);
PyObject *sr_py_gdb_stacktrace_limit_frame_depth(PyObject *self, PyObject *args);
PyObject *sr_py_gdb_stacktrace_quality_simple(PyObject *self, PyObject *args);
PyObject *sr_py_gdb_stacktrace_quality_complex(PyObject *self, PyObject *args);
diff --git a/tests/python/gdb.py b/tests/python/gdb.py
index f271fe0..ea3f81d 100755
--- a/tests/python/gdb.py
+++ b/tests/python/gdb.py
@@ -55,6 +55,9 @@ class TestGdbStacktrace(BindingsTestCase):
def test_bthash(self):
self.assertEqual(self.trace.get_bthash(), 'd0fcdc87161ccb093f7efeff12218321d8fd5298')
+ def test_crash_thread(self):
+ self.assertTrue(self.trace.crash_thread is self.trace.threads[1])
+
class TestGdbThread(BindingsTestCase):
def setUp(self):
self.thread = satyr.GdbStacktrace(contents).threads[0]
diff --git a/tests/python/koops.py b/tests/python/koops.py
index 241ad21..260cb6e 100755
--- a/tests/python/koops.py
+++ b/tests/python/koops.py
@@ -70,6 +70,9 @@ class TestKerneloops(BindingsTestCase):
self.assertEqual(self.koops.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain)
self.assertEqual(self.koops.get_duphash(), '53f62f9d6f7de093f50653863d200f4789ace7ef')
+ def test_crash_thread(self):
+ self.assertTrue(self.koops.crash_thread is self.koops)
+
class TestKoopsFrame(BindingsTestCase):
def setUp(self):
self.frame = satyr.Kerneloops(contents).frames[0]
diff --git a/tests/python/python.py b/tests/python/python.py
index 9529536..13c3bd7 100755
--- a/tests/python/python.py
+++ b/tests/python/python.py
@@ -87,6 +87,9 @@ class TestPythonStacktrace(BindingsTestCase):
self.assertEqual(self.trace.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain)
self.assertEqual(self.trace.get_duphash(), '2c8e509a33966a08df1dd8b2348e850d1bc5b776')
+ def test_crash_thread(self):
+ self.assertTrue(self.trace.crash_thread is self.trace)
+
class TestPythonFrame(BindingsTestCase):
def setUp(self):
self.frame = satyr.PythonStacktrace(contents).frames[-1]
--
1.8.3.1
More information about the Crash-catcher
mailing list