]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2667. [func] Add support for logging stack backtrace on assertion
authorTatuya JINMEI 神明達哉 <jinmei@isc.org>
Tue, 1 Sep 2009 18:40:25 +0000 (18:40 +0000)
committerTatuya JINMEI 神明達哉 <jinmei@isc.org>
Tue, 1 Sep 2009 18:40:25 +0000 (18:40 +0000)
failure (not available for all platforms). [RT #19780]
9.7.0

22 files changed:
CHANGES
bin/check/Makefile.in
bin/confgen/Makefile.in
bin/dig/Makefile.in
bin/dnssec/Makefile.in
bin/named/Makefile.in
bin/named/main.c
bin/nsupdate/Makefile.in
bin/rndc/Makefile.in
bin/tests/Makefile.in
bin/tests/backtrace_test.c [new file with mode: 0644]
bin/tools/Makefile.in
config.h.in
configure.in
lib/isc/Makefile.in
lib/isc/assertions.c
lib/isc/backtrace-emptytbl.c [new file with mode: 0644]
lib/isc/backtrace.c [new file with mode: 0644]
lib/isc/include/isc/backtrace.h [new file with mode: 0644]
lib/isc/include/isc/platform.h.in
lib/isc/include/isc/types.h
make/rules.in

diff --git a/CHANGES b/CHANGES
index ba70d925d3aad261dd7fcaf34b5218cdc02e6c0d..c7bae302eb6b1977d45a668f678e6acec5530a79 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+2667.  [func]          Add support for logging stack backtrace on assertion
+                       failure (not available for all platforms). [RT #19780]
+
 2666.  [func]          Added an 'options' argument to dns_name_fromstring()
                        (API change from 9.7.0a2). [RT #20196]
 
index 488a143d83bfbd96459d395333c54bdf82213823..39af25cbe89dbbdbc9c83309f2f95335474c21d6 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.33 2009/09/01 00:22:24 jinmei Exp $
+# $Id: Makefile.in,v 1.34 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -32,6 +32,7 @@ CWARNINGS =
 DNSLIBS =      ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
 ISCCFGLIBS =   ../../lib/isccfg/libisccfg.@A@
 ISCLIBS =      ../../lib/isc/libisc.@A@
+ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@
 BIND9LIBS =    ../../lib/bind9/libbind9.@A@
 
 DNSDEPLIBS =   ../../lib/dns/libdns.@A@
@@ -39,7 +40,8 @@ ISCCFGDEPLIBS =       ../../lib/isccfg/libisccfg.@A@
 ISCDEPLIBS =   ../../lib/isc/libisc.@A@
 BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@
 
-LIBS =         @LIBS@
+LIBS =         ${ISCLIBS} @LIBS@
+NOSYMLIBS =    ${ISCNOSYMLIBS} @LIBS@
 
 SUBDIRS =
 
@@ -69,14 +71,14 @@ named-checkzone.@O@: named-checkzone.c
 
 named-checkconf@EXEEXT@: named-checkconf.@O@ check-tool.@O@ ${ISCDEPLIBS} \
                ${ISCCFGDEPLIBS} ${BIND9DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       named-checkconf.@O@ check-tool.@O@ ${BIND9LIBS} ${ISCCFGLIBS} \
-       ${DNSLIBS} ${ISCLIBS} ${LIBS}
+       export BASEOBJS="named-checkconf.@O@ check-tool.@O@"; \
+       export LIBS0="${BIND9LIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \
+       ${FINALBUILDCMD}
 
 named-checkzone@EXEEXT@: named-checkzone.@O@ check-tool.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       named-checkzone.@O@ check-tool.@O@ ${ISCCFGLIBS} ${DNSLIBS} \
-       ${ISCLIBS} ${LIBS}
+       export BASEOBJS="named-checkzone.@O@ check-tool.@O@"; \
+       export LIBS0="${ISCCFGLIBS} ${DNSLIBS}"; \
+       ${FINALBUILDCMD}
 
 doc man:: ${MANOBJS}
 
index be9fc385b89a447fcddd5227a318b56453ae606c..5bfdc6adfe2b04524033b5dbb272b3aa2e4c4382 100644 (file)
@@ -12,7 +12,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.5 2009/09/01 00:22:24 jinmei Exp $
+# $Id: Makefile.in,v 1.6 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -43,7 +43,10 @@ BIND9DEPLIBS =       ../../lib/bind9/libbind9.@A@
 RNDCLIBS =     ${ISCCFGLIBS} ${ISCCCLIBS} ${BIND9LIBS} ${DNSLIBS} ${ISCLIBS} @LIBS@
 RNDCDEPLIBS =  ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${BIND9DEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS}
 
-CONFLIBS =     ${DNSLIBS} ${ISCLIBS} @LIBS@
+LIBS =         ${DNSLIBS} ${ISCLIBS} @LIBS@
+
+NOSYMLIBS =    ${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@
+
 CONFDEPLIBS =  ${DNSDEPLIBS} ${ISCDEPLIBS}
 
 SRCS=          rndc-confgen.c ddns-confgen.c
@@ -71,12 +74,12 @@ ddns-confgen.@O@: ddns-confgen.c
        ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${srcdir}/ddns-confgen.c
 
 rndc-confgen@EXEEXT@: rndc-confgen.@O@ util.@O@ keygen.@O@ ${UOBJS} ${CONFDEPLIBS} 
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rndc-confgen.@O@ util.@O@ keygen.@O@ \
-               ${UOBJS} ${CONFLIBS}
+       export BASEOBJS="rndc-confgen.@O@ util.@O@ keygen.@O@ ${UOBJS}"; \
+       ${FINALBUILDCMD}
 
 ddns-confgen@EXEEXT@: ddns-confgen.@O@ util.@O@ keygen.@O@ ${UOBJS} ${CONFDEPLIBS} 
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ddns-confgen.@O@ util.@O@ keygen.@O@ \
-               ${UOBJS} ${CONFLIBS}
+       export BASEOBJS="ddns-confgen.@O@ util.@O@ keygen.@O@ ${UOBJS}"; \
+       ${FINALBUILDCMD}
 
 doc man:: ${MANOBJS}
 
index ad8f2e8d9856f1f6f6651ea3d3880834782a50d5..ee57ce2dcb4ed5639b94f8fd3ad8f61e07e00034 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.42 2009/09/01 00:22:24 jinmei Exp $
+# $Id: Makefile.in,v 1.43 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -33,6 +33,7 @@ ISCCFGLIBS =  ../../lib/isccfg/libisccfg.@A@
 DNSLIBS =      ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
 BIND9LIBS =    ../../lib/bind9/libbind9.@A@
 ISCLIBS =      ../../lib/isc/libisc.@A@
+ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@
 LWRESLIBS =    ../../lib/lwres/liblwres.@A@
 
 ISCCFGDEPLIBS =        ../../lib/isccfg/libisccfg.@A@
@@ -47,6 +48,9 @@ DEPLIBS =     ${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} ${ISCCFGDEPLIBS} \
 LIBS =         ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCLIBS} \
                ${ISCCFGLIBS} @IDNLIBS@ @LIBS@
 
+NOSYMLIBS =    ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCNOSYMLIBS} \
+               ${ISCCFGLIBS} @IDNLIBS@ @LIBS@
+
 SUBDIRS =
 
 TARGETS =      dig@EXEEXT@ host@EXEEXT@ nslookup@EXEEXT@
@@ -66,16 +70,16 @@ MANOBJS =   ${MANPAGES} ${HTMLPAGES}
 @BIND9_MAKE_RULES@
 
 dig@EXEEXT@: dig.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       dig.@O@ dighost.@O@ ${UOBJS} ${LIBS}
+       export BASEOBJS="dig.@O@ dighost.@O@ ${UOBJS}"; \
+       ${FINALBUILDCMD}
 
 host@EXEEXT@: host.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       host.@O@ dighost.@O@ ${UOBJS} ${LIBS}
+       export BASEOBJS="host.@O@ dighost.@O@ ${UOBJS}"; \
+       ${FINALBUILDCMD}
 
 nslookup@EXEEXT@: nslookup.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       nslookup.@O@ dighost.@O@ ${UOBJS} ${LIBS}
+       export BASEOBJS="nslookup.@O@ dighost.@O@ ${UOBJS}"; \
+       ${FINALBUILDCMD}
 
 doc man:: ${MANOBJS}
 
index ef4bedbcf5a2248be128724570b15710d8baca57..2af3838fa898a96f31374ed81eabe4b5fce864f0 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.39 2009/09/01 00:22:24 jinmei Exp $
+# $Id: Makefile.in,v 1.40 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -30,6 +30,7 @@ CWARNINGS =
 
 DNSLIBS =      ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
 ISCLIBS =      ../../lib/isc/libisc.@A@
+ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@
 
 DNSDEPLIBS =   ../../lib/dns/libdns.@A@
 ISCDEPLIBS =   ../../lib/isc/libisc.@A@
@@ -38,6 +39,8 @@ DEPLIBS =     ${DNSDEPLIBS} ${ISCDEPLIBS}
 
 LIBS =         ${DNSLIBS} ${ISCLIBS} @LIBS@
 
+NOSYMLIBS =    ${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@
+
 # Alphabetically
 TARGETS =      dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \
                dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \
@@ -60,24 +63,24 @@ MANOBJS =   ${MANPAGES} ${HTMLPAGES}
 @BIND9_MAKE_RULES@
 
 dnssec-dsfromkey@EXEEXT@: dnssec-dsfromkey.@O@ ${OBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       dnssec-dsfromkey.@O@ ${OBJS} ${LIBS}
+       export BASEOBJS="dnssec-dsfromkey.@O@ ${OBJS}"; \
+       ${FINALBUILDCMD}
 
 dnssec-keyfromlabel@EXEEXT@: dnssec-keyfromlabel.@O@ ${OBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       dnssec-keyfromlabel.@O@ ${OBJS} ${LIBS}
+       export BASEOBJS="dnssec-keyfromlabel.@O@ ${OBJS}"; \
+       ${FINALBUILDCMD}
 
 dnssec-keygen@EXEEXT@: dnssec-keygen.@O@ ${OBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       dnssec-keygen.@O@ ${OBJS} ${LIBS}
+       export BASEOBJS="dnssec-keygen.@O@ ${OBJS}"; \
+       ${FINALBUILDCMD}
 
 dnssec-signzone.@O@: dnssec-signzone.c
        ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \
                -c ${srcdir}/dnssec-signzone.c
 
 dnssec-signzone@EXEEXT@: dnssec-signzone.@O@ ${OBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       dnssec-signzone.@O@ ${OBJS} ${LIBS}
+       export BASEOBJS="dnssec-signzone.@O@ ${OBJS}"; \
+       ${FINALBUILDCMD}
 
 dnssec-revoke@EXEEXT@: dnssec-revoke.@O@ ${OBJS} ${DEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
index cd2a0247ae618e262cd04f65a6f3cab2e65bac47..a5cbc1e4d6e91b55b40750007e6193426fa4cb55 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.105 2009/09/01 00:22:25 jinmei Exp $
+# $Id: Makefile.in,v 1.106 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -53,6 +53,7 @@ DNSLIBS =     ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
 ISCCFGLIBS =   ../../lib/isccfg/libisccfg.@A@
 ISCCCLIBS =    ../../lib/isccc/libisccc.@A@
 ISCLIBS =      ../../lib/isc/libisc.@A@
+ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@
 LWRESLIBS =    ../../lib/lwres/liblwres.@A@
 BIND9LIBS =    ../../lib/bind9/libbind9.@A@
 
@@ -70,6 +71,10 @@ LIBS =               ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
                ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \
                ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
 
+NOSYMLIBS =    ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
+               ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCNOSYMLIBS} \
+               ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
+
 SUBDIRS =      unix
 
 TARGETS =      named@EXEEXT@ lwresd@EXEEXT@
@@ -86,10 +91,12 @@ OBJS =              builtin.@O@ client.@O@ config.@O@ control.@O@ \
 
 UOBJS =                unix/os.@O@
 
+SYMOBJS =      symtbl.@O@
+
 SRCS =         builtin.c client.c config.c control.c \
                controlconf.c interfacemgr.c \
                listenlist.c log.c logconf.c main.c notify.c \
-               query.c server.c sortlist.c statschannel.c \
+               query.c server.c sortlist.c statschannel.c symtbl.c symtbl-empty.c \
                tkeyconf.c tsigconf.c update.c xfrout.c \
                zoneconf.c \
                lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \
@@ -122,8 +129,9 @@ config.@O@: config.c bind.keys.h
                -c ${srcdir}/config.c
 
 named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
-       ${OBJS} ${UOBJS} ${LIBS}
+       export MAKE_SYMTABLE="yes"; \
+       export BASEOBJS="${OBJS} ${UOBJS}"; \
+       ${FINALBUILDCMD}
 
 lwresd@EXEEXT@: named@EXEEXT@
        rm -f lwresd@EXEEXT@
index a05daf15df356be8a4916ca982404349932866cb..b0f051413334e541eda28a3a0cc2b2f943666e6c 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: main.c,v 1.172 2009/05/07 09:33:52 fdupont Exp $ */
+/* $Id: main.c,v 1.173 2009/09/01 18:40:25 jinmei Exp $ */
 
 /*! \file */
 
@@ -26,6 +26,7 @@
 #include <string.h>
 
 #include <isc/app.h>
+#include <isc/backtrace.h>
 #include <isc/commandline.h>
 #include <isc/dir.h>
 #include <isc/entropy.h>
 #include <dlz/dlz_drivers.h>
 #endif
 
+/*
+ * The maximum number of stack frames to dump on assertion failure.
+ */
+#ifndef BACKTRACE_MAXFRAME
+#define BACKTRACE_MAXFRAME 128
+#endif
+
 static isc_boolean_t   want_stats = ISC_FALSE;
 static char            program_name[ISC_DIR_NAMEMAX] = "named";
 static char            absolute_conffile[ISC_DIR_PATHMAX];
@@ -134,6 +142,12 @@ static void
 assertion_failed(const char *file, int line, isc_assertiontype_t type,
                 const char *cond)
 {
+       void *tracebuf[BACKTRACE_MAXFRAME];
+       int i, nframes;
+       isc_result_t result;
+       const char *logsuffix = "";
+       const char *fname;
+
        /*
         * Handle assertion failures.
         */
@@ -145,10 +159,40 @@ assertion_failed(const char *file, int line, isc_assertiontype_t type,
                 */
                isc_assertion_setcallback(NULL);
 
+               result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
+                                               &nframes);
+               if (result == ISC_R_SUCCESS && nframes > 0)
+                       logsuffix = ", back trace";
                isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                              NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
-                             "%s:%d: %s(%s) failed", file, line,
-                             isc_assertion_typetotext(type), cond);
+                             "%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++) {
+                               unsigned long offset;
+
+                               fname = NULL;
+                               result = isc_backtrace_getsymbol(tracebuf[i],
+                                                                &fname,
+                                                                &offset);
+                               if (result == ISC_R_SUCCESS) {
+                                       isc_log_write(ns_g_lctx,
+                                                     NS_LOGCATEGORY_GENERAL,
+                                                     NS_LOGMODULE_MAIN,
+                                                     ISC_LOG_CRITICAL,
+                                                     "#%d %p in %s()+0x%lx", i,
+                                                     tracebuf[i], fname,
+                                                     offset);
+                               } else {
+                                       isc_log_write(ns_g_lctx,
+                                                     NS_LOGCATEGORY_GENERAL,
+                                                     NS_LOGMODULE_MAIN,
+                                                     ISC_LOG_CRITICAL,
+                                                     "#%d %p in ??", i,
+                                                     tracebuf[i]);
+                               }
+                       }
+               }
                isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                              NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
                              "exiting (due to assertion failure)");
@@ -584,6 +628,34 @@ destroy_managers(void) {
        isc_hash_destroy();
 }
 
+static void
+dump_symboltable() {
+       int i;
+       isc_result_t result;
+       const char *fname;
+       const void *addr;
+
+       if (isc__backtrace_nsymbols == 0)
+               return;
+
+       if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99)))
+               return;
+
+       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+                     ISC_LOG_DEBUG(99), "Symbol table:");
+
+       for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) {
+               addr = NULL;
+               fname = NULL;
+               result = isc_backtrace_getsymbolfromindex(i, &addr, &fname);
+               if (result == ISC_R_SUCCESS) {
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
+                                     "[%d] %p %s", i, addr, fname);
+               }
+       }
+}
+
 static void
 setup(void) {
        isc_result_t result;
@@ -691,6 +763,8 @@ setup(void) {
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
                      ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
 
+       dump_symboltable();
+
        /*
         * Get the initial resource limits.
         */
@@ -902,6 +976,9 @@ main(int argc, char *argv[]) {
        if (strcmp(program_name, "lwresd") == 0)
                ns_g_lwresdonly = ISC_TRUE;
 
+       if (result != ISC_R_SUCCESS)
+               ns_main_earlyfatal("failed to build internal symbol table");
+
        isc_assertion_setcallback(assertion_failed);
        isc_error_setfatal(library_fatal_error);
        isc_error_setunexpected(library_unexpected_error);
index 00d0fbd23eba79bae6753fe642fe6bde486e7ffd..b2ce180684be8a4d7a3a041f4821ca59e57c62ad 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.33 2009/09/01 00:22:25 jinmei Exp $
+# $Id: Makefile.in,v 1.34 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -33,6 +33,7 @@ LWRESLIBS =   ../../lib/lwres/liblwres.@A@
 DNSLIBS =      ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
 BIND9LIBS =    ../../lib/bind9/libbind9.@A@
 ISCLIBS =      ../../lib/isc/libisc.@A@
+ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@
 ISCCFGLIBS =   ../../lib/isccfg/libisccfg.@A@
 
 LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@
@@ -45,6 +46,8 @@ DEPLIBS =     ${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} ${ISCCFGDEPLIBS}
 
 LIBS =         ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} ${ISCLIBS} @LIBS@
 
+NOSYMLIBS =    ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCNOSYMLIBS} ${ISCCFGLIBS} @LIBS@
+
 SUBDIRS =
 
 TARGETS =      nsupdate@EXEEXT@
@@ -69,7 +72,8 @@ nsupdate.@O@: nsupdate.c
                -c ${srcdir}/nsupdate.c
 
 nsupdate@EXEEXT@: nsupdate.@O@ ${UOBJS} ${DEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsupdate.@O@ ${UOBJS} ${LIBS}
+       export BASEOBJS="nsupdate.@O@ ${UOBJS}"; \
+       ${FINALBUILDCMD}
 
 doc man:: ${MANOBJS}
 
index 6ec10ba7d33e0d97d8b86b109e1dd95c4f210bcb..3334e445b6ac3a554e59f4a0caae47d9e907e2db 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.47 2009/09/01 00:22:25 jinmei Exp $
+# $Id: Makefile.in,v 1.48 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -32,6 +32,7 @@ CWARNINGS =
 ISCCFGLIBS =   ../../lib/isccfg/libisccfg.@A@
 ISCCCLIBS =    ../../lib/isccc/libisccc.@A@
 ISCLIBS =      ../../lib/isc/libisc.@A@
+ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@
 DNSLIBS =      ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
 BIND9LIBS =    ../../lib/bind9/libbind9.@A@
 
@@ -41,10 +42,11 @@ ISCDEPLIBS =        ../../lib/isc/libisc.@A@
 DNSDEPLIBS =   ../../lib/dns/libdns.@A@
 BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@
 
-RNDCLIBS =     ${ISCCFGLIBS} ${ISCCCLIBS} ${BIND9LIBS} ${DNSLIBS} ${ISCLIBS} @LIBS@
+LIBS =         ${ISCLIBS} @LIBS@
+NOSYMLIBS =    ${ISCNOSYMLIBS} @LIBS@
+
 RNDCDEPLIBS =  ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${BIND9DEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS}
 
-CONFLIBS =     ${DNSLIBS} ${ISCLIBS} @LIBS@
 CONFDEPLIBS =  ${DNSDEPLIBS} ${ISCDEPLIBS}
 
 SRCS=          rndc.c
@@ -67,8 +69,9 @@ rndc.@O@: rndc.c
                -c ${srcdir}/rndc.c
 
 rndc@EXEEXT@: rndc.@O@ util.@O@ ${RNDCDEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rndc.@O@ util.@O@ \
-               ${RNDCLIBS}
+       export BASEOBJS="rndc.@O@ util.@O@"; \
+       export LIBS0="${ISCCFGLIBS} ${ISCCCLIBS} ${BIND9LIBS} ${DNSLIBS}"; \
+       ${FINALBUILDCMD}
 
 doc man:: ${MANOBJS}
 
index 20f1206046b019c44e0c99546fc6c4d89c3ffa96..4dbdb78d6fa1d8cefe1562178ed189f8b6a06d61 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.135 2009/09/01 00:22:25 jinmei Exp $
+# $Id: Makefile.in,v 1.136 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -29,11 +29,13 @@ CWARNINGS =
 
 DNSLIBS =      ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
 ISCLIBS =      ../../lib/isc/libisc.@A@ @DNS_CRYPTO_LIBS@
+ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @DNS_CRYPTO_LIBS@
 ISCCFGLIBS =   ../../lib/isccfg/libisccfg.@A@
 LWRESLIBS =    ../../lib/lwres/liblwres.@A@
 
 DNSDEPLIBS =   ../../lib/dns/libdns.@A@
 ISCDEPLIBS =   ../../lib/isc/libisc.@A@
+ISCDEPNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@
 ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@
 LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@
 
@@ -52,6 +54,8 @@ TARGETS =     cfg_test@EXEEXT@
 # Alphabetically
 XTARGETS =     adb_test@EXEEXT@ \
                byaddr_test@EXEEXT@ \
+               backtrace_test@EXEEXT@ \
+               backtrace_test_nosymtbl@EXEEXT@ \
                byname_test@EXEEXT@ \
                compress_test@EXEEXT@ \
                db_test@EXEEXT@ \
@@ -91,6 +95,7 @@ SRCS =                cfg_test.c ${XSRCS}
 
 XSRCS =                adb_test.c \
                byaddr_test.c \
+               backtrace_test.c \
                byname_test.c \
                compress_test.c \
                db_test.c \
@@ -128,12 +133,41 @@ XSRCS =           adb_test.c \
 
 @BIND9_MAKE_RULES@
 
+# disable optimization for backtrace test to get the expected result   
+BTTEST_CFLAGS =        ${EXT_CFLAGS} ${ALL_CPPFLAGS} -g ${ALWAYS_WARNINGS} \
+       ${STD_CWARNINGS} ${CWARNINGS}
+
 all_tests: ${XTARGETS}
 
 adb_test@EXEEXT@: adb_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ adb_test.@O@ \
                ${DNSLIBS} ${ISCLIBS} ${LIBS}
 
+backtrace_test_nosymtbl@EXEEXT@: backtrace_test.c ${ISCDEPLIBS}
+       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} -o $@ \
+       backtrace_test.c ${ISCLIBS} ${LIBS}
+
+backtrace_test@EXEEXT@: backtrace_test_nosymtbl@EXEEXT@
+       #first step: create a first symbol table
+       rm -f symtbl.c
+       if test X${MKSYMTBL_PROGRAM} != X; then \
+       ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl $<; else \
+       cp ${top_srcdir}/lib/isc/backtrace-emptytbl.c symtbl.c; fi
+       #second step: build a binary with the first symbol table
+       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} \
+       -o $@0 backtrace_test.c symtbl.c \
+       ${ISCNOSYMLIBS} ${LIBS}
+       rm -f symtbl.c
+       #third step: create a second symbol table
+       if test X${MKSYMTBL_PROGRAM} != X; then \
+       ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl $@0; else \
+       cp ${top_srcdir}/lib/isc/backtrace-emptytbl.c symtbl.c; fi
+       #fourth step: build the final binary
+       rm -f $@0
+       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} \
+       -o $@ backtrace_test.c symtbl.c ${ISCNOSYMLIBS} ${LIBS}
+       rm -f symtbl.c
+
 nsecify@EXEEXT@: nsecify.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsecify.@O@ \
                ${DNSLIBS} ${ISCLIBS} ${LIBS}
