diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index bb5f7137b53..bb61ef0514f 100755 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -60,7 +60,7 @@ if (WIN32) # (as well as all the other third-party dependencies) on MSVC 1900. # # [1] https://github.com/google/glog/pull/43 - set(GLOG_URL ${UPSTREAM_URL}/glog-v0.3.4-g4d391fe.tar.gz) + set(GLOG_URL ${UPSTREAM_URL}/glog-da816ea70.tar.gz) set(CURL_URL ${UPSTREAM_URL}/curl-${CURL_VERSION}.tar.gz) set(LIBAPR_URL ${UPSTREAM_URL}/libapr-${LIBAPR_VERSION}.tar.gz) set(ZLIB_URL ${UPSTREAM_URL}/zlib-${ZLIB_VERSION}.tar.gz) @@ -107,6 +107,7 @@ if (NOT WIN32) set(LIBEVENT_INSTALL_CMD mkdir -p ${LIBEVENT_LIB_ROOT} && cp -r ${LIBEVENT_ROOT}-build/lib/. ${LIBEVENT_LIB_DIR} && cp -r ${LIBEVENT_ROOT}-build/include/. ${LIBEVENT_INCLUDE_DIR} && cp -r ${LIBEVENT_ROOT}/include/. ${LIBEVENT_INCLUDE_DIR}) elseif (WIN32) set(GLOG_INSTALL_CMD ${CMAKE_NOOP}) + set(GLOG_PATCH_CMD ${PATCHEXE_LOCATION} -p1 < ${MESOS_3RDPARTY_SRC}/glog-da816ea70.patch) set(LIBEVENT_INSTALL_CMD ${CMAKE_NOOP}) diff --git a/3rdparty/glog-da816ea70.patch b/3rdparty/glog-da816ea70.patch new file mode 100644 index 00000000000..2f0fae3c465 --- /dev/null +++ b/3rdparty/glog-da816ea70.patch @@ -0,0 +1,726 @@ +diff --git c/CMakeLists.txt w/CMakeLists.txt +index 7ede6e7ad..1b05456e4 100644 +--- c/CMakeLists.txt ++++ w/CMakeLists.txt +@@ -364,9 +364,9 @@ set (GLOG_SRCS + src/vlog_is_on.cc + ) + +-if (HAVE_PTHREAD) ++if (HAVE_PTHREAD OR WIN32) + list (APPEND GLOG_SRCS src/signalhandler.cc) +-endif (HAVE_PTHREAD) ++endif (HAVE_PTHREAD OR WIN32) + + if (WIN32) + list (APPEND GLOG_SRCS +@@ -455,6 +455,12 @@ if (HAVE_EXECINFO_H) + set (HAVE_STACKTRACE 1) + endif (HAVE_EXECINFO_H) + ++if (WIN32) ++ set (HAVE_STACKTRACE 1) ++ set (HAVE_SYMBOLIZE 1) ++ target_link_libraries (glog PUBLIC Dbghelp.lib) ++endif (WIN32) ++ + if (UNIX OR (APPLE AND HAVE_DLADDR)) + set (HAVE_SYMBOLIZE 1) + endif (UNIX OR (APPLE AND HAVE_DLADDR)) +@@ -527,13 +533,13 @@ if (BUILD_TESTING) + + target_link_libraries (utilities_unittest PRIVATE glog) + +- if (HAVE_STACKTRACE AND HAVE_SYMBOLIZE) ++ if (HAVE_STACKTRACE AND HAVE_SYMBOLIZE AND NOT WIN32) + add_executable (signalhandler_unittest + src/signalhandler_unittest.cc + ) + + target_link_libraries (signalhandler_unittest PRIVATE glog) +- endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE) ++ endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE AND NOT WIN32) + + add_test (NAME demangle COMMAND demangle_unittest) + add_test (NAME logging COMMAND logging_unittest) +diff --git c/src/demangle.cc w/src/demangle.cc +index e858181a6..cf897457a 100644 +--- c/src/demangle.cc ++++ w/src/demangle.cc +@@ -35,10 +35,16 @@ + // Note that we only have partial C++0x support yet. + + #include // for NULL ++#include "utilities.h" + #include "demangle.h" + ++#if defined(OS_WINDOWS) ++#include ++#endif ++ + _START_GOOGLE_NAMESPACE_ + ++#if !defined(OS_WINDOWS) + typedef struct { + const char *abbrev; + const char *real_name; +@@ -1293,12 +1299,32 @@ static bool ParseTopLevelMangledName(State *state) { + } + return false; + } ++#endif + + // The demangler entry point. + bool Demangle(const char *mangled, char *out, int out_size) { ++#if defined(OS_WINDOWS) ++ // When built with incremental linking, the Windows debugger ++ // library provides a more complicated `Symbol->Name` with the ++ // Incremental Linking Table offset, which looks like ++ // `@ILT+1105(?func@Foo@@SAXH@Z)`. However, the demangler expects ++ // only the mangled symbol, `?func@Foo@@SAXH@Z`. Fortunately, the ++ // mangled symbol is guaranteed not to have parentheses, ++ // so we search for `(` and extract up to `)`. ++ std::string symbol(mangled); ++ size_t mark = symbol.find('('); ++ if (mark != std::string::npos) { ++ // Extract the string `(?...)` ++ std::string temp = symbol.substr(mark); ++ // Remove the surrounding parentheses ++ symbol = temp.substr(1, temp.size() - 2); ++ } // Else the symbol wasn't inside a set of parentheses ++ return UnDecorateSymbolName(symbol.c_str(), out, out_size, UNDNAME_COMPLETE); ++#else + State state; + InitState(&state, mangled, out, out_size); + return ParseTopLevelMangledName(&state) && !state.overflowed; ++#endif + } + + _END_GOOGLE_NAMESPACE_ +diff --git c/src/demangle_unittest.cc w/src/demangle_unittest.cc +index 32f322101..be483411f 100644 +--- c/src/demangle_unittest.cc ++++ w/src/demangle_unittest.cc +@@ -62,18 +62,37 @@ static const char *DemangleIt(const char * const mangled) { + } + } + ++#if defined(OS_WINDOWS) ++ ++TEST(Demangle, Windows) { ++ EXPECT_STREQ( ++ "public: static void __cdecl Foo::func(int)", ++ DemangleIt("?func@Foo@@SAXH@Z")); ++ EXPECT_STREQ( ++ "public: static void __cdecl Foo::func(int)", ++ DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)")); ++ EXPECT_STREQ( ++ "int __cdecl foobarArray(int * const)", ++ DemangleIt("?foobarArray@@YAHQAH@Z")); ++} ++ ++#else ++ + // Test corner cases of bounary conditions. + TEST(Demangle, CornerCases) { +- char tmp[10]; +- EXPECT_TRUE(Demangle("_Z6foobarv", tmp, sizeof(tmp))); +- // sizeof("foobar()") == 9 +- EXPECT_STREQ("foobar()", tmp); +- EXPECT_TRUE(Demangle("_Z6foobarv", tmp, 9)); +- EXPECT_STREQ("foobar()", tmp); +- EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 8)); // Not enough. +- EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 1)); +- EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 0)); +- EXPECT_FALSE(Demangle("_Z6foobarv", NULL, 0)); // Should not cause SEGV. ++ const size_t size = 10; ++ char tmp[size] = { 0 }; ++ const char *demangled = "foobar()"; ++ const char *mangled = "_Z6foobarv"; ++ EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp))); ++ // sizeof("foobar()") == size - 1 ++ EXPECT_STREQ(demangled, tmp); ++ EXPECT_TRUE(Demangle(mangled, tmp, size - 1)); ++ EXPECT_STREQ(demangled, tmp); ++ EXPECT_FALSE(Demangle(mangled, tmp, size - 2)); // Not enough. ++ EXPECT_FALSE(Demangle(mangled, tmp, 1)); ++ EXPECT_FALSE(Demangle(mangled, tmp, 0)); ++ EXPECT_FALSE(Demangle(mangled, NULL, 0)); // Should not cause SEGV. + } + + // Test handling of functions suffixed with .clone.N, which is used by GCC +@@ -123,6 +142,8 @@ TEST(Demangle, FromFile) { + } + } + ++#endif ++ + int main(int argc, char **argv) { + #ifdef HAVE_LIB_GFLAGS + ParseCommandLineFlags(&argc, &argv, true); +diff --git c/src/logging.cc w/src/logging.cc +index 0b5e6ee97..aa8a95eda 100644 +--- c/src/logging.cc ++++ w/src/logging.cc +@@ -92,6 +92,15 @@ using std::fdopen; + #define fdopen _fdopen + #endif + ++#if defined(OS_WINDOWS) ++_START_GOOGLE_NAMESPACE_ ++namespace glog_internal_namespace_ { ++ void DumpTimeInfo(); ++ void DumpStackInfo(int); ++} ++_END_GOOGLE_NAMESPACE_ ++#endif ++ + // There is no thread annotation support. + #define EXCLUSIVE_LOCKS_REQUIRED(mu) + +@@ -1466,8 +1475,17 @@ void LogMessage::RecordCrashReason( + static void logging_fail() ATTRIBUTE_NORETURN; + + static void logging_fail() { ++#if defined(OS_WINDOWS) ++ // On Windows,the stack trace info needs to be dumped here instead ++ // of in the `SIGABRT` signal handler to avoid thread switching. ++ // The signal handler runs on the thread on which it was installed, ++ // making the stack trace irrelevant. ++ glog_internal_namespace_::DumpTimeInfo(); ++ glog_internal_namespace_::DumpStackInfo(5); ++ FlushLogFilesUnsafe(0); ++#endif + #if defined(_DEBUG) && defined(_MSC_VER) +- // When debugging on windows, avoid the obnoxious dialog and make ++ // When debugging on Windows, avoid the obnoxious dialog and make + // it possible to continue past a LOG(FATAL) in the debugger + __debugbreak(); + #else +diff --git c/src/signalhandler.cc w/src/signalhandler.cc +index a7aef8b99..a28b8b7c6 100644 +--- c/src/signalhandler.cc ++++ w/src/signalhandler.cc +@@ -48,38 +48,11 @@ + + _START_GOOGLE_NAMESPACE_ + +-// TOOD(hamaji): Use signal instead of sigaction? +-#ifdef HAVE_SIGACTION +- +-namespace { +- +-// We'll install the failure signal handler for these signals. We could +-// use strsignal() to get signal names, but we don't use it to avoid +-// introducing yet another #ifdef complication. +-// +-// The list should be synced with the comment in signalhandler.h. +-const struct { +- int number; +- const char *name; +-} kFailureSignals[] = { +- { SIGSEGV, "SIGSEGV" }, +- { SIGILL, "SIGILL" }, +- { SIGFPE, "SIGFPE" }, +- { SIGABRT, "SIGABRT" }, +- { SIGBUS, "SIGBUS" }, +- { SIGTERM, "SIGTERM" }, +-}; ++namespace glog_internal_namespace_ { + +-// Returns the program counter from signal context, NULL if unknown. +-void* GetPC(void* ucontext_in_void) { +-#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT) +- if (ucontext_in_void != NULL) { +- ucontext_t *context = reinterpret_cast(ucontext_in_void); +- return (void*)context->PC_FROM_UCONTEXT; +- } ++#ifdef HAVE_SIGACTION ++ void DumpSignalInfo(int signal_number, siginfo_t *siginfo); + #endif +- return NULL; +-} + + // The class is used for formatting error messages. We don't use printf() + // as it's not async signal safe. +@@ -168,6 +141,76 @@ void DumpTimeInfo() { + g_failure_writer(buf, formatter.num_bytes_written()); + } + ++// Dumps information about the stack frame to STDERR. ++void DumpStackFrameInfo(const char* prefix, void* pc) { ++ // Get the symbol name. ++ const char *symbol = "(unknown)"; ++ char symbolized[1024] = {}; // Big enough for a sane symbol. ++ // Symbolizes the previous address of pc because pc may be in the ++ // next function. ++ if (Symbolize(reinterpret_cast(pc) - 1, ++ symbolized, sizeof(symbolized))) { ++ symbol = symbolized; ++ } ++ ++ char buf[1024]; // Big enough for stack frame info. ++ MinimalFormatter formatter(buf, sizeof(buf)); ++ ++ formatter.AppendString(prefix); ++ formatter.AppendString("@ "); ++ const int width = 2 * sizeof(void*) + 2; // + 2 for "0x". ++ formatter.AppendHexWithPadding(reinterpret_cast(pc), width); ++ formatter.AppendString(" "); ++ formatter.AppendString(symbol); ++ formatter.AppendString("\n"); ++ g_failure_writer(buf, formatter.num_bytes_written()); ++} ++ ++// Argument is the number of frames to skip, excluding this function. ++void DumpStackInfo(int frames) { ++#ifdef HAVE_STACKTRACE ++ // Get the stack traces. ++ void *stack[32]; ++ // +1 to exclude this function. ++ const int depth = GetStackTrace(stack, ARRAYSIZE(stack), frames + 1); ++ // Dump the stack traces. ++ for (int i = 0; i < depth; ++i) { ++ DumpStackFrameInfo(" ", stack[i]); ++ } ++#endif ++} ++ ++// TOOD(hamaji): Use signal instead of sigaction? ++#ifdef HAVE_SIGACTION ++ ++// We'll install the failure signal handler for these signals. We could ++// use strsignal() to get signal names, but we don't use it to avoid ++// introducing yet another #ifdef complication. ++// ++// The list should be synced with the comment in signalhandler.h. ++const struct { ++ int number; ++ const char *name; ++} kFailureSignals[] = { ++ { SIGSEGV, "SIGSEGV" }, ++ { SIGILL, "SIGILL" }, ++ { SIGFPE, "SIGFPE" }, ++ { SIGABRT, "SIGABRT" }, ++ { SIGBUS, "SIGBUS" }, ++ { SIGTERM, "SIGTERM" }, ++}; ++ ++// Returns the program counter from signal context, NULL if unknown. ++void* GetPC(void* ucontext_in_void) { ++#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT) ++ if (ucontext_in_void != NULL) { ++ ucontext_t *context = reinterpret_cast(ucontext_in_void); ++ return (void*)context->PC_FROM_UCONTEXT; ++ } ++#endif ++ return NULL; ++} ++ + // Dumps information about the signal to STDERR. + void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { + // Get the signal name. +@@ -213,31 +256,6 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { + g_failure_writer(buf, formatter.num_bytes_written()); + } + +-// Dumps information about the stack frame to STDERR. +-void DumpStackFrameInfo(const char* prefix, void* pc) { +- // Get the symbol name. +- const char *symbol = "(unknown)"; +- char symbolized[1024]; // Big enough for a sane symbol. +- // Symbolizes the previous address of pc because pc may be in the +- // next function. +- if (Symbolize(reinterpret_cast(pc) - 1, +- symbolized, sizeof(symbolized))) { +- symbol = symbolized; +- } +- +- char buf[1024]; // Big enough for stack frame info. +- MinimalFormatter formatter(buf, sizeof(buf)); +- +- formatter.AppendString(prefix); +- formatter.AppendString("@ "); +- const int width = 2 * sizeof(void*) + 2; // + 2 for "0x". +- formatter.AppendHexWithPadding(reinterpret_cast(pc), width); +- formatter.AppendString(" "); +- formatter.AppendString(symbol); +- formatter.AppendString("\n"); +- g_failure_writer(buf, formatter.num_bytes_written()); +-} +- + // Invoke the default signal handler. + void InvokeDefaultSignalHandler(int signal_number) { + struct sigaction sig_action; +@@ -302,18 +320,14 @@ void FailureSignalHandler(int signal_number, + void *pc = GetPC(ucontext); + DumpStackFrameInfo("PC: ", pc); + +-#ifdef HAVE_STACKTRACE +- // Get the stack traces. +- void *stack[32]; +- // +1 to exclude this function. +- const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1); ++ // Now dumb the signal info. ++#ifdef HAVE_SIGACTION + DumpSignalInfo(signal_number, signal_info); +- // Dump the stack traces. +- for (int i = 0; i < depth; ++i) { +- DumpStackFrameInfo(" ", stack[i]); +- } + #endif + ++ // Now dump the stack trace. ++ DumpStackInfo(0); ++ + // *** TRANSITION *** + // + // BEFORE this point, all code must be async-termination-safe! +@@ -330,12 +344,15 @@ void FailureSignalHandler(int signal_number, + // Kill ourself by the default signal handler. + InvokeDefaultSignalHandler(signal_number); + } +- +-} // namespace +- ++#elif defined(OS_WINDOWS) ++void FailureSignalHandler(int signal) { ++ if (signal != SIGABRT) { ++ return; ++ } ++ exit(1); ++} + #endif // HAVE_SIGACTION + +-namespace glog_internal_namespace_ { + + bool IsFailureSignalHandlerInstalled() { + #ifdef HAVE_SIGACTION +@@ -345,6 +362,9 @@ bool IsFailureSignalHandlerInstalled() { + sigaction(SIGABRT, NULL, &sig_action); + if (sig_action.sa_sigaction == &FailureSignalHandler) + return true; ++#elif defined(OS_WINDOWS) ++ // TODO: check if we installed it ++ return true; + #endif // HAVE_SIGACTION + return false; + } +@@ -363,11 +383,15 @@ void InstallFailureSignalHandler() { + for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { + CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL)); + } ++#elif defined(OS_WINDOWS) ++ typedef void (*SignalHandlerPointer)(int); ++ SignalHandlerPointer previousHandler; ++ previousHandler = signal(SIGABRT, &FailureSignalHandler); + #endif // HAVE_SIGACTION + } + + void InstallFailureWriter(void (*writer)(const char* data, int size)) { +-#ifdef HAVE_SIGACTION ++#if defined(HAVE_SIGACTION) || defined(OS_WINDOWS) + g_failure_writer = writer; + #endif // HAVE_SIGACTION + } +diff --git c/src/stacktrace_unittest.cc w/src/stacktrace_unittest.cc +index c1b3b36ff..ed95f8945 100644 +--- c/src/stacktrace_unittest.cc ++++ w/src/stacktrace_unittest.cc +@@ -90,6 +90,32 @@ AddressRange expected_range[BACKTRACE_STEPS]; + (prange)->end = ra; \ + } \ + } while (0) ++#elif defined(OS_WINDOWS) ++// Compiler Intrinsic _ReturnAddress documentation: ++// https://msdn.microsoft.com/en-us/library/64ez38eh(v=vs.140).aspx ++// This is equivalent to __builtin_return_address. ++#include ++#pragma intrinsic(_ReturnAddress) ++#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \ ++ do { \ ++ (prange)->start = &fn; \ ++ (prange)->end = _ReturnAddress(); \ ++ CHECK_LT((prange)->start, (prange)->end); \ ++ } while (0) ++#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0) ++// MSVC may do the same thing as GCC (as noted above). ++// Adjust function range from _ReturnAddress. ++#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \ ++ do { \ ++ void *ra = _ReturnAddress(); \ ++ CHECK_LT((prange)->start, ra); \ ++ if (ra > (prange)->end) { \ ++ printf("Adjusting range from %p..%p to %p..%p\n", \ ++ (prange)->start, (prange)->end, \ ++ (prange)->start, ra); \ ++ (prange)->end = ra; \ ++ } \ ++ } while (0) + #else + // Assume the Check* functions below are not longer than 256 bytes. + #define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \ +diff --git c/src/stacktrace_windows-inl.h w/src/stacktrace_windows-inl.h +new file mode 100644 +index 000000000..dc23d109d +--- /dev/null ++++ w/src/stacktrace_windows-inl.h +@@ -0,0 +1,49 @@ ++// Copyright (c) 2000 - 2007, Google Inc. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions are ++// met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above ++// copyright notice, this list of conditions and the following disclaimer ++// in the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Google Inc. nor the names of its ++// contributors may be used to endorse or promote products derived from ++// this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++// Author: Andrew Schwartzmeyer ++// ++// Windows implementation - just use CaptureStackBackTrace ++ ++#include "port.h" ++#include "stacktrace.h" ++#include "Dbghelp.h" ++ ++_START_GOOGLE_NAMESPACE_ ++ ++int GetStackTrace(void** result, int max_depth, int skip_count) { ++ if (max_depth > 64) { ++ max_depth = 64; ++ } ++ skip_count++; // we want to skip the current frame as well ++ // This API is thread-safe (moreover it walks only the current thread). ++ return CaptureStackBackTrace(skip_count, max_depth, result, NULL); ++} ++ ++_END_GOOGLE_NAMESPACE_ +diff --git c/src/symbolize.cc w/src/symbolize.cc +index f83c30973..0f10a86af 100644 +--- c/src/symbolize.cc ++++ w/src/symbolize.cc +@@ -837,6 +837,57 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, + + _END_GOOGLE_NAMESPACE_ + ++#elif defined(OS_WINDOWS) ++ ++#include "Dbghelp.h" ++ ++_START_GOOGLE_NAMESPACE_ ++ ++class SymInitializer { ++public: ++ HANDLE process = NULL; ++ bool ready = false; ++ SymInitializer() { ++ // Initialize the symbol handler. ++ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx ++ process = GetCurrentProcess(); ++ // Defer symbol loading. ++ // We do not request undecorated symbols with SYMOPT_UNDNAME ++ // because the mangling library calls UnDecorateSymbolName. ++ SymSetOptions(SYMOPT_DEFERRED_LOADS); ++ if (SymInitialize(process, NULL, true)) { ++ ready = true; ++ } ++ } ++ ~SymInitializer() { ++ SymCleanup(process); ++ } ++}; ++ ++__declspec(noinline) static bool SymbolizeAndDemangle(void *pc, char *out, ++ int out_size) { ++ const SymInitializer symInitializer; ++ if (!symInitializer.ready) { ++ return false; ++ } ++ // Resolve symbol information from address. ++ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx ++ char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; ++ SYMBOL_INFO *symbol = reinterpret_cast(buf); ++ symbol->SizeOfStruct = sizeof(SYMBOL_INFO); ++ symbol->MaxNameLen = MAX_SYM_NAME; ++ bool ret = SymFromAddr(symInitializer.process, reinterpret_cast(pc), 0, symbol); ++ if (ret && static_cast(symbol->NameLen) < out_size) { ++ strncpy(out, symbol->Name, symbol->NameLen + 1); ++ // Symbolization succeeded. Now we try to demangle the symbol. ++ DemangleInplace(out, out_size); ++ return true; ++ } ++ return false; ++} ++ ++_END_GOOGLE_NAMESPACE_ ++ + #else + # error BUG: HAVE_SYMBOLIZE was wrongly set + #endif +diff --git c/src/symbolize_unittest.cc w/src/symbolize_unittest.cc +index 05cb8a11c..348a71b43 100644 +--- c/src/symbolize_unittest.cc ++++ w/src/symbolize_unittest.cc +@@ -49,10 +49,22 @@ using namespace GFLAGS_NAMESPACE; + using namespace std; + using namespace GOOGLE_NAMESPACE; + +-#if defined(HAVE_STACKTRACE) && defined(__ELF__) ++#if defined(HAVE_STACKTRACE) + + #define always_inline + ++// A wrapper function for Symbolize() to make the unit test simple. ++static const char *TrySymbolize(void *pc) { ++ static char symbol[4096]; ++ if (Symbolize(pc, symbol, sizeof(symbol))) { ++ return symbol; ++ } else { ++ return NULL; ++ } ++} ++ ++# if defined(__ELF__) ++ + // This unit tests make sense only with GCC. + // Uses lots of GCC specific features. + #if defined(__GNUC__) && !defined(__OPENCC__) +@@ -70,16 +82,6 @@ using namespace GOOGLE_NAMESPACE; + # endif // defined(__i386__) || defined(__x86_64__) + #endif + +-// A wrapper function for Symbolize() to make the unit test simple. +-static const char *TrySymbolize(void *pc) { +- static char symbol[4096]; +- if (Symbolize(pc, symbol, sizeof(symbol))) { +- return symbol; +- } else { +- return NULL; +- } +-} +- + // Make them C linkage to avoid mangled names. + extern "C" { + void nonstatic_func() { +@@ -340,11 +342,42 @@ void ATTRIBUTE_NOINLINE TestWithReturnAddress() { + #endif + } + ++# elif defined(OS_WINDOWS) ++ ++#include ++#pragma intrinsic(_ReturnAddress) ++ ++struct Foo { ++ static void func(int x); ++}; ++ ++__declspec(noinline) void Foo::func(int x) { ++ volatile int a = x; ++ ++a; ++} ++ ++TEST(Symbolize, SymbolizeWithDemangling) { ++ Foo::func(100); ++ const char* ret = TrySymbolize((void *)(&Foo::func)); ++ EXPECT_STREQ("public: static void __cdecl Foo::func(int)", ret); ++} ++ ++__declspec(noinline) void TestWithReturnAddress() { ++ void *return_address = _ReturnAddress(); ++ const char *symbol = TrySymbolize(return_address); ++ CHECK(symbol != NULL); ++ CHECK_STREQ(symbol, "main"); ++ cout << "Test case TestWithReturnAddress passed." << endl; ++} ++# endif // __ELF__ ++#endif // HAVE_STACKTRACE ++ + int main(int argc, char **argv) { + FLAGS_logtostderr = true; + InitGoogleLogging(argv[0]); + InitGoogleTest(&argc, argv); +-#ifdef HAVE_SYMBOLIZE ++#if defined(HAVE_SYMBOLIZE) ++# if defined(__ELF__) + // We don't want to get affected by the callback interface, that may be + // used to install some callback function at InitGoogle() time. + InstallSymbolizeCallback(NULL); +@@ -353,18 +386,15 @@ int main(int argc, char **argv) { + TestWithPCInsideNonInlineFunction(); + TestWithReturnAddress(); + return RUN_ALL_TESTS(); +-#else +- return 0; +-#endif +-} +- +-#else +-int main() { +-#ifdef HAVE_SYMBOLIZE ++# elif defined(OS_WINDOWS) ++ TestWithReturnAddress(); ++ return RUN_ALL_TESTS(); ++# else + printf("PASS (no symbolize_unittest support)\n"); ++ return 0; ++# endif // __ELF__ + #else + printf("PASS (no symbolize support)\n"); +-#endif + return 0; ++#endif + } +-#endif // HAVE_STACKTRACE +diff --git c/src/utilities.h w/src/utilities.h +index 5f79968ef..10f98b24a 100644 +--- c/src/utilities.h ++++ w/src/utilities.h +@@ -97,6 +97,8 @@ + // malloc() from the unwinder. This is a problem because we're + // trying to use the unwinder to instrument malloc(). + // ++// 4) The Windows API CaptureStackTrace. ++// + // Note: if you add a new implementation here, make sure it works + // correctly when GetStackTrace() is called with max_depth == 0. + // Some code may do that. +@@ -110,6 +112,8 @@ + # define STACKTRACE_H "stacktrace_x86_64-inl.h" + # elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2 + # define STACKTRACE_H "stacktrace_powerpc-inl.h" ++# elif defined(OS_WINDOWS) ++# define STACKTRACE_H "stacktrace_windows-inl.h" + # endif + #endif + +@@ -127,6 +131,9 @@ + #elif defined(OS_MACOSX) && defined(HAVE_DLADDR) + // Use dladdr to symbolize. + # define HAVE_SYMBOLIZE ++#elif defined(OS_WINDOWS) ++// Use Dbghelp.dll to symbolize ++# define HAVE_SYMBOLIZE + #endif + + #ifndef ARRAYSIZE