util/debug: Make debug_backtrace_capture work for 64bit windows.
authorJosé Fonseca <jfonseca@vmware.com>
Mon, 24 Jun 2013 12:37:45 +0000 (13:37 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Tue, 25 Jun 2013 17:41:59 +0000 (18:41 +0100)
Rely on Windows' CaptureStackBackTrace to do the grunt work.

Reviewed-by: Brian Paul <brianp@vmware.com>
src/gallium/auxiliary/util/u_debug_stack.c
src/gallium/auxiliary/util/u_debug_stack.h

index 50a248a979f77e7e35da7891d5093ce15ede0b6e..68961d3510e3533f5605eb7606850791ca4cda12 100644 (file)
 #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;
index f50f04e0f7bf8400fed525151281530cc4fe7146..b1848ddefa82b181bfaea969d11a7ea6a4539f35 100644 (file)
@@ -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;