@@ -280,6 +314,7 @@ distclean::
 clean distclean::
        rm -f ${TARGETS} ${XTARGETS}
        rm -f t_journal
+       rm -f backtrace_test_symtbl.c
 
 check: test
 
diff --git a/bin/tests/backtrace_test.c b/bin/tests/backtrace_test.c
new file mode 100644 (file)
index 0000000..f2f27ea
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: backtrace_test.c,v 1.2 2009/09/01 18:40:25 jinmei Exp $ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/backtrace.h>
+#include <isc/result.h>
+
+const char *expected_symbols[] = {
+       "func3",
+       "func2",
+       "func1",
+       "main"
+};
+
+static int
+func3() {
+       void *tracebuf[16];
+       int i, nframes;
+       int error = 0;
+       const char *fname;
+       isc_result_t result;
+       unsigned long offset;
+
+       result = isc_backtrace_gettrace(tracebuf, 16, &nframes);
+       if (result != ISC_R_SUCCESS) {
+               printf("isc_backtrace_gettrace failed: %s\n",
+                      isc_result_totext(result));
+               return (1);
+       }
+               
+       if (nframes < 4)
+               error++;
+       
+       for (i = 0; i < 4 && i < nframes; i++) {
+               fname = NULL;
+               result = isc_backtrace_getsymbol(tracebuf[i], &fname, &offset);
+               if (result != ISC_R_SUCCESS) {
+                       error++;
+                       continue;
+               }
+               if (strcmp(fname, expected_symbols[i]) != 0)
+                       error++;
+       }
+
+       if (error) {
+               printf("Unexpected result:\n");
+               printf("  # of frames: %d (expected: at least 4)\n", nframes);
+               printf("  symbols:\n");
+               for (i = 0; i < nframes; i++) {
+                       fname = NULL;
+                       result = isc_backtrace_getsymbol(tracebuf[i], &fname,
+                                                        &offset);
+                       if (result == ISC_R_SUCCESS)
+                               printf("  [%d] %s\n", i, fname);
+                       else {
+                               printf("  [%d] getsymbol failed: %s\n", i,
+                                      isc_result_totext(result));
+                       }
+               }
+       }
+
+       return (error);
+}
+
+static int
+func2() {
+       return (func3());
+}
+
+static int
+func1() {
+       return (func2());
+}
+
+int
+main() {
+       return (func1());
+}
index 90a7b9eac94a33b1d57b4fed91102422261146d2..0ed7b66e45e14c9af3e4fb63a3f7ffc267c7b277 100644 (file)
@@ -12,7 +12,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.8 2009/09/01 00:22:26 jinmei Exp $
+# $Id: Makefile.in,v 1.9 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -28,6 +28,7 @@ CWARNINGS =
 
 DNSLIBS =      ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
 ISCLIBS =      ../../lib/isc/libisc.@A@ @DNS_CRYPTO_LIBS@
+ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@
 ISCCFGLIBS =   ../../lib/isccfg/libisccfg.@A@
 LWRESLIBS =    ../../lib/lwres/liblwres.@A@
 
@@ -36,7 +37,8 @@ ISCDEPLIBS =  ../../lib/isc/libisc.@A@
 ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@
 LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@
 
-LIBS =         @LIBS@
+LIBS =         ${ISCLIBS} @LIBS@
+NOSYMLIBS =    ${ISCNOSYMLIBS} @LIBS@
 
 SUBDIRS = 
 
@@ -53,13 +55,16 @@ MANOBJS =   ${MANPAGES} ${HTMLPAGES}
 arpaname@EXEEXT@: arpaname.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ arpaname.@O@ \
                ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
 journalprint@EXEEXT@: journalprint.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ journalprint.@O@ \
-               ${DNSLIBS} ${ISCLIBS} ${LIBS}
+       export BASEOBJS="journalprint.@O@"; \
+       export LIBS0="${DNSLIBS}"; \
+       ${FINALBUILDCMD}
 
 nsec3hash@EXEEXT@: nsec3hash.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
-       ${LIBTOOL_MODE_LINK} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsec3hash.@O@ \
-       ${DNSLIBS} ${ISCLIBS} ${LIBS}
+       export BASEOBJS="nsec3hash.@O@"; \
+       export LIBS0="${DNSLIBS}"; \
+       ${FINALBUILDCMD}
 
 genrandom@EXEEXT@: genrandom.@O@
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ genrandom.@O@ @GENRANDOMLIB@ ${LIBS}
index 009515ef7f33c0232d04d8ba5de766900e961e53..cc78c6d3186911d6a6b8bf739e2312c212e9d6c3 100644 (file)
@@ -16,7 +16,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: config.h.in,v 1.119 2009/09/01 17:54:16 jinmei Exp $ */
+/* $Id: config.h.in,v 1.120 2009/09/01 18:40:25 jinmei Exp $ */
 
 /*! \file */
 
@@ -334,6 +334,9 @@ int sigwait(const unsigned int *set, int *sig);
    non-blocking. */
 #undef USE_FIONBIO_IOCTL
 
+/** define if the system have backtrace function. */
+#undef HAVE_LIBCTRACE
+
 /* define if idnkit support is to be included. */
 #undef WITH_IDN
 
index 11e79a334d9b8d874c998dfb3890cc0301af5045..f224951cc1b79425c4e0cf5e021aab79dd3ff2d0 100644 (file)
@@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl
 esyscmd([sed "s/^/# /" COPYRIGHT])dnl
 AC_DIVERT_POP()dnl
 
-AC_REVISION($Revision: 1.475 $)
+AC_REVISION($Revision: 1.476 $)
 
 AC_INIT(lib/dns/name.c)
 AC_PREREQ(2.59)
@@ -111,6 +111,8 @@ AC_SUBST(ETAGS)
 
 #
 # Perl is optional; it is used only by some of the system test scripts.
+# Note: the backtrace feature (see below) uses perl to build the symbol table,
+# but it still compiles without perl, in which case an empty table will be used.
 #
 AC_PATH_PROGS(PERL, perl5 perl)
 AC_SUBST(PERL)
@@ -1306,6 +1308,53 @@ case $use_libtool in
                ;;
 esac
 
