mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-127604: Add C stack dumps to faulthandler (#128159)
				
					
				
			This commit is contained in:
		
							parent
							
								
									ea8ec95cfa
								
							
						
					
					
						commit
						8dfa840773
					
				
					 13 changed files with 378 additions and 69 deletions
				
			
		|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
| ------- | ||||
| 
 | ||||
|  |  | |||
|  | @ -56,6 +56,7 @@ struct _faulthandler_runtime_state { | |||
| #ifdef MS_WINDOWS | ||||
|         void *exc_handler; | ||||
| #endif | ||||
|         int c_stack; | ||||
|     } fatal_error; | ||||
| 
 | ||||
|     struct { | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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`. | ||||
|  | @ -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" | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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	- | ||||
| 
 | ||||
|  |  | |||
| Can't render this file because it has a wrong number of fields in line 4. | 
							
								
								
									
										161
									
								
								configure
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										161
									
								
								configure
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Peter Bierma
						Peter Bierma