const char *cond) {
void *tracebuf[BACKTRACE_MAXFRAME];
int nframes;
- isc_result_t result;
- const char *logsuffix = "";
/*
* Handle assertion failures.
*/
isc_assertion_setcallback(NULL);
- result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
- &nframes);
- if (result == ISC_R_SUCCESS && nframes > 0) {
- logsuffix = ", back trace";
- }
+ nframes = isc_backtrace(tracebuf, BACKTRACE_MAXFRAME);
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
"%s:%d: %s(%s) failed%s", file, line,
- isc_assertion_typetotext(type), cond, logsuffix);
- if (result == ISC_R_SUCCESS) {
-#if HAVE_BACKTRACE_SYMBOLS
- char **strs = backtrace_symbols(tracebuf, nframes);
- for (int i = 0; i < nframes; i++) {
- isc_log_write(named_g_lctx,
- NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_MAIN,
- ISC_LOG_CRITICAL, "%s", strs[i]);
- }
-#else /* HAVE_BACKTRACE_SYMBOLS */
- for (int i = 0; i < nframes; i++) {
- isc_log_write(
- named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
- "#%d %p in ??", i, tracebuf[i]);
+ isc_assertion_typetotext(type), cond,
+ (nframes > 0) ? ", back trace" : "");
+ if (nframes > 0) {
+ char **strs = isc_backtrace_symbols(tracebuf, nframes);
+ if (strs != NULL) {
+ for (int i = 0; i < nframes; i++) {
+ isc_log_write(named_g_lctx,
+ NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN,
+ ISC_LOG_CRITICAL, "%s",
+ strs[i]);
+ }
}
-#endif /* HAVE_BACKTRACE_SYMBOLS */
}
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
# Check if the system supports glibc-compatible backtrace() function.
#
AC_CHECK_HEADERS([execinfo.h],
- [AC_SEARCH_LIBS([backtrace], [execinfo],
- [AC_CHECK_FUNCS([backtrace backtrace_symbols])])])
-
-AM_CONDITIONAL([HAVE_BACKTRACE], [test "$ac_cv_func_backtrace" = "yes"])
+ [AC_SEARCH_LIBS([backtrace_symbols], [execinfo],
+ [AC_CHECK_FUNCS([backtrace_symbols])])])
#
# We do the IPv6 compilation checking after libtool so that we can put
#include <isc/assertions.h>
#include <isc/backtrace.h>
+#include <isc/platform.h>
#include <isc/print.h>
#include <isc/result.h>
+#include <isc/strerr.h>
+
+#if _WIN32
+#include <dbghelp.h>
+#endif
/*
* The maximum number of stack frames to dump on assertion failure.
default_callback(const char *file, int line, isc_assertiontype_t type,
const char *cond) {
void *tracebuf[BACKTRACE_MAXFRAME];
- int nframes;
- bool have_backtrace = false;
- isc_result_t result;
-
- result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME, &nframes);
- if (result == ISC_R_SUCCESS && nframes > 0) {
- have_backtrace = true;
- }
+ int nframes = isc_backtrace(tracebuf, BACKTRACE_MAXFRAME);
fprintf(stderr, "%s:%d: %s(%s) failed%s\n", file, line,
isc_assertion_typetotext(type), cond,
- (have_backtrace) ? ", back trace" : ".");
-
- if (result == ISC_R_SUCCESS) {
-#if HAVE_BACKTRACE_SYMBOLS
- char **strs = backtrace_symbols(tracebuf, nframes);
- for (int i = 0; i < nframes; i++) {
- fprintf(stderr, "%s\n", strs[i]);
- }
-#else /* HAVE_BACKTRACE_SYMBOLS */
- for (int i = 0; i < nframes; i++) {
- fprintf(stderr, "#%d %p in ??\n", i, tracebuf[i]);
- }
-#endif /* HAVE_BACKTRACE_SYMBOLS */
+ (nframes > 0) ? ", back trace" : ".");
+
+ if (nframes > 0) {
+ isc_backtrace_symbols_fd(tracebuf, nframes, fileno(stderr));
}
+
fflush(stderr);
}
#include <stdlib.h>
#include <string.h>
-#ifdef HAVE_BACKTRACE
+#ifdef HAVE_BACKTRACE_SYMBOLS
#include <execinfo.h>
-#endif /* HAVE_BACKTRACE */
+#endif /* HAVE_BACKTRACE_SYMBOLS */
#include <isc/backtrace.h>
+#include <isc/platform.h>
+#include <isc/print.h>
#include <isc/result.h>
#include <isc/util.h>
-#ifdef HAVE_BACKTRACE
-isc_result_t
-isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
+#if defined(_WIN32) && defined(_DEBUG)
+
+#include <dbghelp.h>
+
+int
+isc_backtrace(void **addrs, int maxaddrs, int *nframes) {
+ USHORT n = CaptureStackBackTrace(1, maxaddrs, addrs, NULL);
+
+ return (n);
+}
+
+#define TRACE_MAX_DEPTH 128
+#define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
+
+int
+vasprintf(char **strp, const char *format, va_list ap) {
+ int len, retval;
+ char *str = NULL;
+
+ len = _vscprintf(format, ap);
+ if (len == -1) {
+ return (-1);
+ }
+
+ str = malloc((size_t)len + 1);
+ if (str == NULL) {
+ return (-1);
+ }
+
+ retval = vsnprintf(str, len + 1, format, ap);
+ if (retval == -1) {
+ free(str);
+ return (-1);
+ }
+
+ *strp = str;
+ return (retval);
+}
+
+int
+asprintf(char **strp, const char *format, ...) {
+ va_list ap;
+ int retval;
+
+ va_start(ap, format);
+ retval = vasprintf(strp, format, ap);
+ va_end(ap);
+
+ return (retval);
+}
+
+static char **
+_backtrace_symbols(void *const *buffer, size_t size, bool add_cr) {
+ HANDLE process = GetCurrentProcess();
+ DWORD displacement;
+ uint8_t symbol_storage[sizeof(SYMBOL_INFO) +
+ (TRACE_MAX_FUNCTION_NAME_LENGTH - 1) *
+ sizeof(TCHAR)];
+ SYMBOL_INFO *symbol = (SYMBOL_INFO *)symbol_storage;
+ uint8_t line_storage[sizeof(IMAGEHLP_LINE64)];
+ IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)line_storage;
+ char **lines = NULL;
+ char **outbuf = NULL;
+ char *cur = NULL;
+ size_t outsize = 0;
+
+ if (buffer == NULL || size <= 0) {
+ return (NULL);
+ }
+
+ lines = malloc(size * sizeof(*lines));
+ if (lines == NULL) {
+ return (NULL);
+ }
+
+ /* Initialize symbol_info */
+ symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+
+ line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+
+ SymInitialize(process, NULL, TRUE);
+
+ /* adjust for the char ** array size */
+ outsize = size * sizeof(char *);
+ for (size_t i = 0; i < size; i++) {
+ DWORD64 address = (DWORD64)(buffer[i]);
+ BOOL r;
+ char *file = NULL;
+ unsigned int lineno;
+ int len;
+
+ if (SymFromAddr(process, address, NULL, symbol) &&
+ SymGetLineFromAddr64(process, address, &displacement, line))
+ {
+ file = line->FileName;
+ lineno = line->LineNumber;
+ } else {
+ file = "??";
+ lineno = 0;
+ }
+
+ len = asprintf(&lines[i], "#%-2d %p in %s at %s:%lu%s", i,
+ (void *)symbol->Address, symbol->Name,
+ line->FileName, line->LineNumber,
+ (add_cr) ? "\n" : "");
+ if (len == -1) {
+ goto cleanup;
+ }
+
+ outsize += strlen(lines[i]) + 1;
+ }
+
+ outbuf = malloc(outsize);
+ if (outbuf == NULL) {
+ goto cleanup;
+ }
+
+ cur = (char *)&outbuf[size];
+ for (size_t i = 0; i < size; i++) {
+ size_t remaining = outsize - (cur - (char *)outbuf);
+ size_t copied = strlcpy(cur, lines[i], remaining);
+ if (copied >= remaining) {
+ free(outbuf);
+ outbuf = NULL;
+ goto cleanup;
+ }
+
+ outbuf[i] = cur;
+ cur += copied + 1;
+ }
+
+cleanup:
+ for (size_t i = 0; i < size; i++) {
+ free(lines[i]);
+ }
+ free(lines);
+
+ return (outbuf);
+}
+
+char **
+isc_backtrace_symbols(void *const *buffer, int size) {
+ if (buffer == NULL || size <= 0) {
+ return (NULL);
+ }
+ return (_backtrace_symbols(buffer, size, false));
+}
+
+void
+isc_backtrace_symbols_fd(void *const *buffer, int size, int fd) {
+ char **strings = NULL;
+ size_t sz;
+
+ strings = _backtrace_symbols(buffer, size, true);
+ if (strings == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < (size_t)size; i++) {
+ sz = strlen(strings[i]);
+ if (write(fd, strings[i], sz) == -1) {
+ return;
+ }
+ }
+
+ free(strings);
+}
+
+#elif HAVE_BACKTRACE_SYMBOLS
+int
+isc_backtrace(void **addrs, int maxaddrs) {
+ int n;
+
/*
* Validate the arguments: intentionally avoid using REQUIRE().
* See notes in backtrace.h.
*/
- if (addrs == NULL || nframes == NULL) {
- return (ISC_R_FAILURE);
+ if (addrs == NULL || maxaddrs <= 0) {
+ return (-1);
}
/*
* backtrace(3) includes this function itself in the address array,
* which should be eliminated from the returned sequence.
*/
- int n = backtrace(addrs, maxaddrs);
+ n = backtrace(addrs, maxaddrs);
if (n < 2) {
- return (ISC_R_NOTFOUND);
+ return (-1);
}
n--;
memmove(addrs, &addrs[1], sizeof(addrs[0]) * n);
- *nframes = n;
- return (ISC_R_SUCCESS);
+
+ return (n);
+}
+
+char **
+isc_backtrace_symbols(void *const *buffer, int size) {
+ return (backtrace_symbols(buffer, size));
+}
+
+void
+isc_backtrace_symbols_fd(void *const *buffer, int size, int fd) {
+ backtrace_symbols_fd(buffer, size, fd);
}
-#else /* HAVE_BACKTRACE */
-isc_result_t
-isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
+#else /* HAVE_BACKTRACE_SYMBOLS */
+
+int
+isc_backtrace(void **addrs, int maxaddrs) {
UNUSED(addrs);
UNUSED(maxaddrs);
- UNUSED(nframes);
- return (ISC_R_NOTIMPLEMENTED);
+ return (-1);
+}
+
+char **
+isc_backtrace_symbols(void *const *buffer, int size) {
+ UNUSED(buffer);
+ UNUSED(size);
+
+ return (NULL);
+}
+
+void
+isc_backtrace_symbols_fd(void *const *buffer, int size, int fd) {
+ UNUSED(buffer);
+ UNUSED(size);
+ UNUSED(fd);
}
-#endif /* HAVE_BACKTRACE */
+
+#endif /* HAVE_BACKTRACE_SYMBOLS */
* 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.
+ * backtrace function).
*/
-#ifndef ISC_BACKTRACE_H
-#define ISC_BACKTRACE_H 1
+#pragma once
/***
*** Imports
***/
-
-#if HAVE_BACKTRACE_SYMBOLS
-#include <execinfo.h>
-#endif /* HAVE_BACKTRACE_SYMBOLS */
-
#include <isc/types.h>
/***
***/
ISC_LANG_BEGINDECLS
-isc_result_t
-isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes);
+int
+isc_backtrace(void **addrs, int maxaddrs);
/*%<
* 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
*\li #ISC_R_NOTFOUND
*\li #ISC_R_NOTIMPLEMENTED
*/
-ISC_LANG_ENDDECLS
-#endif /* ISC_BACKTRACE_H */
+char **
+isc_backtrace_symbols(void *const *buffer, int size);
+/*
+ * isc_backtrace_symbols() attempts to transform a call stack obtained by
+ * backtrace() into an array of human-readable strings using dladdr(). The
+ * array of strings returned has size elements. It is allocated using
+ * malloc() and should be released using free(). There is no need to free
+ * the individual strings in the array.
+ *
+ * Notes:
+ *
+ *\li On Windows, this is shim implementation using SymFromAddr()
+ *\li On systems with backtrace_symbols(), it's just a thin wrapper
+ *\li Otherwise, it returns NULL
+ *\li See platform NOTES for backtrace_symbols
+ *
+ * Returns:
+ *
+ *\li On success, backtrace_symbols() returns a pointer to the array
+ *\li On error, NULL is returned.
+ */
+
+void
+isc_backtrace_symbols_fd(void *const *buffer, int size, int fd);
+/*
+ * isc_backtrace_symbols_fd() performs the same operation as
+ * isc_backtrace_symbols(), but the resulting strings are immediately written to
+ * the file descriptor fd, and are not returned. isc_backtrace_symbols_fd()
+ * does not call malloc(3), and so can be employed in situations where the
+ * latter function might fail.
+ *
+ * Notes:
+ *
+ *\li See isc_backtrace_symbols() notes
+ *\li See platform NOTES for backtrace_symbols_fd for caveats
+ */
+
+ISC_LANG_ENDDECLS
#include <uv.h>
#include <isc/atomic.h>
+#include <isc/backtrace.h>
#include <isc/buffer.h>
#include <isc/condition.h>
#include <isc/errno.h>
#include "openssl_shim.h"
#include "uv-compat.h"
-#if NETMGR_TRACE
-#if HAVE_BACKTRACE
-#include <execinfo.h>
-#else /* HAVE_BACKTRACE */
-#define backtrace(buffer, size) 0
-#define backtrace_symbols_fd(buffer, size, fd) \
- fprintf(stderr, "<not available>");
-#endif /* HAVE_BACKTRACE */
-#endif /* NETMGR_TRACE */
-
/*%
* How many isc_nmhandles and isc_nm_uvreqs will we be
* caching for reuse in a socket.
mgr->mctx, ISC_NM_REQS_STACK_SIZE) };
#if NETMGR_TRACE
- sock->backtrace_size = backtrace(sock->backtrace, TRACE_SIZE);
+ sock->backtrace_size = isc_backtrace(sock->backtrace, TRACE_SIZE);
ISC_LINK_INIT(sock, active_link);
ISC_LIST_INIT(sock->active_handles);
LOCK(&mgr->lock);
isc___nmsocket_attach(sock, &handle->sock FLARG_PASS);
#if NETMGR_TRACE
- handle->backtrace_size = backtrace(handle->backtrace, TRACE_SIZE);
+ handle->backtrace_size = isc_backtrace(handle->backtrace, TRACE_SIZE);
#endif
if (peer != NULL) {
fprintf(stderr, "Active handle %p, refs %" PRIuFAST32 "\n", handle,
isc_refcount_current(&handle->references));
fprintf(stderr, "Created by:\n");
- backtrace_symbols_fd(handle->backtrace, handle->backtrace_size,
- STDERR_FILENO);
+ isc_backtrace_symbols_fd(handle->backtrace, handle->backtrace_size,
+ STDERR_FILENO);
fprintf(stderr, "\n\n");
}
atomic_load(&sock->connecting) ? " connecting" : "",
sock->accepting ? " accepting" : "");
fprintf(stderr, "Created by:\n");
- backtrace_symbols_fd(sock->backtrace, sock->backtrace_size,
- STDERR_FILENO);
+ isc_backtrace_symbols_fd(sock->backtrace, sock->backtrace_size,
+ STDERR_FILENO);
fprintf(stderr, "\n");
for (handle = ISC_LIST_HEAD(sock->active_handles); handle != NULL;
isc_assertion_failed
isc_assertion_setcallback
isc_assertion_typetotext
-isc_backtrace_gettrace
+isc_backtrace
+isc_backtrace_symbols
+isc_backtrace_symbols_fd
isc_base32_decoderegion
isc_base32_decodestring
isc_base32_tobuffer
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
- <AdditionalDependencies>@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBUV_LIB@@NGHTTP2_LIB@@LIBXML2_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBUV_LIB@@NGHTTP2_LIB@@LIBXML2_LIB@@ZLIB_LIB@ws2_32.lib;Dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
<ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
</Link>
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@NGHTTP2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ELSE PKCS11
- <PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>BIND9;WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@NGHTTP2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@END PKCS11