mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +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 @@ class FaultHandlerTests(unittest.TestCase):
|
|||
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 @@ class FaultHandlerTests(unittest.TestCase):
|
|||
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 @@ class FaultHandlerTests(unittest.TestCase):
|
|||
_, 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 @@ class TestSignatureDefinitions(unittest.TestCase):
|
|||
|
||||
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