+ format_tb_func = PyObject_GetAttrString(traceback_module,
+ "format_tb");
+ if (!format_tb_func) {
+ BT_LOGE("Cannot find `format_tb` attribute in `traceback` module.");
+ goto error;
+ }
+
+ if (!PyCallable_Check(format_tb_func)) {
+ BT_LOGE("`traceback.format_tb` attribute is not callable.");
+ goto error;
+ }
+
+ /*
+ * If we are calling format_exception_only, `py_exc_tb` is NULL, so the
+ * effective argument list is of length 2.
+ */
+ exc_str_list = PyObject_CallFunctionObjArgs(
+ format_tb_func, py_exc_tb, NULL);
+ if (!exc_str_list) {
+ if (BT_LOG_ON_ERROR) {
+ BT_LOGE("Failed to call `traceback.format_tb` function:");
+ PyErr_Print();
+ }
+
+ goto error;
+ }
+
+ msg_buf = py_str_list_to_gstring(exc_str_list, log_level);
+ if (!msg_buf) {
+ goto error;
+ }
+
+error:
+ Py_XDECREF(traceback_module);
+ Py_XDECREF(format_tb_func);
+ Py_XDECREF(exc_str_list);
+
+ return msg_buf;
+}
+
+GString *bt_py_common_format_exception(PyObject *py_exc_type,
+ PyObject *py_exc_value, PyObject *py_exc_tb,
+ int log_level, bool chain)
+{
+ PyObject *traceback_module = NULL;
+ PyObject *format_exception_func = NULL;
+ PyObject *exc_str_list = NULL;
+ GString *msg_buf = NULL;
+ const char *format_exc_func_name;