Commit e5d36443 authored by Andrew Schwartzmeyer's avatar Andrew Schwartzmeyer

Support stacktrace on Windows

parent 9c1d0e6f
...@@ -455,6 +455,11 @@ if (HAVE_EXECINFO_H) ...@@ -455,6 +455,11 @@ if (HAVE_EXECINFO_H)
set (HAVE_STACKTRACE 1) set (HAVE_STACKTRACE 1)
endif (HAVE_EXECINFO_H) 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)) if (UNIX OR (APPLE AND HAVE_DLADDR))
set (HAVE_SYMBOLIZE 1) set (HAVE_SYMBOLIZE 1)
endif (UNIX OR (APPLE AND HAVE_DLADDR)) endif (UNIX OR (APPLE AND HAVE_DLADDR))
......
...@@ -27,33 +27,60 @@ ...@@ -27,33 +27,60 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // 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. // Windows implementation - just use CaptureStackBackTrace
// This can cause a deadlock in HeapProfiler.
#include <execinfo.h> #include "port.h"
#include <string.h>
#include "stacktrace.h" #include "stacktrace.h"
#include "Dbghelp.h"
#include <vector>
_START_GOOGLE_NAMESPACE_ _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. // If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) { int GetStackTrace(void** result, int max_depth, int skip_count) {
static const int kStackLength = 64; if (!ready_to_run) {
void * stack[kStackLength]; return 0;
int size; }
size = backtrace(stack, kStackLength);
skip_count++; // we want to skip the current frame as well skip_count++; // we want to skip the current frame as well
int result_count = size - skip_count; if (max_depth > 64) {
if (result_count < 0) max_depth = 64;
result_count = 0; }
if (result_count > max_depth) std::vector<void*> stack(max_depth);
result_count = max_depth; // This API is thread-safe (moreover it walks only the current thread).
for (int i = 0; i < result_count; i++) int size = CaptureStackBackTrace(skip_count, max_depth, &stack[0], NULL);
result[i] = stack[i + skip_count]; 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<SYMBOL_INFO*>(buffer);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
SymFromAddr(module_initializer.hProcess, reinterpret_cast<DWORD64>(stack[i]), 0, symbol);
result[i] = stack[i];
}
return result_count; return size;
} }
_END_GOOGLE_NAMESPACE_ _END_GOOGLE_NAMESPACE_
...@@ -99,6 +99,8 @@ ...@@ -99,6 +99,8 @@
// malloc() from the unwinder. This is a problem because we're // malloc() from the unwinder. This is a problem because we're
// trying to use the unwinder to instrument malloc(). // 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 // Note: if you add a new implementation here, make sure it works
// correctly when GetStackTrace() is called with max_depth == 0. // correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that. // Some code may do that.
...@@ -112,6 +114,8 @@ ...@@ -112,6 +114,8 @@
# define STACKTRACE_H "stacktrace_x86_64-inl.h" # define STACKTRACE_H "stacktrace_x86_64-inl.h"
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2 # elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_powerpc-inl.h" # define STACKTRACE_H "stacktrace_powerpc-inl.h"
# elif defined(OS_WINDOWS)
# define STACKTRACE_H "stacktrace_windows-inl.h"
# endif # endif
#endif #endif
...@@ -143,6 +147,9 @@ namespace glog_internal_namespace_ { ...@@ -143,6 +147,9 @@ namespace glog_internal_namespace_ {
#ifdef HAVE___ATTRIBUTE__ #ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_NOINLINE __attribute__ ((noinline)) # define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
# define HAVE_ATTRIBUTE_NOINLINE # define HAVE_ATTRIBUTE_NOINLINE
#elif defined(OS_WINDOWS)
# define ATTRIBUTE_NOINLINE __declspec(noinline)
# define HAVE_ATTRIBUTE_NOINLINE
#else #else
# define ATTRIBUTE_NOINLINE # define ATTRIBUTE_NOINLINE
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment