https://github.com/python/cpython/commit/8dfa840773d1d6bae1bf6e0dfa07618ea10c9d71 commit: 8dfa840773d1d6bae1bf6e0dfa07618ea10c9d71 branch: main author: Peter Bierma <zintensity...@gmail.com> committer: pablogsal <pablog...@gmail.com> date: 2025-04-21T20:48:02+01:00 summary:
gh-127604: Add C stack dumps to `faulthandler` (#128159) files: A Misc/NEWS.d/next/Library/2024-12-21-13-31-55.gh-issue-127604.etL5mf.rst M Doc/library/faulthandler.rst M Doc/whatsnew/3.14.rst M Include/internal/pycore_faulthandler.h M Include/internal/pycore_traceback.h M Lib/test/test_faulthandler.py M Lib/test/test_inspect/test_inspect.py M Modules/faulthandler.c M Python/traceback.c M Tools/c-analyzer/cpython/ignored.tsv M configure M configure.ac M pyconfig.h.in diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst index b7df9f6b9bcf96..8823c8f8edf567 100644 --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -66,10 +66,41 @@ Dumping the traceback Added support for passing file descriptor to this function. +Dumping the C stack +------------------- + +.. versionadded:: next + +.. function:: dump_c_stack(file=sys.stderr) + + Dump the C stack trace of the current thread into *file*. + + If the Python build does not support it or the operating system + does not provide a stack trace, then this prints an error in place + of a dumped C stack. + +.. _c-stack-compatibility: + +C Stack Compatibility +********************* + +If the system does not support the C-level :manpage:`backtrace(3)`, +:manpage:`backtrace_symbols(3)`, or :manpage:`dladdr(3)`, then C stack dumps +will not work. An error will be printed instead of the stack. + +Additionally, some compilers do not support :term:`CPython's <CPython>` +implementation of C stack dumps. As a result, a different error may be printed +instead of the stack, even if the the operating system supports dumping stacks. + +.. note:: + + Dumping C stacks can be arbitrarily slow, depending on the DWARF level + of the binaries in the call stack. + Fault handler state ------------------- -.. function:: enable(file=sys.stderr, all_threads=True) +.. function:: enable(file=sys.stderr, all_threads=True, c_stack=True) Enable the fault handler: install handlers for the :const:`~signal.SIGSEGV`, :const:`~signal.SIGFPE`, :const:`~signal.SIGABRT`, :const:`~signal.SIGBUS` @@ -81,6 +112,10 @@ Fault handler state The *file* must be kept open until the fault handler is disabled: see :ref:`issue with file descriptors <faulthandler-fd>`. + If *c_stack* is ``True``, then the C stack trace is printed after the Python + traceback, unless the system does not support it. See :func:`dump_c_stack` for + more information on compatibility. + .. versionchanged:: 3.5 Added support for passing file descriptor to this function. @@ -95,6 +130,9 @@ Fault handler state Only the current thread is dumped if the :term:`GIL` is disabled to prevent the risk of data races. + .. versionchanged:: next + The dump now displays the C stack trace if *c_stack* is true. + .. function:: disable() Disable the fault handler: uninstall the signal handlers installed by diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 51f4286efd6785..c9b0c57aa2ba04 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -699,6 +699,15 @@ errno (Contributed by James Roy in :gh:`126585`.) +faulthandler +------------ + +* Add support for printing the C stack trace on systems that + :ref:`support it <c-stack-compatibility>` via :func:`faulthandler.dump_c_stack` + or via the *c_stack* argument in :func:`faulthandler.enable`. + (Contributed by Peter Bierma in :gh:`127604`.) + + fnmatch ------- diff --git a/Include/internal/pycore_faulthandler.h b/Include/internal/pycore_faulthandler.h index 6dd7d8d7ca9792..78cd657e6ae5ae 100644 --- a/Include/internal/pycore_faulthandler.h +++ b/Include/internal/pycore_faulthandler.h @@ -56,6 +56,7 @@ struct _faulthandler_runtime_state { #ifdef MS_WINDOWS void *exc_handler; #endif + int c_stack; } fatal_error; struct { diff --git a/Include/internal/pycore_traceback.h b/Include/internal/pycore_traceback.h index 741108a957a35c..d71dd2886999a6 100644 --- a/Include/internal/pycore_traceback.h +++ b/Include/internal/pycore_traceback.h @@ -99,6 +99,9 @@ extern int _PyTraceBack_Print( extern int _Py_WriteIndentedMargin(int, const char*, PyObject *); extern int _Py_WriteIndent(int, PyObject *); +// Export for the faulthandler module +PyAPI_FUNC(void) _Py_DumpStack(int fd); + #ifdef __cplusplus } #endif diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 2a8c96f049efd0..371c63adce9412 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -55,6 +55,13 @@ def temporary_filename(): finally: os_helper.unlink(filename) + +ADDRESS_EXPR = "0x[0-9a-f]+" +C_STACK_REGEX = [ + r"Current thread's C stack trace \(most recent call first\):", + fr'( Binary file ".+"(, at .*(\+|-){ADDRESS_EXPR})? \[{ADDRESS_EXPR}\])|(<.+>)' +] + class FaultHandlerTests(unittest.TestCase): def get_output(self, code, filename=None, fd=None): @@ -103,6 +110,7 @@ def check_error(self, code, lineno, fatal_error, *, fd=None, know_current_thread=True, py_fatal_error=False, garbage_collecting=False, + c_stack=True, function='<module>'): """ Check that the fault handler for fatal errors is enabled and check the @@ -134,6 +142,8 @@ def check_error(self, code, lineno, fatal_error, *, if garbage_collecting and not all_threads_disabled: regex.append(' Garbage-collecting') regex.append(fr' File "<string>", line {lineno} in {function}') + if c_stack: + regex.extend(C_STACK_REGEX) regex = '\n'.join(regex) if other_regex: @@ -950,5 +960,35 @@ def run(self): _, exitcode = self.get_output(code) self.assertEqual(exitcode, 0) + def check_c_stack(self, output): + starting_line = output.pop(0) + self.assertRegex(starting_line, C_STACK_REGEX[0]) + self.assertGreater(len(output), 0) + + for line in output: + with self.subTest(line=line): + if line != '': # Ignore trailing or leading newlines + self.assertRegex(line, C_STACK_REGEX[1]) + + + def test_dump_c_stack(self): + code = dedent(""" + import faulthandler + faulthandler.dump_c_stack() + """) + output, exitcode = self.get_output(code) + self.assertEqual(exitcode, 0) + self.check_c_stack(output) + + + def test_dump_c_stack_file(self): + import tempfile + + with tempfile.TemporaryFile("w+") as tmp: + faulthandler.dump_c_stack(file=tmp) + tmp.flush() # Just in case + tmp.seek(0) + self.check_c_stack(tmp.read().split("\n")) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index daae990458d708..06f0ca36f9796f 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -5760,7 +5760,7 @@ def test_errno_module_has_signatures(self): def test_faulthandler_module_has_signatures(self): import faulthandler - unsupported_signature = {'dump_traceback', 'dump_traceback_later', 'enable'} + unsupported_signature = {'dump_traceback', 'dump_traceback_later', 'enable', 'dump_c_stack'} unsupported_signature |= {name for name in ['register'] if hasattr(faulthandler, name)} self._test_module_has_signatures(faulthandler, unsupported_signature=unsupported_signature) diff --git a/Misc/NEWS.d/next/Library/2024-12-21-13-31-55.gh-issue-127604.etL5mf.rst b/Misc/NEWS.d/next/Library/2024-12-21-13-31-55.gh-issue-127604.etL5mf.rst new file mode 100644 index 00000000000000..c4d2938a50010d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-12-21-13-31-55.gh-issue-127604.etL5mf.rst @@ -0,0 +1,3 @@ +Add support for printing the C stack trace on systems that support it via +:func:`faulthandler.dump_c_stack` or via the *c_stack* argument in +:func:`faulthandler.enable`. diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index cc5ecdcc4f96e9..563ffd9fbbdadb 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" diff --git a/Python/traceback.c b/Python/traceback.c index d30ba586cfcca4..7319382f053eae 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -18,7 +18,25 @@ #ifdef HAVE_UNISTD_H # include <unistd.h> // lseek() #endif +#if defined(HAVE_EXECINFO_H) && defined(HAVE_DLFCN_H) && defined(HAVE_LINK_H) +# include <execinfo.h> // backtrace(), backtrace_symbols() +# include <dlfcn.h> // dladdr1() +# include <link.h> // struct DL_info +# if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_DLADDR1) +# define CAN_C_BACKTRACE +# endif +#endif +#if defined(__STDC_NO_VLA__) && (__STDC_NO_VLA__ == 1) +/* Use alloca() for VLAs. */ +# define VLA(type, name, size) type *name = alloca(size) +#elif !defined(__STDC_NO_VLA__) || (__STDC_NO_VLA__ == 0) +/* Use actual C VLAs.*/ +# define VLA(type, name, size) type name[size] +#elif defined(CAN_C_BACKTRACE) +/* VLAs are not possible. Disable C stack trace functions. */ +# undef CAN_C_BACKTRACE +#endif #define OFF(x) offsetof(PyTracebackObject, x) #define PUTS(fd, str) (void)_Py_write_noraise(fd, str, strlen(str)) @@ -1166,3 +1184,93 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, return NULL; } +#ifdef CAN_C_BACKTRACE +/* Based on glibc's implementation of backtrace_symbols(), but only uses stack memory. */ +void +_Py_backtrace_symbols_fd(int fd, void *const *array, Py_ssize_t size) +{ + VLA(Dl_info, info, size); + VLA(int, status, size); + /* Fill in the information we can get from dladdr() */ + for (Py_ssize_t i = 0; i < size; ++i) { + struct link_map *map; + status[i] = dladdr1(array[i], &info[i], (void **)&map, RTLD_DL_LINKMAP); + if (status[i] != 0 + && info[i].dli_fname != NULL + && info[i].dli_fname[0] != '\0') { + /* The load bias is more useful to the user than the load + address. The use of these addresses is to calculate an + address in the ELF file, so its prelinked bias is not + something we want to subtract out */ + info[i].dli_fbase = (void *) map->l_addr; + } + } + for (Py_ssize_t i = 0; i < size; ++i) { + if (status[i] == 0 + || info[i].dli_fname == NULL + || info[i].dli_fname[0] == '\0' + ) { + dprintf(fd, " Binary file '<unknown>' [%p]\n", array[i]); + continue; + } + + if (info[i].dli_sname == NULL) { + /* We found no symbol name to use, so describe it as + relative to the file. */ + info[i].dli_saddr = info[i].dli_fbase; + } + + if (info[i].dli_sname == NULL + && info[i].dli_saddr == 0) { + dprintf(fd, " Binary file \"%s\" [%p]\n", + info[i].dli_fname, + array[i]); + } + else { + char sign; + ptrdiff_t offset; + if (array[i] >= (void *) info[i].dli_saddr) { + sign = '+'; + offset = array[i] - info[i].dli_saddr; + } + else { + sign = '-'; + offset = info[i].dli_saddr - array[i]; + } + const char *symbol_name = info[i].dli_sname != NULL ? info[i].dli_sname : ""; + dprintf(fd, " Binary file \"%s\", at %s%c%#tx [%p]\n", + info[i].dli_fname, + symbol_name, + sign, offset, array[i]); + } + } +} + +void +_Py_DumpStack(int fd) +{ +#define BACKTRACE_SIZE 32 + PUTS(fd, "Current thread's C stack trace (most recent call first):\n"); + VLA(void *, callstack, BACKTRACE_SIZE); + int frames = backtrace(callstack, BACKTRACE_SIZE); + if (frames == 0) { + // Some systems won't return anything for the stack trace + PUTS(fd, " <system returned no stack trace>\n"); + return; + } + + _Py_backtrace_symbols_fd(fd, callstack, frames); + if (frames == BACKTRACE_SIZE) { + PUTS(fd, " <truncated rest of calls>\n"); + } + +#undef BACKTRACE_SIZE +} +#else +void +_Py_DumpStack(int fd) +{ + PUTS(fd, "Current thread's C stack trace (most recent call first):\n"); + PUTS(fd, " <cannot get C stack on this system>\n"); +} +#endif diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 14dc5007b65861..a33619b1b345e2 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -166,6 +166,7 @@ Python/sysmodule.c - _preinit_xoptions - # thread-safety # XXX need race protection? Modules/faulthandler.c faulthandler_dump_traceback reentrant - +Modules/faulthandler.c faulthandler_dump_c_stack reentrant - Python/pylifecycle.c _Py_FatalErrorFormat reentrant - Python/pylifecycle.c fatal_error reentrant - diff --git a/configure b/configure index 284263dff48f87..2685fdcd7b435f 100755 --- a/configure +++ b/configure @@ -2313,6 +2313,70 @@ fi } # ac_fn_c_try_run +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (void); below. */ + +#include <limits.h> +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (void); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main (void) +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$3=yes" +else case e in #( + e) eval "$3=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; +esac +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache @@ -2567,70 +2631,6 @@ rm -f conftest.val } # ac_fn_c_compute_int -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case <limits.h> declares $2. - For example, HP-UX 11i <limits.h> declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (void); below. */ - -#include <limits.h> -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (void); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main (void) -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - # ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR # ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR @@ -11877,6 +11877,39 @@ fi fi +# for faulthandler + for ac_header in execinfo.h link.h dlfcn.h +do : + as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | sed "$as_sed_sh"` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_$ac_header" | sed "$as_sed_cpp"` 1 +_ACEOF + ac_fn_c_check_func "$LINENO" "backtrace" "ac_cv_func_backtrace" +if test "x$ac_cv_func_backtrace" = xyes +then : + printf "%s\n" "#define HAVE_BACKTRACE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "backtrace_symbols" "ac_cv_func_backtrace_symbols" +if test "x$ac_cv_func_backtrace_symbols" = xyes +then : + printf "%s\n" "#define HAVE_BACKTRACE_SYMBOLS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "dladdr1" "ac_cv_func_dladdr1" +if test "x$ac_cv_func_dladdr1" = xyes +then : + printf "%s\n" "#define HAVE_DLADDR1 1" >>confdefs.h + +fi + +fi + +done + # bluetooth/bluetooth.h has been known to not compile with -std=c99. # http://permalink.gmane.org/gmane.linux.bluez.kernel/22294 SAVE_CFLAGS=$CFLAGS diff --git a/configure.ac b/configure.ac index 99ebe111cfb184..55b499faa8d06e 100644 --- a/configure.ac +++ b/configure.ac @@ -2985,6 +2985,10 @@ AC_CHECK_HEADERS([ \ AC_HEADER_DIRENT AC_HEADER_MAJOR +# for faulthandler +AC_CHECK_HEADERS([execinfo.h link.h dlfcn.h], + [AC_CHECK_FUNCS(backtrace backtrace_symbols dladdr1)]) + # bluetooth/bluetooth.h has been known to not compile with -std=c99. # http://permalink.gmane.org/gmane.linux.bluez.kernel/22294 SAVE_CFLAGS=$CFLAGS diff --git a/pyconfig.h.in b/pyconfig.h.in index aa086d49e90a5b..c8a0174bd38aee 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -89,6 +89,12 @@ /* Define to 1 if you have the 'atanh' function. */ #undef HAVE_ATANH +/* Define to 1 if you have the 'backtrace' function. */ +#undef HAVE_BACKTRACE + +/* Define to 1 if you have the 'backtrace_symbols' function. */ +#undef HAVE_BACKTRACE_SYMBOLS + /* Define if you have the 'bind' function. */ #undef HAVE_BIND @@ -289,6 +295,9 @@ /* Define to 1 if you have the 'dladdr' function. */ #undef HAVE_DLADDR +/* Define to 1 if you have the 'dladdr1' function. */ +#undef HAVE_DLADDR1 + /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H @@ -334,6 +343,9 @@ /* Define if you have the 'eventfd' function. */ #undef HAVE_EVENTFD +/* Define to 1 if you have the <execinfo.h> header file. */ +#undef HAVE_EXECINFO_H + /* Define to 1 if you have the 'execv' function. */ #undef HAVE_EXECV @@ -705,6 +717,9 @@ /* Define to 1 if you have the 'linkat' function. */ #undef HAVE_LINKAT +/* Define to 1 if you have the <link.h> header file. */ +#undef HAVE_LINK_H + /* Define to 1 if you have the <linux/auxvec.h> header file. */ #undef HAVE_LINUX_AUXVEC_H _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com