summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJosé Fonseca <[email protected]>2013-06-24 13:37:45 +0100
committerJosé Fonseca <[email protected]>2013-06-25 18:41:59 +0100
commita26f834a39063b68466db62b154c6fe817f06008 (patch)
tree6b57eee487e7f4c0a885511f03e9b452ed50fa95 /src
parent29dacd98038efa5b5056464167cb30290c41a090 (diff)
util/debug: Make debug_backtrace_capture work for 64bit windows.
Rely on Windows' CaptureStackBackTrace to do the grunt work. Reviewed-by: Brian Paul <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/gallium/auxiliary/util/u_debug_stack.c56
-rw-r--r--src/gallium/auxiliary/util/u_debug_stack.h7
2 files changed, 61 insertions, 2 deletions
diff --git a/src/gallium/auxiliary/util/u_debug_stack.c b/src/gallium/auxiliary/util/u_debug_stack.c
index 50a248a979f..68961d3510e 100644
--- a/src/gallium/auxiliary/util/u_debug_stack.c
+++ b/src/gallium/auxiliary/util/u_debug_stack.c
@@ -36,7 +36,17 @@
#include "u_debug_symbol.h"
#include "u_debug_stack.h"
+#if defined(PIPE_OS_WINDOWS)
+#include <windows.h>
+#endif
+
+/**
+ * Capture stack backtrace.
+ *
+ * NOTE: The implementation of this function is quite big, but it is important not to
+ * break it down in smaller functions to avoid adding new frames to the calling stack.
+ */
void
debug_backtrace_capture(struct debug_stack_frame *backtrace,
unsigned start_frame,
@@ -45,8 +55,50 @@ debug_backtrace_capture(struct debug_stack_frame *backtrace,
const void **frame_pointer = NULL;
unsigned i = 0;
- if(!nr_frames)
+ if (!nr_frames) {
return;
+ }
+
+ /*
+ * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
+ *
+ * It works reliably both for x86 for x86_64.
+ */
+#if defined(PIPE_OS_WINDOWS)
+ {
+ typedef USHORT (WINAPI *PFNCAPTURESTACKBACKTRACE)(ULONG, ULONG, PVOID *, PULONG);
+ static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace = NULL;
+
+ if (!pfnCaptureStackBackTrace) {
+ static HMODULE hModule = NULL;
+ if (!hModule) {
+ hModule = LoadLibraryA("kernel32");
+ assert(hModule);
+ }
+ if (hModule) {
+ pfnCaptureStackBackTrace = (PFNCAPTURESTACKBACKTRACE)GetProcAddress(hModule,
+ "RtlCaptureStackBackTrace");
+ }
+ }
+ if (pfnCaptureStackBackTrace) {
+ /*
+ * Skip this (debug_backtrace_capture) function's frame.
+ */
+
+ start_frame += 1;
+
+ assert(start_frame + nr_frames < 63);
+ i = pfnCaptureStackBackTrace(start_frame, nr_frames, (PVOID *) &backtrace->function, NULL);
+
+ /* Pad remaing requested frames with NULL */
+ while (i < nr_frames) {
+ backtrace[i++].function = NULL;
+ }
+
+ return;
+ }
+ }
+#endif
#if defined(PIPE_CC_GCC)
frame_pointer = ((const void **)__builtin_frame_address(1));
@@ -86,7 +138,7 @@ debug_backtrace_capture(struct debug_stack_frame *backtrace,
#else
(void) frame_pointer;
#endif
-
+
while(nr_frames) {
backtrace[i++].function = NULL;
--nr_frames;
diff --git a/src/gallium/auxiliary/util/u_debug_stack.h b/src/gallium/auxiliary/util/u_debug_stack.h
index f50f04e0f7b..b1848ddefa8 100644
--- a/src/gallium/auxiliary/util/u_debug_stack.h
+++ b/src/gallium/auxiliary/util/u_debug_stack.h
@@ -42,6 +42,13 @@ extern "C" {
#endif
+/**
+ * Represent a frame from a stack backtrace.
+ *
+ * XXX: Do not change this.
+ *
+ * TODO: This should be refactored as a void * typedef.
+ */
struct debug_stack_frame
{
const void *function;