+#
+# enable/disable dumping stack backtrace.  Also check if the system supports
+# glibc-compatible backtrace() function.
+#
+AC_ARG_ENABLE(backtrace,
+[  --enable-backtrace      log stack backtrace on abort [[default=yes]]],
+             want_backtrace="$enableval",  want_backtrace="yes")
+case $want_backtrace in
+yes)
+       ISC_PLATFORM_USEBACKTRACE="#define ISC_PLATFORM_USEBACKTRACE 1"
+       AC_TRY_LINK([#include <execinfo.h>],
+       [return (backtrace((void **)0, 0));],
+       [AC_DEFINE([HAVE_LIBCTRACE], [], [if system have backtrace function])],)
+       ;;
+*)
+       ISC_PLATFORM_USEBACKTRACE="#undef ISC_PLATFORM_USEBACKTRACE"
+       ;;
+esac
+AC_SUBST(ISC_PLATFORM_USEBACKTRACE)
+
+AC_ARG_ENABLE(symtable,
+[  --enable-symtable       use internal symbol table for backtrace
+                          [[all|minimal(default)|none]]],
+               want_symtable="$enableval",  want_symtable="minimal")
+case $want_symtable in
+yes|all|minimal)
+       
+       if test "$PERL" == ""
+       then
+               AC_MSG_ERROR([Internal symbol table requires perl but no perl is found.
+Install perl or explicitly disable the feature by --disable-symtable.])
+       fi
+       if test "$use_libtool" = "yes"; then
+               AC_MSG_WARN([Internal symbol table does not work with libtool.  Disabling symtbol table.])
+       else
+               MKSYMTBL_PROGRAM="$PERL"
+               if test $want_symtable = all; then
+                       ALWAYS_MAKE_SYMTABLE="yes"
+               fi
+       fi
+       ;;
+*)
+       ;;
+esac
+AC_SUBST(MKSYMTBL_PROGRAM)
+AC_SUBST(ALWAYS_MAKE_SYMTABLE)
+
 #
 # File name extension for static archive files, for those few places
 # where they are treated differently from dynamic ones.
index ced0e64729ef7b3c45d5db6cc89fc52dbc0e1828..bbe3cd01e816a1a00904908c392c6159289b474f 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.101 2009/09/01 00:22:28 jinmei Exp $
+# $Id: Makefile.in,v 1.102 2009/09/01 18:40:25 jinmei Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -50,8 +50,9 @@ WIN32OBJS =   win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \
 
 # Alphabetically
 OBJS =         @ISC_EXTRA_OBJS@ \
-               assertions.@O@ base32.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \
-               bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \
+               assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \
+               bitstring.@O@ buffer.@O@ bufferlist.@O@ commandline.@O@ \
+               error.@O@ event.@O@ \
                hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \
                httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \
                lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
@@ -62,6 +63,7 @@ OBJS =                @ISC_EXTRA_OBJS@ \
                serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ \
                string.@O@ strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ \
                timer.@O@ version.@O@ ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS}
+SYMTBLOBJS =   backtrace-emptytbl.@O@
 
 # Alphabetically
 SRCS =         @ISC_EXTRA_SRCS@ \
@@ -75,7 +77,7 @@ SRCS =                @ISC_EXTRA_SRCS@ \
                parseint.c portset.c quota.c radix.c random.c \
                ratelimiter.c refcount.c region.c result.c rwlock.c \
                serial.c sha1.c sha2.c sockaddr.c stats.c string.c strtoul.c \
