1 /**************************************************************************
3 * Copyright 2009 VMware, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
32 * @author Jose Fonseca <jfonseca@vmware.com>
35 #include "util/u_debug.h"
36 #include "u_debug_symbol.h"
37 #include "u_debug_stack.h"
38 #include "pipe/p_config.h"
40 #if defined(HAVE_LIBUNWIND)
47 #include "os/os_thread.h"
48 #include "util/hash_table.h"
50 static struct hash_table
* symbols_hash
;
51 static mtx_t symbols_mutex
= _MTX_INITIALIZER_NP
;
53 /* TODO with some refactoring we might be able to re-use debug_symbol_name_cached()
54 * instead.. otoh if using libunwind I think u_debug_symbol could just be excluded
58 symbol_name_cached(unw_cursor_t
*cursor
, unw_proc_info_t
*pip
)
60 void *addr
= (void *)(uintptr_t)pip
->start_ip
;
63 mtx_lock(&symbols_mutex
);
65 symbols_hash
= _mesa_pointer_hash_table_create(NULL
);
66 struct hash_entry
*entry
= _mesa_hash_table_search(symbols_hash
, addr
);
72 ret
= unw_get_proc_name(cursor
, procname
, sizeof(procname
), &off
);
73 if (ret
&& ret
!= -UNW_ENOMEM
) {
78 if (asprintf(&name
, "%s%s", procname
, ret
== -UNW_ENOMEM
? "..." : "") == -1)
80 entry
= _mesa_hash_table_insert(symbols_hash
, addr
, (void*)name
);
82 mtx_unlock(&symbols_mutex
);
88 debug_backtrace_capture(struct debug_stack_frame
*backtrace
,
93 unw_context_t context
;
97 pip
.unwind_info
= NULL
;
99 unw_getcontext(&context
);
100 unw_init_local(&cursor
, &context
);
102 while ((start_frame
> 0) && (unw_step(&cursor
) > 0))
105 while ((i
< nr_frames
) && (unw_step(&cursor
) > 0)) {
108 unw_get_reg(&cursor
, UNW_REG_IP
, &ip
);
109 unw_get_proc_info(&cursor
, &pip
);
111 backtrace
[i
].start_ip
= pip
.start_ip
;
112 backtrace
[i
].off
= ip
- pip
.start_ip
;
113 backtrace
[i
].procname
= symbol_name_cached(&cursor
, &pip
);
118 while (i
< nr_frames
) {
119 backtrace
[i
].start_ip
= 0;
125 frame_ip(const struct debug_stack_frame
*frame
)
127 return (void *)(uintptr_t)(frame
->start_ip
+ frame
->off
);
131 frame_info(const struct debug_stack_frame
*frame
, unsigned *offset
)
134 const void *addr
= frame_ip(frame
);
137 if (dladdr(addr
, &dlinfo
) && dlinfo
.dli_fname
&&
139 *offset
= (unsigned)((uintptr_t)addr
- (uintptr_t)dlinfo
.dli_fbase
);
140 return dlinfo
.dli_fname
;
148 debug_backtrace_dump(const struct debug_stack_frame
*backtrace
,
152 const char *filename
;
154 for (i
= 0; i
< nr_frames
; ++i
) {
155 if (!backtrace
[i
].start_ip
)
157 filename
= frame_info(&backtrace
[i
], &offset
);
158 debug_printf("\t%s(+0x%x) (%s+0x%x) [%p]\n", filename
, offset
,
159 backtrace
[i
].procname
, backtrace
[i
].off
,
160 frame_ip(&backtrace
[i
]));
165 debug_backtrace_print(FILE *f
,
166 const struct debug_stack_frame
*backtrace
,
170 const char *filename
;
172 for (i
= 0; i
< nr_frames
; ++i
) {
173 if (!backtrace
[i
].start_ip
)
175 filename
= frame_info(&backtrace
[i
], &offset
);
176 fprintf(f
, "\t%s(+0x%x) (%s+0x%x) [%p]\n", filename
, offset
,
177 backtrace
[i
].procname
, backtrace
[i
].off
,
178 frame_ip(&backtrace
[i
]));
181 #elif defined(ANDROID)
182 /* Not implemented here; see u_debug_stack_android.cpp */
183 #else /* ! HAVE_LIBUNWIND */
185 #if defined(PIPE_OS_WINDOWS)
191 * Capture stack backtrace.
193 * NOTE: The implementation of this function is quite big, but it is important
194 * not to break it down in smaller functions to avoid adding new frames to the
198 debug_backtrace_capture(struct debug_stack_frame
*backtrace
,
199 unsigned start_frame
,
202 const void **frame_pointer
= NULL
;
210 * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
212 * It works reliably both for x86 for x86_64.
214 #if defined(PIPE_OS_WINDOWS)
216 typedef USHORT (WINAPI
*PFNCAPTURESTACKBACKTRACE
)(ULONG
, ULONG
,
218 static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace
= NULL
;
220 if (!pfnCaptureStackBackTrace
) {
221 static HMODULE hModule
= NULL
;
223 hModule
= LoadLibraryA("kernel32");
227 pfnCaptureStackBackTrace
=
228 (PFNCAPTURESTACKBACKTRACE
)GetProcAddress(hModule
,
229 "RtlCaptureStackBackTrace");
232 if (pfnCaptureStackBackTrace
) {
234 * Skip this (debug_backtrace_capture) function's frame.
239 assert(start_frame
+ nr_frames
< 63);
240 i
= pfnCaptureStackBackTrace(start_frame
, nr_frames
,
241 (PVOID
*) &backtrace
->function
, NULL
);
243 /* Pad remaing requested frames with NULL */
244 while (i
< nr_frames
) {
245 backtrace
[i
++].function
= NULL
;
253 #if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 404) || defined(__clang__)
254 #pragma GCC diagnostic push
255 #pragma GCC diagnostic ignored "-Wframe-address"
256 frame_pointer
= ((const void **)__builtin_frame_address(1));
257 #pragma GCC diagnostic pop
258 #elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
260 mov frame_pointer
, ebp
262 frame_pointer
= (const void **)frame_pointer
[0];
264 frame_pointer
= NULL
;
269 const void **next_frame_pointer
;
277 backtrace
[i
++].function
= frame_pointer
[1];
281 next_frame_pointer
= (const void **)frame_pointer
[0];
283 /* Limit the stack walk to avoid referencing undefined memory */
284 if ((uintptr_t)next_frame_pointer
<= (uintptr_t)frame_pointer
||
285 (uintptr_t)next_frame_pointer
> (uintptr_t)frame_pointer
+ 64*1024)
288 frame_pointer
= next_frame_pointer
;
291 (void) frame_pointer
;
295 backtrace
[i
++].function
= NULL
;
302 debug_backtrace_dump(const struct debug_stack_frame
*backtrace
,
307 for (i
= 0; i
< nr_frames
; ++i
) {
308 if (!backtrace
[i
].function
)
310 debug_symbol_print(backtrace
[i
].function
);
316 debug_backtrace_print(FILE *f
,
317 const struct debug_stack_frame
*backtrace
,
322 for (i
= 0; i
< nr_frames
; ++i
) {
324 if (!backtrace
[i
].function
)
326 symbol
= debug_symbol_name_cached(backtrace
[i
].function
);
328 fprintf(f
, "%s\n", symbol
);
332 #endif /* HAVE_LIBUNWIND */