From: Andrew Schwartzmeyer Date: Wed, 21 Dec 2016 21:48:58 +0000 (-0800) Subject: Support stacktrace on Windows X-Git-Tag: accepted/tizen/5.0/unified/20181102.024921~40^2~4 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fupstream%2Fglog.git;a=commitdiff_plain;h=e5d36443c6d03453f985721a6b16b4f1749846c4 Support stacktrace on Windows --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 7415eab..d353c00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -455,6 +455,11 @@ if (HAVE_EXECINFO_H) set (HAVE_STACKTRACE 1) endif (HAVE_EXECINFO_H) +if (WIN32) + set (HAVE_STACKTRACE 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)) diff --git a/src/stacktrace_windows-inl.h b/src/stacktrace_windows-inl.h index fad81d3..5606408 100644 --- a/src/stacktrace_windows-inl.h +++ b/src/stacktrace_windows-inl.h @@ -27,33 +27,60 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Portable implementation - just use glibc +// Author: Andrew Schwartzmeyer // -// Note: The glibc implementation may cause a call to malloc. -// This can cause a deadlock in HeapProfiler. -#include -#include +// Windows implementation - just use CaptureStackBackTrace + +#include "port.h" #include "stacktrace.h" +#include "Dbghelp.h" +#include _START_GOOGLE_NAMESPACE_ +static bool ready_to_run = false; +class StackTraceInit { +public: + HANDLE hProcess; + StackTraceInit() { + // Initialize the symbol handler + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx + hProcess = GetCurrentProcess(); + SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + SymInitialize(hProcess, NULL, true); + ready_to_run = true; + } + ~StackTraceInit() { + SymCleanup(hProcess); + ready_to_run = false; + } +}; + +static const StackTraceInit module_initializer; // Force initialization + // If you change this function, also change GetStackFrames below. int GetStackTrace(void** result, int max_depth, int skip_count) { - static const int kStackLength = 64; - void * stack[kStackLength]; - int size; - - size = backtrace(stack, kStackLength); + if (!ready_to_run) { + return 0; + } skip_count++; // we want to skip the current frame as well - int result_count = size - skip_count; - if (result_count < 0) - result_count = 0; - if (result_count > max_depth) - result_count = max_depth; - for (int i = 0; i < result_count; i++) - result[i] = stack[i + skip_count]; + if (max_depth > 64) { + max_depth = 64; + } + std::vector stack(max_depth); + // This API is thread-safe (moreover it walks only the current thread). + int size = CaptureStackBackTrace(skip_count, max_depth, &stack[0], NULL); + for (int i = 0; i < size; ++i) { + // Resolve symbol information from address. + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + SYMBOL_INFO* symbol = reinterpret_cast(buffer); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + SymFromAddr(module_initializer.hProcess, reinterpret_cast(stack[i]), 0, symbol); + result[i] = stack[i]; + } - return result_count; + return size; } _END_GOOGLE_NAMESPACE_ diff --git a/src/utilities.h b/src/utilities.h index 101ca64..a10735b 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -99,6 +99,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. @@ -112,6 +114,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 @@ -143,6 +147,9 @@ namespace glog_internal_namespace_ { #ifdef HAVE___ATTRIBUTE__ # define ATTRIBUTE_NOINLINE __attribute__ ((noinline)) # define HAVE_ATTRIBUTE_NOINLINE +#elif defined(OS_WINDOWS) +# define ATTRIBUTE_NOINLINE __declspec(noinline) +# define HAVE_ATTRIBUTE_NOINLINE #else # define ATTRIBUTE_NOINLINE #endif