-               symtab.c task.c taskpool.c timer.c version.c
+               symtab.c symtbl-empty.c task.c taskpool.c timer.c version.c
 
 LIBS =         @LIBS@
 
@@ -92,17 +94,27 @@ version.@O@: version.c
                -DLIBAGE=${LIBAGE} \
                -c ${srcdir}/version.c
 
-libisc.@SA@: ${OBJS}
+libisc.@SA@: ${OBJS} ${SYMTBLOBJS}
+       ${AR} ${ARFLAGS} $@ ${OBJS} ${SYMTBLOBJS}
+       ${RANLIB} $@
+
+libisc-nosymtbl.@SA@: ${OBJS}
        ${AR} ${ARFLAGS} $@ ${OBJS}
        ${RANLIB} $@
 
-libisc.la: ${OBJS}
+libisc.la: ${OBJS} ${SYMTBLOBJS}
        ${LIBTOOL_MODE_LINK} \
                ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la -rpath ${libdir} \
                -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+               ${OBJS} ${SYMTBLOBJS} ${LIBS}
+
+libisc-nosymtbl.la: ${OBJS}
+       ${LIBTOOL_MODE_LINK} \
+               ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-nosymtbl.la -rpath ${libdir} \
+               -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
                ${OBJS} ${LIBS}
 
-timestamp: libisc.@A@
+timestamp: libisc.@A@ libisc-nosymtbl.@A@
        touch timestamp
 
 installdirs:
@@ -115,4 +127,5 @@ install:: @ISC_ARCH_DIR@/include/isc/atomic.h
        ${INSTALL_DATA} @ISC_ARCH_DIR@/include/isc/atomic.h ${DESTDIR}${includedir}/isc
 
 clean distclean::
-       rm -f libisc.@A@ libisc.la timestamp
+       rm -f libisc.@A@ libisc-nosymtbl.@A@ libisc.la \
+       libisc-nosymtbl.la timestamp
index 4c9251bdcf25199dd622049ae35821775caf842d..0d5cc5c2118194ed0bd99eb69d7dc7e966c1b2cf 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: assertions.c,v 1.23 2008/10/15 23:47:31 tbox Exp $ */
+/* $Id: assertions.c,v 1.24 2009/09/01 18:40:25 jinmei Exp $ */
 
 /*! \file */
 
 #include <stdlib.h>
 
 #include <isc/assertions.h>
+#include <isc/backtrace.h>
 #include <isc/msgs.h>
+#include <isc/result.h>
+
+/*
+ * The maximum number of stack frames to dump on assertion failure.
+ */
+#ifndef BACKTRACE_MAXFRAME
+#define BACKTRACE_MAXFRAME 128
+#endif
 
 /*%
  * Forward.
@@ -87,10 +96,36 @@ static void
 default_callback(const char *file, int line, isc_assertiontype_t type,
                 const char *cond)
 {
-       fprintf(stderr, "%s:%d: %s(%s) %s.\n",
+       void *tracebuf[BACKTRACE_MAXFRAME];
+       int i, nframes;
+       const char *logsuffix = ".";
+       const char *fname;
+       isc_result_t result;
+
+       result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME, &nframes);
+               if (result == ISC_R_SUCCESS && nframes > 0)
+                       logsuffix = ", back trace";
+
+       fprintf(stderr, "%s:%d: %s(%s) %s%s\n",
                file, line, isc_assertion_typetotext(type), cond,
                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
-                              ISC_MSG_FAILED, "failed"));
+                              ISC_MSG_FAILED, "failed"), logsuffix);
+       if (result == ISC_R_SUCCESS) {
+               for (i = 0; i < nframes; i++) {
+                       unsigned long offset;
+
+                       fname = NULL;
+                       result = isc_backtrace_getsymbol(tracebuf[i], &fname,
+                                                        &offset);
+                       if (result == ISC_R_SUCCESS) {
+                               fprintf(stderr, "#%d %p in %s()+0x%lx\n", i,
+                                       tracebuf[i], fname, offset);
+                       } else {
+                               fprintf(stderr, "#%d %p in ??\n", i,
+                                       tracebuf[i]);
+                       }
+               }
+       }
        fflush(stderr);
        abort();
        /* NOTREACHED */
