• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2009 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 /**
29  * @file
30  * Stack backtracing.
31  *
32  * @author Jose Fonseca <jfonseca@vmware.com>
33  */
34 
35 #include "u_debug.h"
36 #include "u_debug_symbol.h"
37 #include "u_debug_stack.h"
38 
39 #if defined(PIPE_OS_WINDOWS)
40 #include <windows.h>
41 #endif
42 
43 
44 /**
45  * Capture stack backtrace.
46  *
47  * NOTE: The implementation of this function is quite big, but it is important
48  * not to break it down in smaller functions to avoid adding new frames to the
49  * calling stack.
50  */
51 void
debug_backtrace_capture(struct debug_stack_frame * backtrace,unsigned start_frame,unsigned nr_frames)52 debug_backtrace_capture(struct debug_stack_frame *backtrace,
53                         unsigned start_frame,
54                         unsigned nr_frames)
55 {
56    const void **frame_pointer = NULL;
57    unsigned i = 0;
58 
59    if (!nr_frames) {
60       return;
61    }
62 
63    /*
64     * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
65     *
66     * It works reliably both for x86 for x86_64.
67     */
68 #if defined(PIPE_OS_WINDOWS)
69    {
70       typedef USHORT (WINAPI *PFNCAPTURESTACKBACKTRACE)(ULONG, ULONG,
71                                                         PVOID *, PULONG);
72       static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace = NULL;
73 
74       if (!pfnCaptureStackBackTrace) {
75          static HMODULE hModule = NULL;
76          if (!hModule) {
77             hModule = LoadLibraryA("kernel32");
78             assert(hModule);
79          }
80          if (hModule) {
81             pfnCaptureStackBackTrace =
82                (PFNCAPTURESTACKBACKTRACE)GetProcAddress(hModule,
83                                                 "RtlCaptureStackBackTrace");
84          }
85       }
86       if (pfnCaptureStackBackTrace) {
87          /*
88           * Skip this (debug_backtrace_capture) function's frame.
89           */
90 
91          start_frame += 1;
92 
93          assert(start_frame + nr_frames < 63);
94          i = pfnCaptureStackBackTrace(start_frame, nr_frames,
95                                       (PVOID *) &backtrace->function, NULL);
96 
97          /* Pad remaing requested frames with NULL */
98          while (i < nr_frames) {
99             backtrace[i++].function = NULL;
100          }
101 
102          return;
103       }
104    }
105 #endif
106 
107 #if defined(PIPE_CC_GCC)
108    frame_pointer = ((const void **)__builtin_frame_address(1));
109 #elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
110    __asm {
111       mov frame_pointer, ebp
112    }
113    frame_pointer = (const void **)frame_pointer[0];
114 #else
115    frame_pointer = NULL;
116 #endif
117 
118 #ifdef PIPE_ARCH_X86
119    while (nr_frames) {
120       const void **next_frame_pointer;
121 
122       if (!frame_pointer)
123          break;
124 
125       if (start_frame)
126          --start_frame;
127       else {
128          backtrace[i++].function = frame_pointer[1];
129          --nr_frames;
130       }
131 
132       next_frame_pointer = (const void **)frame_pointer[0];
133 
134       /* Limit the stack walk to avoid referencing undefined memory */
135       if ((uintptr_t)next_frame_pointer <= (uintptr_t)frame_pointer ||
136           (uintptr_t)next_frame_pointer > (uintptr_t)frame_pointer + 64*1024)
137          break;
138 
139       frame_pointer = next_frame_pointer;
140    }
141 #else
142    (void) frame_pointer;
143 #endif
144 
145    while (nr_frames) {
146       backtrace[i++].function = NULL;
147       --nr_frames;
148    }
149 }
150 
151 
152 void
debug_backtrace_dump(const struct debug_stack_frame * backtrace,unsigned nr_frames)153 debug_backtrace_dump(const struct debug_stack_frame *backtrace,
154                      unsigned nr_frames)
155 {
156    unsigned i;
157 
158    for (i = 0; i < nr_frames; ++i) {
159       if (!backtrace[i].function)
160          break;
161       debug_symbol_print(backtrace[i].function);
162    }
163 }
164 
165