Commit e5d36443 authored by Andrew Schwartzmeyer's avatar Andrew Schwartzmeyer

Support stacktrace on Windows

parent 9c1d0e6f
......@@ -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))
......
......@@ -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 <execinfo.h>
#include <string.h>
// Windows implementation - just use CaptureStackBackTrace
#include "port.h"
#include "stacktrace.h"
#include "Dbghelp.h"
#include <vector>
_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<void*> 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<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_
......@@ -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
......
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