diff options
Diffstat (limited to 'Modules/faulthandler.c')
-rw-r--r-- | Modules/faulthandler.c | 60 |
1 files changed, 57 insertions, 3 deletions
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index cc5ecdcc4f9..563ffd9fbbd 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -9,10 +9,10 @@ #include "pycore_sysmodule.h" // _PySys_GetRequiredAttr() #include "pycore_time.h" // _PyTime_FromSecondsObject() #include "pycore_traceback.h" // _Py_DumpTracebackThreads - #ifdef HAVE_UNISTD_H # include <unistd.h> // _exit() #endif + #include <signal.h> // sigaction() #include <stdlib.h> // abort() #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) && defined(HAVE_PTHREAD_H) @@ -210,6 +210,25 @@ faulthandler_dump_traceback(int fd, int all_threads, reentrant = 0; } +static void +faulthandler_dump_c_stack(int fd) +{ + static volatile int reentrant = 0; + + if (reentrant) { + return; + } + + reentrant = 1; + + if (fatal_error.c_stack) { + PUTS(fd, "\n"); + _Py_DumpStack(fd); + } + + reentrant = 0; +} + static PyObject* faulthandler_dump_traceback_py(PyObject *self, PyObject *args, PyObject *kwargs) @@ -260,6 +279,33 @@ faulthandler_dump_traceback_py(PyObject *self, Py_RETURN_NONE; } +static PyObject * +faulthandler_dump_c_stack_py(PyObject *self, + PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = {"file", NULL}; + PyObject *file = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|O:dump_c_stack", kwlist, + &file)) { + return NULL; + } + + int fd = faulthandler_get_fileno(&file); + if (fd < 0) { + return NULL; + } + + _Py_DumpStack(fd); + + if (PyErr_CheckSignals()) { + return NULL; + } + + Py_RETURN_NONE; +} + static void faulthandler_disable_fatal_handler(fault_handler_t *handler) { @@ -350,6 +396,7 @@ faulthandler_fatal_error(int signum) faulthandler_dump_traceback(fd, deduce_all_threads(), fatal_error.interp); + faulthandler_dump_c_stack(fd); _Py_DumpExtensionModules(fd, fatal_error.interp); @@ -425,6 +472,7 @@ faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info) faulthandler_dump_traceback(fd, deduce_all_threads(), fatal_error.interp); + faulthandler_dump_c_stack(fd); /* call the next exception handler */ return EXCEPTION_CONTINUE_SEARCH; @@ -519,14 +567,15 @@ faulthandler_enable(void) static PyObject* faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs) { - static char *kwlist[] = {"file", "all_threads", NULL}; + static char *kwlist[] = {"file", "all_threads", "c_stack", NULL}; PyObject *file = NULL; int all_threads = 1; int fd; + int c_stack = 1; PyThreadState *tstate; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|Op:enable", kwlist, &file, &all_threads)) + "|Opp:enable", kwlist, &file, &all_threads, &c_stack)) return NULL; fd = faulthandler_get_fileno(&file); @@ -543,6 +592,7 @@ faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs) fatal_error.fd = fd; fatal_error.all_threads = all_threads; fatal_error.interp = PyThreadState_GetInterpreter(tstate); + fatal_error.c_stack = c_stack; if (faulthandler_enable() < 0) { return NULL; @@ -1238,6 +1288,10 @@ static PyMethodDef module_methods[] = { PyDoc_STR("dump_traceback($module, /, file=sys.stderr, all_threads=True)\n--\n\n" "Dump the traceback of the current thread, or of all threads " "if all_threads is True, into file.")}, + {"dump_c_stack", + _PyCFunction_CAST(faulthandler_dump_c_stack_py), METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("dump_c_stack($module, /, file=sys.stderr)\n--\n\n" + "Dump the C stack of the current thread.")}, {"dump_traceback_later", _PyCFunction_CAST(faulthandler_dump_traceback_later), METH_VARARGS|METH_KEYWORDS, PyDoc_STR("dump_traceback_later($module, /, timeout, repeat=False, file=sys.stderr, exit=False)\n--\n\n" |