[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