X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=exception.c;h=9f8ee4ceb17b028179446b786d53ce318b7fbfb8;hb=8c3291c74998bddac4b355d2ffbaf94e22bad3a7;hp=9c3fa48d29453321936d79f5f5df8d6b1789d11b;hpb=f6c7eade2b8853b3d525b5cc0402e89ca74c1908;p=libsigrokdecode.git
diff --git a/exception.c b/exception.c
index 9c3fa48..9f8ee4c 100644
--- a/exception.c
+++ b/exception.c
@@ -17,75 +17,156 @@
* along with this program. If not, see .
*/
+#include
#include "libsigrokdecode-internal.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */
#include "libsigrokdecode.h"
-#include "config.h"
#include
#include
-#include /* Python header not pulled in by default. */
+
+static char *py_stringify(PyObject *py_obj)
+{
+ PyObject *py_str, *py_bytes;
+ char *str = NULL;
+
+ /* Note: Caller already ran PyGILState_Ensure(). */
+
+ if (!py_obj)
+ return NULL;
+
+ py_str = PyObject_Str(py_obj);
+ if (!py_str || !PyUnicode_Check(py_str))
+ goto cleanup;
+
+ py_bytes = PyUnicode_AsUTF8String(py_str);
+ if (!py_bytes)
+ goto cleanup;
+
+ str = g_strdup(PyBytes_AsString(py_bytes));
+ Py_DECREF(py_bytes);
+
+cleanup:
+ Py_XDECREF(py_str);
+ if (!str) {
+ PyErr_Clear();
+ srd_dbg("Failed to stringify object.");
+ }
+
+ return str;
+}
+
+static char *py_get_string_attr(PyObject *py_obj, const char *attr)
+{
+ PyObject *py_str, *py_bytes;
+ char *str = NULL;
+
+ /* Note: Caller already ran PyGILState_Ensure(). */
+
+ if (!py_obj)
+ return NULL;
+
+ py_str = PyObject_GetAttrString(py_obj, attr);
+ if (!py_str || !PyUnicode_Check(py_str))
+ goto cleanup;
+
+ py_bytes = PyUnicode_AsUTF8String(py_str);
+ if (!py_bytes)
+ goto cleanup;
+
+ str = g_strdup(PyBytes_AsString(py_bytes));
+ Py_DECREF(py_bytes);
+
+cleanup:
+ Py_XDECREF(py_str);
+ if (!str) {
+ PyErr_Clear();
+ srd_dbg("Failed to get object attribute %s.", attr);
+ }
+
+ return str;
+}
/** @private */
SRD_PRIV void srd_exception_catch(const char *format, ...)
{
- PyObject *etype, *evalue, *etb, *py_str;
- PyTracebackObject *py_tb;
- GString *msg;
+ int i, ret;
va_list args;
- char *ename, *str, *tracestr;
+ PyObject *py_etype, *py_evalue, *py_etraceback;
+ PyObject *py_mod, *py_func, *py_tracefmt;
+ char *msg, *etype_name, *evalue_str, *outstr;
+ const char *etype_name_fallback;
+ PyGILState_STATE gstate;
+ GString *s;
- if (!PyErr_Occurred())
- /* Nothing is wrong. */
- return;
+ py_etype = py_evalue = py_etraceback = py_mod = py_func = NULL;
- PyErr_Fetch(&etype, &evalue, &etb);
- PyErr_NormalizeException(&etype, &evalue, &etb);
+ va_start(args, format);
+ msg = g_strdup_vprintf(format, args);
+ va_end(args);
+
+ gstate = PyGILState_Ensure();
- if (!(py_str = PyObject_Str(evalue))) {
- /* Shouldn't happen. */
- srd_dbg("Failed to convert exception value to string.");
- return;
+ PyErr_Fetch(&py_etype, &py_evalue, &py_etraceback);
+ if (!py_etype) {
+ /* No current exception, so just print the message. */
+ srd_err("%s.", msg);
+ goto cleanup;
}
+ PyErr_NormalizeException(&py_etype, &py_evalue, &py_etraceback);
- msg = g_string_sized_new(128);
- va_start(args, format);
- g_string_vprintf(msg, format, args);
- va_end(args);
+ etype_name = py_get_string_attr(py_etype, "__name__");
+ evalue_str = py_stringify(py_evalue);
+ etype_name_fallback = (etype_name) ? etype_name : "(unknown exception)";
- /* Can be NULL. */
- if (evalue)
- ename = (char *)Py_TYPE(evalue)->tp_name;
+ if (evalue_str)
+ srd_err("%s: %s: %s", etype_name_fallback, msg, evalue_str);
else
- ename = "(unknown exception)";
-
- /* Send the exception error message(s) to srd_err(). */
- py_str_as_str(py_str, &str);
- g_string_append(msg, ename);
- g_string_append(msg, ": ");
- g_string_append(msg, str);
- Py_DecRef(py_str);
- srd_err(msg->str);
-
- /* Send a more precise error location to srd_dbg(), if we have it. */
- if (etb && etb != Py_None) {
- tracestr = NULL;
- py_tb = (PyTracebackObject *)etb;
- py_str = PyUnicode_FromFormat("%U:%d in %U",
- py_tb->tb_frame->f_code->co_filename,
- py_tb->tb_frame->f_lineno,
- py_tb->tb_frame->f_code->co_name);
- py_str_as_str(py_str, &tracestr);
- Py_DecRef(py_str);
- g_string_printf(msg, "%s in %s: %s", ename, tracestr, str);
- srd_dbg(msg->str);
- g_free(tracestr);
+ srd_err("%s: %s.", etype_name_fallback, msg);
+
+ g_free(evalue_str);
+ g_free(etype_name);
+
+ /* If there is no traceback object, we are done. */
+ if (!py_etraceback)
+ goto cleanup;
+
+ py_mod = py_import_by_name("traceback");
+ if (!py_mod)
+ goto cleanup;
+
+ py_func = PyObject_GetAttrString(py_mod, "format_exception");
+ if (!py_func || !PyCallable_Check(py_func))
+ goto cleanup;
+
+ /* Call into Python to format the stack trace. */
+ py_tracefmt = PyObject_CallFunctionObjArgs(py_func,
+ py_etype, py_evalue, py_etraceback, NULL);
+ if (!py_tracefmt || !PyList_Check(py_tracefmt))
+ goto cleanup;
+
+ s = g_string_sized_new(128);
+ for (i = 0; i < PyList_Size(py_tracefmt); i++) {
+ ret = py_listitem_as_str(py_tracefmt, i, &outstr);
+ if (ret == 0) {
+ s = g_string_append(s, outstr);
+ g_free(outstr);
+ }
}
- g_free(str);
- g_string_free(msg, TRUE);
+ srd_err("%s", s->str);
+ g_string_free(s, TRUE);
+
+ Py_DECREF(py_tracefmt);
- Py_XDECREF(etype);
- Py_XDECREF(evalue);
- Py_XDECREF(etb);
+cleanup:
+ Py_XDECREF(py_func);
+ Py_XDECREF(py_mod);
+ Py_XDECREF(py_etraceback);
+ Py_XDECREF(py_evalue);
+ Py_XDECREF(py_etype);
/* Just in case. */
PyErr_Clear();
+
+ PyGILState_Release(gstate);
+
+ g_free(msg);
}