]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Improve the backtrace to print symbols when backtrace_symbols() is available
authorOndřej Surý <ondrej@isc.org>
Wed, 11 Mar 2020 08:55:48 +0000 (09:55 +0100)
committerOndřej Surý <ondrej@isc.org>
Wed, 11 Mar 2020 19:32:21 +0000 (20:32 +0100)
The previous commit removed the code related to the internal symbol
table.  On platforms where available, we can now use backtrace_symbols()
to print more verbose symbols table to the output.

As there's now general availability of backtrace() and
backtrace_symbols() functions (see below), the commit also removes the
usage of glibc internals and the custom stack tracing.

* backtrace(), backtrace_symbols(), and backtrace_symbols_fd() are
  provided in glibc since version 2.1.
* backtrace(), backtrace_symbols(), and backtrace_symbols_fd() first
  appeared in Mac OS X 10.5.
* The backtrace() library of functions first appeared in NetBSD 7.0 and
  FreeBSD 10.0.

bin/named/main.c
bin/tests/Makefile.in
bin/tests/optional/Makefile.in
config.h.in
configure
configure.ac
lib/isc/assertions.c
lib/isc/backtrace.c
lib/isc/include/isc/backtrace.h

index d7150c47bdff45a3c014704d7d3c8df85689ed8f..19875e2ce883d186fd91cd14f54db035dd419db5 100644 (file)
@@ -197,7 +197,7 @@ static void
 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 = "";
 
@@ -222,12 +222,22 @@ assertion_failed(const char *file, int line, isc_assertiontype_t type,
                              "%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,
index 49a3d3aecb022e01f047243d159b4acddbb42558..dd3dddd438cbc71593ef5e06af7610d30f39e430 100644 (file)
@@ -18,7 +18,6 @@ CINCLUDES =   ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \
 
 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}
index 593610633a182efb05dd850889f6f26450d1fe30..b01bc5e04ddb0123a0c30bf147f5c27434323752 100644 (file)
@@ -19,7 +19,6 @@ CINCLUDES =   ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \
 CDEFINES =     @USE_GSSAPI@
 
 CWARNINGS =
-BACKTRACECFLAGS = @BACKTRACECFLAGS@
 PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
 
 DNSLIBS =      ../../../lib/dns/libdns.@A@ ${MAXMINDDB_LIBS} @DNS_CRYPTO_LIBS@
@@ -97,7 +96,7 @@ XSRCS =               adb_test.c \
 @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}
index 4d292f2950c9ad9b30fc2c6b48e550bd52323167..463841adbcb520566aa194e279cfc384e2fa8f4c 100644 (file)
 /* 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
 
index 2f3a2ceb1bd8b8cd2fed8a968943f167173a2240..063b66062224da7666b65f8a1c0b2bbc2c5bd04a 100755 (executable)
--- a/configure
+++ b/configure
@@ -775,7 +775,6 @@ XTARGETS
 PKG_CONFIG_LIBDIR
 PKG_CONFIG_PATH
 PKG_CONFIG
-BACKTRACECFLAGS
 CCNOOPT
 CCOPT
 STD_CWARNINGS
@@ -920,7 +919,6 @@ with_json_c
 with_zlib
 with_purify
 with_gperftools_profiler
-enable_backtrace
 enable_tcp_fastopen
 with_readline
 enable_isc_spnego
@@ -1626,7 +1624,6 @@ Optional Features:
                           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
@@ -12088,7 +12085,6 @@ fi
 
 
 
-
 #
 # Use pkg-config
 #
@@ -18681,43 +18677,89 @@ $as_echo "no" >&6; }
 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.
index 81bcc0ae51c36be22f07e3818a516e90fda3d99b..0f051587b4414ed3388d566820b2735b3007d074 100644 (file)
@@ -56,7 +56,6 @@ AC_SUBST(STD_CDEFINES)
 AC_SUBST(STD_CWARNINGS)
 AC_SUBST(CCOPT)
 AC_SUBST(CCNOOPT)
-AC_SUBST(BACKTRACECFLAGS)
 
 #
 # Use pkg-config
@@ -1425,23 +1424,13 @@ case $use_profiler in
 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
index cd5cda3b5f2da1b454d8aa0f39bfe5478d62f9d7..c2ca5f46a132d00958d0e9f2d5a78bf66aa12fff 100644 (file)
@@ -95,7 +95,7 @@ static void
 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;
 
@@ -108,9 +108,16 @@ default_callback(const char *file, int line, isc_assertiontype_t type,
                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);
 }
index aafff91b6a34d5d9f548d348062ab032ae987876..54699200b6b88cdccac8f174850959e165753458 100644 (file)
 
 #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.
@@ -70,154 +36,23 @@ isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
         * 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 */
index a7a5ff0f7a3972eaccfbe218add5644d00e6b557..c59dca87b74ecb44b2c60a6be32336482de78d61 100644 (file)
  ***   Imports
  ***/
 
+#if HAVE_BACKTRACE_SYMBOLS
+#include <execinfo.h>
+#endif /* HAVE_BACKTRACE_SYMBOLS */
+
 #include <isc/types.h>
 
 /***