diff --git a/lib/isc/backtrace-emptytbl.c b/lib/isc/backtrace-emptytbl.c
new file mode 100644 (file)
index 0000000..a5e3187
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: backtrace-emptytbl.c,v 1.2 2009/09/01 18:40:25 jinmei Exp $ */
+
+/*! \file */
+
+/*
+ * This file defines an empty (default) symbol table used in backtrace.c
+ * If the application wants to have a complete symbol table, it should redefine
+ * isc__backtrace_symtable with the complete table in some way, and link the
+ * version of the library not including this definition
+ * (e.g. libisc-nosymbol.a).
+ */
+
+#include <isc/backtrace.h>
+
+const int isc__backtrace_nsymbols = 0;
+const isc_backtrace_symmap_t isc__backtrace_symtable[] = { { NULL, "" } };
diff --git a/lib/isc/backtrace.c b/lib/isc/backtrace.c
new file mode 100644 (file)
index 0000000..26355ad
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: backtrace.c,v 1.2 2009/09/01 18:40:25 jinmei Exp $ */
+
+/*! \file */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_LIBCTRACE
+#include <execinfo.h>
+#endif
+
+#include <isc/backtrace.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#ifdef ISC_PLATFORM_USEBACKTRACE
+/*
+ * 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(__x86_64__) || defined(__i386__)
+#define BACKTRACE_X86STACK
+#else
+#define BACKTRACE_DISABLED
+#endif  /* HAVE_LIBCTRACE */
+#else  /* !ISC_PLATFORM_USEBACKTRACE */
+#define BACKTRACE_DISABLED
+#endif /* ISC_PLATFORM_USEBACKTRACE */
+
+#ifdef BACKTRACE_LIBC
+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.
+        */
+       if (addrs == NULL || nframes == NULL)
+               return (ISC_R_FAILURE);
+
+       /*
+        * backtrace(3) includes this function itself in the address array,
+        * which should be eliminated from the returned sequence.
+        */
+       n = backtrace(addrs, maxaddrs);
+       if (n < 2)
+               return (ISC_R_NOTFOUND);
+       n--;
+       memmove(addrs, &addrs[1], sizeof(void *) * 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_X86STACK)
+#ifdef __x86_64__
+static unsigned long
+getrbp() {
+       __asm("movq %rbp, %rax\n");
+}
+#endif
+
+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
+       /*
+        * 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
+
+       while (sp != NULL && i < maxaddrs) {
+               addrs[i++] = *(sp + 1);
+               sp = getnextframeptr(sp);
+       }
+
+       *nframes = i;
+
+       return (ISC_R_SUCCESS);
+}
+#elif defined(BACKTRACE_DISABLED)
+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(maxaddrs);
+
+       return (ISC_R_NOTIMPLEMENTED);
+}
+#endif
+
+isc_result_t
+isc_backtrace_getsymbolfromindex(int index, const void **addrp,
+                                const char **symbolp)
+{
+       REQUIRE(addrp != NULL && *addrp == NULL);
+       REQUIRE(symbolp != NULL && *symbolp == NULL);
+
+       if (index < 0 || index >= isc__backtrace_nsymbols)
+               return (ISC_R_RANGE);
+
+       *addrp = isc__backtrace_symtable[index].addr;
+       *symbolp = isc__backtrace_symtable[index].symbol;
+       return (ISC_R_SUCCESS);
+}
+
+static int
+symtbl_compare(const void *addr, const void *entryarg) {
+       const isc_backtrace_symmap_t *entry = entryarg;
+       const isc_backtrace_symmap_t *end =
+               &isc__backtrace_symtable[isc__backtrace_nsymbols - 1];
+
+       if (isc__backtrace_nsymbols == 1 || entry == end) {
+               if (addr >= entry->addr) {
+                       /*
+                        * If addr is equal to or larger than that of the last
+                        * entry of the table, we cannot be sure if this is
+                        * within a valid range so we consider it valid.
+                        */
+                       return (0);
+               }
+               return (-1);
+       }
+
+       /* entry + 1 is a valid entry from now on. */
+       if (addr < entry->addr)
+               return (-1);
+       else if (addr >= (entry + 1)->addr)
+               return (1);
+       return (0);
+}
+
+isc_result_t
+isc_backtrace_getsymbol(const void *addr, const char **symbolp,
+                       unsigned long *offsetp)
+{
+       isc_result_t result = ISC_R_SUCCESS;
+       isc_backtrace_symmap_t *found;
+
+       /*
+        * Validate the arguments: intentionally avoid using REQUIRE().
+        * See notes in backtrace.h.
+        */
+       if (symbolp == NULL || *symbolp != NULL || offsetp == NULL)
+               return (ISC_R_FAILURE);
+
+       if (isc__backtrace_nsymbols < 1)
+               return (ISC_R_NOTFOUND);
+
+       /*
+        * Search the table for the entry that meets:
+        * entry.addr <= addr < next_entry.addr.
+        */
+       found = bsearch(addr, isc__backtrace_symtable, isc__backtrace_nsymbols,
+                       sizeof(isc__backtrace_symtable[0]), symtbl_compare);
+       if (found == NULL)
+               result = ISC_R_NOTFOUND;
+       else {
+               *symbolp = found->symbol;
+               *offsetp = (const char *)addr - (char *)found->addr;
+       }
+
+       return (result);
+}
diff --git a/lib/isc/include/isc/backtrace.h b/lib/isc/include/isc/backtrace.h
new file mode 100644 (file)
index 0000000..c0e98c0
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: backtrace.h,v 1.2 2009/09/01 18:40:25 jinmei Exp $ */
+
+/*! \file isc/backtrace.h
+ * \brief provide a back trace of the running process to help debug problems.
+ *
+ * This module tries to get a back trace of the process using some platform
+ * dependent way when available.  It also manages an internal symbol table
+ * that maps function addresses used in the process to their textual symbols.
+ * This module is expected to be used to help debug when some fatal error
+ * happens.
+ *
+ * IMPORTANT NOTE: since the (major) intended use case of this module is
+ * dumping a back trace on a fatal error, normally followed by self termination,
+ * functions defined in this module generally doesn't employ assertion checks
+ * (if it did, a program bug could cause infinite recursive calls to a
+ * backtrace function).  These functions still perform minimal checks and return
+ * ISC_R_FAILURE if they detect an error, but the caller should therefore be
+ * very careful about the use of these functions, and generally discouraged to
+ * use them except in an exit path.  The exception is
+ * isc_backtrace_getsymbolfromindex(), which is expected to be used in a
+ * non-error-handling context and validates arguments with assertion checks.
+ */
+
+#ifndef ISC_BACKTRACE_H
+#define ISC_BACKTRACE_H 1
+
+/***
+ ***   Imports
+ ***/
+
+#include <isc/types.h>
+
+/***
+ *** Types
+ ***/
+struct isc_backtrace_symmap {
+       void            *addr;
+       const char      *symbol;
+};
+
+extern const int isc__backtrace_nsymbols;
+extern const isc_backtrace_symmap_t isc__backtrace_symtable[];
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+isc_result_t
+isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes);
+/*%<
+ * Get a back trace of the running process above this function itself.  On
+ * success, addrs[i] will store the address of the call point of the i-th
+ * stack frame (addrs[0] is the caller of this function).  *nframes will store
+ * the total number of frames.
+ *
+ * Requires (note that these are not ensured by assertion checks, see above):
+ *
+ *\li  'addrs' is a valid array containing at least 'maxaddrs' void * entries.
+ *
+ *\li  'nframes' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_FAILURE
+ *\li  #ISC_R_NOTFOUND
+ *\li  #ISC_R_NOTIMPLEMENTED
+ */
+
+isc_result_t
+isc_backtrace_getsymbolfromindex(int index, const void **addrp,
+                                const char **symbolp);
+/*%<
+ * Returns the content of the internal symbol table of the given index.
+ * On success, *addrsp and *symbolp point to the address and the symbol of
+ * the 'index'th entry of the table, respectively.  If 'index' is not in the
+ * range of the symbol table, ISC_R_RANGE will be returned.
+ *
+ * Requires
+ *
+ *\li  'addrp' must be non NULL && '*addrp' == NULL.
+ *
+ *\li  'symbolp' must be non NULL && '*symbolp' == NULL.
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_RANGE
+ */
+
+isc_result_t
+isc_backtrace_getsymbol(const void *addr, const char **symbolp,
+                       unsigned long *offsetp);
+/*%<
+ * Searches the internal symbol table for the symbol that most matches the
+ * given 'addr'.  On success, '*symbolp' will point to the name of function
+ * to which the address 'addr' belong, and '*offsetp' will store the offset
+ * from the function's entry address to 'addr'.
+ *
+ * Requires (note that these are not ensured by assertion checks, see above):
+ *
+ *\li  'symbolp' must be non NULL && '*symbolp' == NULL.
+ *
+ *\li  'offsetp' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_FAILURE
+ *\li  #ISC_R_NOTFOUND
+ */
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BACKTRACE_H */
index fd5461e4b1d515ae7f4100563bdabf4b66b1ce8d..ef49d3298d0d10212c7f60c3fe541c3a53652c88 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: platform.h.in,v 1.51 2009/02/06 23:47:42 tbox Exp $ */
+/* $Id: platform.h.in,v 1.52 2009/09/01 18:40:25 jinmei Exp $ */
 
 #ifndef ISC_PLATFORM_H
 #define ISC_PLATFORM_H 1
  */
 @ISC_PLATFORM_HAVEDEVPOLL@
 
