assertion_failed(const char *file, int line, isc_assertiontype_t type,
const char *cond) {
void *tracebuf[BACKTRACE_MAXFRAME];
- int i, nframes;
+ int nframes;
isc_result_t result;
const char *logsuffix = "";
"%s:%d: %s(%s) failed%s", file, line,
isc_assertion_typetotext(type), cond, logsuffix);
if (result == ISC_R_SUCCESS) {
- for (i = 0; i < nframes; i++) {
+#if HAVE_BACKTRACE_SYMBOLS
+ char **strs = backtrace_symbols(tracebuf, nframes);
+ for (int i = 0; i < nframes; i++) {
+ isc_log_write(named_g_lctx,
+ NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN,
+ ISC_LOG_CRITICAL, "%s", strs[i]);
+ }
+#else /* HAVE_BACKTRACE_SYMBOLS */
+ for (int i = 0; i < nframes; i++) {
isc_log_write(
named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
"#%d %p in ??", i, tracebuf[i]);
}
+#endif /* HAVE_BACKTRACE_SYMBOLS */
}
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
CDEFINES =
CWARNINGS =
-BACKTRACECFLAGS = @BACKTRACECFLAGS@
DNSLIBS = ../../lib/dns/libdns.@A@ ${MAXMINDDB_LIBS} @DNS_CRYPTO_LIBS@
ISCLIBS = ../../lib/isc/libisc.@A@ ${OPENSSL_LIBS} ${JSON_C_LIBS} ${LIBXML2_LIBS} ${ZLIB_LIBS}
CDEFINES = @USE_GSSAPI@
CWARNINGS =
-BACKTRACECFLAGS = @BACKTRACECFLAGS@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
DNSLIBS = ../../../lib/dns/libdns.@A@ ${MAXMINDDB_LIBS} @DNS_CRYPTO_LIBS@
@BIND9_MAKE_RULES@
# disable optimization for backtrace test to get the expected result
-BTTEST_CFLAGS = ${BACKTRACECFLAGS} ${EXT_CFLAGS} ${ALL_CPPFLAGS} -g \
+BTTEST_CFLAGS = ${EXT_CFLAGS} ${ALL_CPPFLAGS} -g \
${ALWAYS_WARNINGS} ${STD_CWARNINGS} ${CWARNINGS} ${PTHREAD_CFLAGS}
all_tests: ${XTARGETS}
/* define if the ARM yield instruction is available */
#undef HAVE_ARM_YIELD
+/* 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 to 1 if the compiler supports __builtin_clz. */
#undef HAVE_BUILTIN_CLZ
/* Define to 1 if you have the `EVP_sha512' function. */
#undef HAVE_EVP_SHA512
+/* Define to 1 if you have the <execinfo.h> header file. */
+#undef HAVE_EXECINFO_H
+
/* Define to 1 if you have the `explicit_bzero' function. */
#undef HAVE_EXPLICIT_BZERO
/* Define to 1 if you have the <krb5/krb5.h> header file. */
#undef HAVE_KRB5_KRB5_H
-/* define if system have backtrace function */
-#undef HAVE_LIBCTRACE
-
/* Define if libidn2 was found */
#undef HAVE_LIBIDN2
/* Define to use default system tuning. */
#undef TUNE_LARGE
-/* define if we can use backtrace */
-#undef USE_BACKTRACE
-
/* Enable DNS Response Policy Service API */
#undef USE_DNSRPS
PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
-BACKTRACECFLAGS
CCNOOPT
CCOPT
STD_CWARNINGS
with_zlib
with_purify
with_gperftools_profiler
-enable_backtrace
enable_tcp_fastopen
with_readline
enable_isc_spnego
pthread rwlock
--enable-fips-mode enable FIPS mode in OpenSSL library [default=no]
--enable-native-pkcs11 use native PKCS11 for public-key crypto [default=no]
- --enable-backtrace log stack backtrace on abort [default=yes]
--disable-tcp-fastopen disable TCP Fast Open support [default=yes]
--disable-isc-spnego use SPNEGO from GSSAPI library
--disable-chroot disable chroot
-
#
# Use pkg-config
#
esac
#
-# enable/disable dumping stack backtrace. Also check if the system supports
-# glibc-compatible backtrace() function.
+# Check if the system supports glibc-compatible backtrace() function.
#
-# Check whether --enable-backtrace was given.
-if test "${enable_backtrace+set}" = set; then :
- enableval=$enable_backtrace;
+for ac_header in execinfo.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
+if test "x$ac_cv_header_execinfo_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_EXECINFO_H 1
+_ACEOF
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5
+$as_echo_n "checking for library containing backtrace... " >&6; }
+if ${ac_cv_search_backtrace+:} false; then :
+ $as_echo_n "(cached) " >&6
else
- enable_backtrace="yes"
-fi
-
-
-if test "$enable_backtrace" = "yes"; then :
-
-$as_echo "#define USE_BACKTRACE 1" >>confdefs.h
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <execinfo.h>
+
+/* 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 backtrace ();
int
main ()
{
-return (backtrace((void **)0, 0));
-
+return backtrace ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+for ac_lib in '' execinfo; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_backtrace=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_backtrace+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_backtrace+:} false; then :
-$as_echo "#define HAVE_LIBCTRACE 1" >>confdefs.h
+else
+ ac_cv_search_backtrace=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace" >&5
+$as_echo "$ac_cv_search_backtrace" >&6; }
+ac_res=$ac_cv_search_backtrace
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+ for ac_func in backtrace backtrace_symbols
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+fi
+done
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
+
fi
+done
+
+
+# AM_CONDITIONAL([HAVE_BACKTRACE], [test "$ac_cv_func_backtrace" = "yes"])
+
#
# File name extension for static archive files, for those few places
# where they are treated differently from dynamic ones.
AC_SUBST(STD_CWARNINGS)
AC_SUBST(CCOPT)
AC_SUBST(CCNOOPT)
-AC_SUBST(BACKTRACECFLAGS)
#
# Use pkg-config
esac
#
-# enable/disable dumping stack backtrace. Also check if the system supports
-# glibc-compatible backtrace() function.
+# Check if the system supports glibc-compatible backtrace() function.
#
-AC_ARG_ENABLE([backtrace],
- [AS_HELP_STRING([--enable-backtrace],
- [log stack backtrace on abort [default=yes]])],
- [], [enable_backtrace="yes"])
+AC_CHECK_HEADERS([execinfo.h],
+ [AC_SEARCH_LIBS([backtrace], [execinfo],
+ [AC_CHECK_FUNCS([backtrace backtrace_symbols])])])
-AS_IF([test "$enable_backtrace" = "yes"],
- [AC_DEFINE([USE_BACKTRACE], [1], [define if we can use backtrace])
- AC_LINK_IFELSE(
- [AC_LANG_PROGRAM(
- [[#include <execinfo.h>]],
- [[return (backtrace((void **)0, 0));]]
- )],
- [AC_DEFINE([HAVE_LIBCTRACE], [1], [define if system have backtrace function])]
- )])
+# AM_CONDITIONAL([HAVE_BACKTRACE], [test "$ac_cv_func_backtrace" = "yes"])
#
# File name extension for static archive files, for those few places
default_callback(const char *file, int line, isc_assertiontype_t type,
const char *cond) {
void *tracebuf[BACKTRACE_MAXFRAME];
- int i, nframes;
+ int nframes;
const char *logsuffix = ".";
isc_result_t result;
isc_assertion_typetotext(type), cond, logsuffix);
if (result == ISC_R_SUCCESS) {
- for (i = 0; i < nframes; i++) {
+#if HAVE_BACKTRACE_SYMBOLS
+ char **strs = backtrace_symbols(tracebuf, nframes);
+ for (int i = 0; i < nframes; i++) {
+ fprintf(stderr, "%s\n", strs[i]);
+ }
+#else /* HAVE_BACKTRACE_SYMBOLS */
+ for (int i = 0; i < nframes; i++) {
fprintf(stderr, "#%d %p in ??\n", i, tracebuf[i]);
}
+#endif /* HAVE_BACKTRACE_SYMBOLS */
}
fflush(stderr);
}
#include <stdlib.h>
#include <string.h>
-#ifdef HAVE_LIBCTRACE
+#ifdef HAVE_BACKTRACE
#include <execinfo.h>
-#endif /* ifdef HAVE_LIBCTRACE */
+#endif /* HAVE_BACKTRACE */
#include <isc/backtrace.h>
#include <isc/result.h>
#include <isc/util.h>
-#ifdef USE_BACKTRACE
-/*
- * Getting a back trace of a running process is tricky and highly platform
- * dependent. Our current approach is as follows:
- * 1. If the system library supports the "backtrace()" function, use it.
- * 2. Otherwise, if the compiler is gcc and the architecture is x86_64 or IA64,
- * then use gcc's (hidden) Unwind_Backtrace() function. Note that this
- * function doesn't work for C programs on many other architectures.
- * 3. Otherwise, if the architecture x86 or x86_64, try to unwind the stack
- * frame following frame pointers. This assumes the executable binary
- * compiled with frame pointers; this is not always true for x86_64 (rather,
- * compiler optimizations often disable frame pointers). The validation
- * checks in getnextframeptr() hopefully rejects bogus values stored in
- * the RBP register in such a case. If the backtrace function itself crashes
- * due to this problem, the whole package should be rebuilt with
- * --disable-backtrace.
- */
-#ifdef HAVE_LIBCTRACE
-#define BACKTRACE_LIBC
-#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__ia64__))
-#define BACKTRACE_GCC
-#elif defined(WIN32)
-#define BACKTRACE_WIN32
-#elif defined(__x86_64__) || defined(__i386__)
-#define BACKTRACE_X86STACK
-#else /* ifdef HAVE_LIBCTRACE */
-#define BACKTRACE_DISABLED
-#endif /* HAVE_LIBCTRACE */
-#else /* USE_BACKTRACE */
-#define BACKTRACE_DISABLED
-#endif /* USE_BACKTRACE */
-
-#ifdef BACKTRACE_LIBC
+#ifdef HAVE_BACKTRACE
isc_result_t
isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
- int n;
-
/*
* Validate the arguments: intentionally avoid using REQUIRE().
* See notes in backtrace.h.
* backtrace(3) includes this function itself in the address array,
* which should be eliminated from the returned sequence.
*/
- n = backtrace(addrs, maxaddrs);
+ int n = backtrace(addrs, maxaddrs);
if (n < 2) {
return (ISC_R_NOTFOUND);
}
n--;
- memmove(addrs, &addrs[1], sizeof(void *) * n);
+ memmove(addrs, &addrs[1], sizeof(addrs[0]) * n);
*nframes = n;
return (ISC_R_SUCCESS);
}
-#elif defined(BACKTRACE_GCC)
-extern int
-_Unwind_Backtrace(void *fn, void *a);
-extern void *
-_Unwind_GetIP(void *ctx);
-
-typedef struct {
- void **result;
- int max_depth;
- int skip_count;
- int count;
-} trace_arg_t;
-
-static int
-btcallback(void *uc, void *opq) {
- trace_arg_t *arg = (trace_arg_t *)opq;
-
- if (arg->skip_count > 0) {
- arg->skip_count--;
- } else {
- arg->result[arg->count++] = (void *)_Unwind_GetIP(uc);
- }
- if (arg->count == arg->max_depth) {
- return (5); /* _URC_END_OF_STACK */
- }
- return (0); /* _URC_NO_REASON */
-}
-
-isc_result_t
-isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
- trace_arg_t arg;
-
- /* Argument validation: see above. */
- if (addrs == NULL || nframes == NULL) {
- return (ISC_R_FAILURE);
- }
-
- arg.skip_count = 1;
- arg.result = addrs;
- arg.max_depth = maxaddrs;
- arg.count = 0;
- _Unwind_Backtrace(btcallback, &arg);
-
- *nframes = arg.count;
-
- return (ISC_R_SUCCESS);
-}
-#elif defined(BACKTRACE_WIN32)
-isc_result_t
-isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
- unsigned long ftc = (unsigned long)maxaddrs;
-
- *nframes = (int)CaptureStackBackTrace(1, ftc, addrs, NULL);
- return (ISC_R_SUCCESS);
-}
-#elif defined(BACKTRACE_X86STACK)
-#ifdef __x86_64__
-static unsigned long
-getrbp(void) {
- __asm("movq %rbp, %rax\n");
-}
-#endif /* ifdef __x86_64__ */
-
-static void **
-getnextframeptr(void **sp) {
- void **newsp = (void **)*sp;
-
- /*
- * Perform sanity check for the new frame pointer, derived from
- * google glog. This can actually be bogus depending on compiler.
- */
-
- /* prohibit the stack frames from growing downwards */
- if (newsp <= sp) {
- return (NULL);
- }
-
- /* A heuristics to reject "too large" frame: this actually happened. */
- if ((char *)newsp - (char *)sp > 100000) {
- return (NULL);
- }
-
- /*
- * Not sure if other checks used in glog are needed at this moment.
- * For our purposes we don't have to consider non-contiguous frames,
- * for example.
- */
-
- return (newsp);
-}
-
-isc_result_t
-isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
- int i = 0;
- void **sp;
-
- /* Argument validation: see above. */
- if (addrs == NULL || nframes == NULL) {
- return (ISC_R_FAILURE);
- }
-#ifdef __x86_64__
- sp = (void **)getrbp();
- if (sp == NULL) {
- return (ISC_R_NOTFOUND);
- }
- /*
- * sp is the frame ptr of this function itself due to the call to
- * getrbp(), so need to unwind one frame for consistency.
- */
- sp = getnextframeptr(sp);
-#else /* ifdef __x86_64__ */
- /*
- * i386: the frame pointer is stored 2 words below the address for the
- * first argument. Note that the body of this function cannot be
- * inlined since it depends on the address of the function argument.
- */
- sp = (void **)&addrs - 2;
-#endif /* ifdef __x86_64__ */
-
- while (sp != NULL && i < maxaddrs) {
- addrs[i++] = *(sp + 1);
- sp = getnextframeptr(sp);
- }
-
- *nframes = i;
-
- return (ISC_R_SUCCESS);
-}
-#elif defined(BACKTRACE_DISABLED)
+#else /* HAVE_BACKTRACE */
isc_result_t
isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
- /* Argument validation: see above. */
- if (addrs == NULL || nframes == NULL) {
- return (ISC_R_FAILURE);
- }
-
+ UNUSED(addrs);
UNUSED(maxaddrs);
+ UNUSED(nframes);
return (ISC_R_NOTIMPLEMENTED);
}
-#endif /* ifdef BACKTRACE_LIBC */
+#endif /* HAVE_BACKTRACE */
*** Imports
***/
+#if HAVE_BACKTRACE_SYMBOLS
+#include <execinfo.h>
+#endif /* HAVE_BACKTRACE_SYMBOLS */
+
#include <isc/types.h>
/***