diff --git a/CHANGES b/CHANGES index ba70d925d3..c7bae302eb 100644 --- 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] diff --git a/bin/check/Makefile.in b/bin/check/Makefile.in index 488a143d83..39af25cbe8 100644 --- a/bin/check/Makefile.in +++ b/bin/check/Makefile.in @@ -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} diff --git a/bin/confgen/Makefile.in b/bin/confgen/Makefile.in index be9fc385b8..5bfdc6adfe 100644 --- a/bin/confgen/Makefile.in +++ b/bin/confgen/Makefile.in @@ -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} diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in index ad8f2e8d98..ee57ce2dcb 100644 --- a/bin/dig/Makefile.in +++ b/bin/dig/Makefile.in @@ -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} diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in index ef4bedbcf5..2af3838fa8 100644 --- a/bin/dnssec/Makefile.in +++ b/bin/dnssec/Makefile.in @@ -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 $@ \ diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in index cd2a0247ae..a5cbc1e4d6 100644 --- a/bin/named/Makefile.in +++ b/bin/named/Makefile.in @@ -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@ diff --git a/bin/named/main.c b/bin/named/main.c index a05daf15df..b0f0514133 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -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 #include +#include #include #include #include @@ -81,6 +82,13 @@ #include #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); diff --git a/bin/nsupdate/Makefile.in b/bin/nsupdate/Makefile.in index 00d0fbd23e..b2ce180684 100644 --- a/bin/nsupdate/Makefile.in +++ b/bin/nsupdate/Makefile.in @@ -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} diff --git a/bin/rndc/Makefile.in b/bin/rndc/Makefile.in index 6ec10ba7d3..3334e445b6 100644 --- a/bin/rndc/Makefile.in +++ b/bin/rndc/Makefile.in @@ -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} diff --git a/bin/tests/Makefile.in b/bin/tests/Makefile.in index 20f1206046..4dbdb78d6f 100644 --- a/bin/tests/Makefile.in +++ b/bin/tests/Makefile.in @@ -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 index 0000000000..f2f27eaa58 --- /dev/null +++ b/bin/tests/backtrace_test.c @@ -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 +#include + +#include +#include + +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()); +} diff --git a/bin/tools/Makefile.in b/bin/tools/Makefile.in index 90a7b9eac9..0ed7b66e45 100644 --- a/bin/tools/Makefile.in +++ b/bin/tools/Makefile.in @@ -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} diff --git a/config.h.in b/config.h.in index 009515ef7f..cc78c6d318 100644 --- a/config.h.in +++ b/config.h.in @@ -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 diff --git a/configure.in b/configure.in index 11e79a334d..f224951cc1 100644 --- a/configure.in +++ b/configure.in @@ -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 ], + [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. diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in index ced0e64729..bbe3cd01e8 100644 --- a/lib/isc/Makefile.in +++ b/lib/isc/Makefile.in @@ -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 diff --git a/lib/isc/assertions.c b/lib/isc/assertions.c index 4c9251bdcf..0d5cc5c211 100644 --- a/lib/isc/assertions.c +++ b/lib/isc/assertions.c @@ -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 */ @@ -25,7 +25,16 @@ #include #include +#include #include +#include + +/* + * 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 index 0000000000..a5e3187c36 --- /dev/null +++ b/lib/isc/backtrace-emptytbl.c @@ -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 + +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 index 0000000000..26355ad55b --- /dev/null +++ b/lib/isc/backtrace.c @@ -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 +#include +#ifdef HAVE_LIBCTRACE +#include +#endif + +#include +#include +#include + +#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 index 0000000000..c0e98c0b75 --- /dev/null +++ b/lib/isc/include/isc/backtrace.h @@ -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 + +/*** + *** 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 */ diff --git a/lib/isc/include/isc/platform.h.in b/lib/isc/include/isc/platform.h.in index fd5461e4b1..ef49d3298d 100644 --- a/lib/isc/include/isc/platform.h.in +++ b/lib/isc/include/isc/platform.h.in @@ -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 @@ -146,6 +146,11 @@ */ @ISC_PLATFORM_HAVEDEVPOLL@ +/*! \brief + * Define if we want to log backtrace + */ +@ISC_PLATFORM_USEBACKTRACE@ + /* *** Printing. ***/ diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index dd60d76a20..03ada89a1c 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -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 */ diff --git a/make/rules.in b/make/rules.in index 4191ef038f..2bd67556a7 100644 --- a/make/rules.in +++ b/make/rules.in @@ -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