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 "u_hash_table.h"
50 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
= util_hash_table_create_ptr_keys();
66 name
= util_hash_table_get(symbols_hash
, addr
);
73 ret
= unw_get_proc_name(cursor
, procname
, sizeof(procname
), &off
);
74 if (ret
&& ret
!= -UNW_ENOMEM
) {
79 if (asprintf(&name
, "%s%s", procname
, ret
== -UNW_ENOMEM
? "..." : "") == -1)
81 _mesa_hash_table_insert(symbols_hash
, addr
, (void*)name
);
83 mtx_unlock(&symbols_mutex
);
89 debug_backtrace_capture(struct debug_stack_frame
*backtrace
,
94 unw_context_t context
;
98 pip
.unwind_info
= NULL
;
100 unw_getcontext(&context
);
101 unw_init_local(&cursor
, &context
);
103 while ((start_frame
> 0) && (unw_step(&cursor
) > 0))
106 while ((i
< nr_frames
) && (unw_step(&cursor
) > 0)) {
109 unw_get_reg(&cursor
, UNW_REG_IP
, &ip
);
110 unw_get_proc_info(&cursor
, &pip
);
112 backtrace
[i
].start_ip
= pip
.start_ip
;
113 backtrace
[i
].off
= ip
- pip
.start_ip
;
114 backtrace
[i
].procname
= symbol_name_cached(&cursor
, &pip
);
119 while (i
< nr_frames
) {
120 backtrace
[i
].start_ip
= 0;
126 frame_ip(const struct debug_stack_frame
*frame
)
128 return (void *)(uintptr_t)(frame
->start_ip
+ frame
->off
);
132 frame_info(const struct debug_stack_frame
*frame
, unsigned *offset
)
135 const void *addr
= frame_ip(frame
);
138 if (dladdr(addr
, &dlinfo
) && dlinfo
.dli_fname
&&
140 *offset
= (unsigned)((uintptr_t)addr
- (uintptr_t)dlinfo
.dli_fbase
);
141 return dlinfo
.dli_fname
;
149 debug_backtrace_dump(const struct debug_stack_frame
*backtrace
,
153 const char *filename
;
155 for (i
= 0; i
< nr_frames
; ++i
) {
156 if (!backtrace
[i
].start_ip
)
158 filename
= frame_info(&backtrace
[i
], &offset
);
159 debug_printf("\t%s(+0x%x) (%s+0x%x) [%p]\n", filename
, offset
,
160 backtrace
[i
].procname
, backtrace
[i
].off
,
161 frame_ip(&backtrace
[i
]));
166 debug_backtrace_print(FILE *f
,
167 const struct debug_stack_frame
*backtrace
,
171 const char *filename
;
173 for (i
= 0; i
< nr_frames
; ++i
) {
174 if (!backtrace
[i
].start_ip
)
176 filename
= frame_info(&backtrace
[i
], &offset
);
177 fprintf(f
, "\t%s(+0x%x) (%s+0x%x) [%p]\n", filename
, offset
,
178 backtrace
[i
].procname
, backtrace
[i
].off
,
179 frame_ip(&backtrace
[i
]));
182 #elif defined(ANDROID)
183 /* Not implemented here; see u_debug_stack_android.cpp */
184 #else /* ! HAVE_LIBUNWIND */
186 #if defined(PIPE_OS_WINDOWS)
192 * Capture stack backtrace.
194 * NOTE: The implementation of this function is quite big, but it is important
195 * not to break it down in smaller functions to avoid adding new frames to the
199 debug_backtrace_capture(struct debug_stack_frame
*backtrace
,
200 unsigned start_frame
,
203 const void **frame_pointer
= NULL
;
211 * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
213 * It works reliably both for x86 for x86_64.
215 #if defined(PIPE_OS_WINDOWS)
217 typedef USHORT (WINAPI
*PFNCAPTURESTACKBACKTRACE
)(ULONG
, ULONG
,
219 static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace
= NULL
;
221 if (!pfnCaptureStackBackTrace
) {
222 static HMODULE hModule
= NULL
;
224 hModule
= LoadLibraryA("kernel32");
228 pfnCaptureStackBackTrace
=
229 (PFNCAPTURESTACKBACKTRACE
)GetProcAddress(hModule
,
230 "RtlCaptureStackBackTrace");
233 if (pfnCaptureStackBackTrace
) {
235 * Skip this (debug_backtrace_capture) function's frame.
240 assert(start_frame
+ nr_frames
< 63);
241 i
= pfnCaptureStackBackTrace(start_frame
, nr_frames
,
242 (PVOID
*) &backtrace
->function
, NULL
);
244 /* Pad remaing requested frames with NULL */
245 while (i
< nr_frames
) {
246 backtrace
[i
++].function
= NULL
;
254 #if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 404) || defined(__clang__)
255 #pragma GCC diagnostic push
256 #pragma GCC diagnostic ignored "-Wframe-address"
257 frame_pointer
= ((const void **)__builtin_frame_address(1));
258 #pragma GCC diagnostic pop
259 #elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
261 mov frame_pointer
, ebp
263 frame_pointer
= (const void **)frame_pointer
[0];
265 frame_pointer
= NULL
;
270 const void **next_frame_pointer
;
278 backtrace
[i
++].function
= frame_pointer
[1];
282 next_frame_pointer
= (const void **)frame_pointer
[0];
284 /* Limit the stack walk to avoid referencing undefined memory */
285 if ((uintptr_t)next_frame_pointer
<= (uintptr_t)frame_pointer
||
286 (uintptr_t)next_frame_pointer
> (uintptr_t)frame_pointer
+ 64*1024)
289 frame_pointer
= next_frame_pointer
;
292 (void) frame_pointer
;
296 backtrace
[i
++].function
= NULL
;
303 debug_backtrace_dump(const struct debug_stack_frame
*backtrace
,
308 for (i
= 0; i
< nr_frames
; ++i
) {
309 if (!backtrace
[i
].function
)
311 debug_symbol_print(backtrace
[i
].function
);
317 debug_backtrace_print(FILE *f
,
318 const struct debug_stack_frame
*backtrace
,
323 for (i
= 0; i
< nr_frames
; ++i
) {
325 if (!backtrace
[i
].function
)
327 symbol
= debug_symbol_name_cached(backtrace
[i
].function
);
329 fprintf(f
, "%s\n", symbol
);
333 #endif /* HAVE_LIBUNWIND */