+/*! \brief
+ * Define if we want to log backtrace
+ */
+@ISC_PLATFORM_USEBACKTRACE@
+
 /*
  *** Printing.
  ***/
index dd60d76a20999d423791120eddf1afbb67d8795a..03ada89a1c0c57c7d9da9c6e7ce7acf1905855fe 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: types.h,v 1.49 2009/09/01 00:22:28 jinmei Exp $ */
+/* $Id: types.h,v 1.50 2009/09/01 18:40:25 jinmei Exp $ */
 
 #ifndef ISC_TYPES_H
 #define ISC_TYPES_H 1
@@ -43,6 +43,7 @@
 /* Core Types.  Alphabetized by defined type. */
 
 typedef struct isc_appctx              isc_appctx_t;           /*%< Application context */
+typedef struct isc_backtrace_symmap    isc_backtrace_symmap_t; /*%< Symbol Table Entry */
 typedef struct isc_bitstring           isc_bitstring_t;        /*%< Bitstring */
 typedef struct isc_buffer              isc_buffer_t;           /*%< Buffer */
 typedef ISC_LIST(isc_buffer_t)         isc_bufferlist_t;       /*%< Buffer List */
index 4191ef038f4728aa9df716e6e53cc6a4ad965edc..2bd67556a7af55018822d945c7e03f2563144bfd 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: rules.in,v 1.67 2009/09/01 00:22:28 jinmei Exp $
+# $Id: rules.in,v 1.68 2009/09/01 18:40:25 jinmei Exp $
 
 ###
 ### Common Makefile rules for BIND 9.
@@ -136,12 +136,83 @@ PURIFY = @PURIFY@
 
 MKDEP = ${SHELL} ${top_builddir}/make/mkdep
 
+###
+### This is a template compound command to build an executable binary with
+### an internal symbol table.
+### This process is tricky.  We first link all objects including a tentative
+### empty symbol table, then get a tentative list of symbols from the resulting
+### binary ($@tmp0).  Next, we re-link all objects, but this time with the
+### symbol table just created ($tmp@1).  The set of symbols should be the same,
+### but the corresponding addresses would be changed due to the difference on
+### the size of symbol tables.  So we create the symbol table and re-create the
+### objects once again.  Finally, we check the symbol table embedded in the
+### final binaryis consistent with the binary itself; otherwise the process is
+### terminated.
+###
+### To minimize the overhead of creating symbol tables, the autoconf switch
+### --enable-symtable takes an argument so that the symbol table can be created
+### on a per application basis: unless the argument is set to "all", the symbol
+### table is created only when a shell (environment) variable "MAKE_SYMTABLE" is
+### set to a non-null value in the rule to build the executable binary.
+###
+### Each Makefile.in that uses this macro is expected to define "LIBS" and
+### "NOSYMLIBS"; the former includes libisc with an empty symbol table, and
+### the latter includes libisc without the definition of a symbol table.
+### The rule to make the executable binary will look like this
+### binary@EXEEXT@: ${OBJS}
+###     #export MAKE_SYMTABLE="yes"; \  <- enable if symtable is always needed
+###    export BASEOBJS="${OBJS}"; \
+###    ${FINALBUILDCMD}
+###
+### Normally, ${LIBS} includes all necessary libraries to build the binary;
+### there are some exceptions however, where the rule lists some of the
+### necessary libraries explicitly in addition to (or instead of) ${LIBS},
+### like this:
+### binary@EXEEXT@: ${OBJS}
+###     cc -o $@ ${OBJS} ${OTHERLIB1} ${OTHERLIB2} ${lIBS}
+### in order to modify such a rule to use this compound command, a separate
+### variable "LIBS0" should be deinfed for the explicitly listed libraries,
+### while making sure ${LIBS} still includes libisc.  So the above rule would
+### be modified as follows:
+### binary@EXEEXT@: ${OBJS}
+###    export BASEOBJS="${OBJS}"; \
+###    export LIBS0="${OTHERLIB1} ${OTHERLIB2}"; \
+###     ${FINALBUILDCMD}
+### See bin/check/Makefile.in for a complete example of the use of LIBS0.
+###
+FINALBUILDCMD = if [ X"${MKSYMTBL_PROGRAM}" = X -o X"$${MAKE_SYMTABLE:-${ALWAYS_MAKE_SYMTABLE}}" = X ] ; then \
+               ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \
+               -o $@ $${BASEOBJS} $${LIBS0} ${LIBS}; \
+       else \
+               rm -f $@tmp0; \
+               ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \
+               -o $@tmp0 $${BASEOBJS} $${LIBS0} ${LIBS} || exit 1; \
+               rm -f $@-symtbl.c $@-symtbl.@O@; \
+               ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \
+               -o $@-symtbl.c $@tmp0 || exit 1; \
+               $(MAKE) $@-symtbl.@O@ || exit 1; \
+               rm -f $@tmp1; \
+               ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \
+               -o $@tmp1 $${BASEOBJS} $@-symtbl.@O@ $${LIBS0} ${NOSYMLIBS} || exit 1; \
+               rm -f $@-symtbl.c $@-symtbl.@O@; \
+               ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \
+               -o $@-symtbl.c $@tmp1 || exit 1; \
+               $(MAKE) $@-symtbl.@O@ || exit 1; \
+               ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \
+               -o $@tmp2 $${BASEOBJS} $@-symtbl.@O@ $${LIBS0} ${NOSYMLIBS}; \
+               ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \
+               -o $@-symtbl2.c $@tmp2; \
+               diff $@-symtbl.c $@-symtbl2.c || exit 1;\
+               mv $@tmp2 $@; \
+               rm -f $@tmp0 $@tmp1 $@tmp2 $@-symtbl2.c; \
+       fi
+
 cleandir: distclean
 superclean: maintainer-clean
 
 clean distclean maintainer-clean::
-       rm -f *.@O@ *.o *.lo *.la core *.core .depend
-       rm -rf .libs
+       rm -f *.@O@ *.o *.lo *.la core *.core *-symtbl.c *tmp0 *tmp1 *tmp2
+       rm -rf .depend .libs
 
 distclean maintainer-clean::
        rm -f Makefile
@@ -218,6 +289,16 @@ LATEX =                    @LATEX@
 PDFLATEX =             @PDFLATEX@
 W3M =                  @W3M@
 
+###
+### Script language program used to create internal symbol tables
+###
+MKSYMTBL_PROGRAM =     @MKSYMTBL_PROGRAM@
+
+###
+### Switch to create internal symbol table selectively
+###
+ALWAYS_MAKE_SYMTABLE = @ALWAYS_MAKE_SYMTABLE@
+
 ###
 ### DocBook -> HTML
 ### DocBook -> man page