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"
39 #if defined(HAVE_LIBUNWIND)
46 #include "os/os_thread.h"
47 #include "u_hash_table.h"
49 struct util_hash_table
* symbols_hash
;
50 static mtx_t symbols_mutex
= _MTX_INITIALIZER_NP
;
52 static unsigned hash_ptr(void* p
)
54 return (unsigned)(uintptr_t)p
;
57 static int compare_ptr(void* a
, void* b
)
67 /* TODO with some refactoring we might be able to re-use debug_symbol_name_cached()
68 * instead.. otoh if using libunwind I think u_debug_symbol could just be excluded
72 symbol_name_cached(unw_cursor_t
*cursor
, unw_proc_info_t
*pip
)
74 void *addr
= (void *)(uintptr_t)pip
->start_ip
;
77 mtx_lock(&symbols_mutex
);
79 symbols_hash
= util_hash_table_create(hash_ptr
, compare_ptr
);
80 name
= util_hash_table_get(symbols_hash
, addr
);
87 ret
= unw_get_proc_name(cursor
, procname
, sizeof(procname
), &off
);
88 if (ret
&& ret
!= -UNW_ENOMEM
) {
93 if (asprintf(&name
, "%s%s", procname
, ret
== -UNW_ENOMEM
? "..." : "") == -1)
95 util_hash_table_set(symbols_hash
, addr
, (void*)name
);
97 mtx_unlock(&symbols_mutex
);
103 debug_backtrace_capture(struct debug_stack_frame
*backtrace
,
104 unsigned start_frame
,
108 unw_context_t context
;
112 pip
.unwind_info
= NULL
;
114 unw_getcontext(&context
);
115 unw_init_local(&cursor
, &context
);
117 while ((start_frame
> 0) && (unw_step(&cursor
) > 0))
120 while ((i
< nr_frames
) && (unw_step(&cursor
) > 0)) {
123 unw_get_reg(&cursor
, UNW_REG_IP
, &ip
);
124 unw_get_proc_info(&cursor
, &pip
);
126 backtrace
[i
].start_ip
= pip
.start_ip
;
127 backtrace
[i
].off
= ip
- pip
.start_ip
;
128 backtrace
[i
].procname
= symbol_name_cached(&cursor
, &pip
);
133 while (i
< nr_frames
) {
134 backtrace
[i
].start_ip
= 0;
140 frame_ip(const struct debug_stack_frame
*frame
)
142 return (void *)(uintptr_t)(frame
->start_ip
+ frame
->off
);
146 frame_info(const struct debug_stack_frame
*frame
, unsigned *offset
)
149 const void *addr
= frame_ip(frame
);
152 if (dladdr(addr
, &dlinfo
) && dlinfo
.dli_fname
&&
154 *offset
= (unsigned)((uintptr_t)addr
- (uintptr_t)dlinfo
.dli_fbase
);
155 return dlinfo
.dli_fname
;
163 debug_backtrace_dump(const struct debug_stack_frame
*backtrace
,
167 const char *filename
;
169 for (i
= 0; i
< nr_frames
; ++i
) {
170 if (!backtrace
[i
].start_ip
)
172 filename
= frame_info(&backtrace
[i
], &offset
);
173 debug_printf("\t%s(+0x%x) (%s+0x%x) [%p]\n", filename
, offset
,
174 backtrace
[i
].procname
, backtrace
[i
].off
,
175 frame_ip(&backtrace
[i
]));
180 debug_backtrace_print(FILE *f
,
181 const struct debug_stack_frame
*backtrace
,
185 const char *filename
;
187 for (i
= 0; i
< nr_frames
; ++i
) {
188 if (!backtrace
[i
].start_ip
)
190 filename
= frame_info(&backtrace
[i
], &offset
);
191 fprintf(f
, "\t%s(+0x%x) (%s+0x%x) [%p]\n", filename
, offset
,
192 backtrace
[i
].procname
, backtrace
[i
].off
,
193 frame_ip(&backtrace
[i
]));
196 #elif defined(ANDROID)
197 /* Not implemented here; see u_debug_stack_android.cpp */
198 #else /* ! HAVE_LIBUNWIND */
200 #if defined(PIPE_OS_WINDOWS)
206 * Capture stack backtrace.
208 * NOTE: The implementation of this function is quite big, but it is important
209 * not to break it down in smaller functions to avoid adding new frames to the
213 debug_backtrace_capture(struct debug_stack_frame
*backtrace
,
214 unsigned start_frame
,
217 const void **frame_pointer
= NULL
;
225 * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
227 * It works reliably both for x86 for x86_64.
229 #if defined(PIPE_OS_WINDOWS)
231 typedef USHORT (WINAPI
*PFNCAPTURESTACKBACKTRACE
)(ULONG
, ULONG
,
233 static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace
= NULL
;
235 if (!pfnCaptureStackBackTrace
) {
236 static HMODULE hModule
= NULL
;
238 hModule
= LoadLibraryA("kernel32");
242 pfnCaptureStackBackTrace
=
243 (PFNCAPTURESTACKBACKTRACE
)GetProcAddress(hModule
,
244 "RtlCaptureStackBackTrace");
247 if (pfnCaptureStackBackTrace
) {
249 * Skip this (debug_backtrace_capture) function's frame.
254 assert(start_frame
+ nr_frames
< 63);
255 i
= pfnCaptureStackBackTrace(start_frame
, nr_frames
,
256 (PVOID
*) &backtrace
->function
, NULL
);
258 /* Pad remaing requested frames with NULL */
259 while (i
< nr_frames
) {
260 backtrace
[i
++].function
= NULL
;
268 #if defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION > 404) || defined(__clang__)
269 #pragma GCC diagnostic push
270 #pragma GCC diagnostic ignored "-Wframe-address"
271 frame_pointer
= ((const void **)__builtin_frame_address(1));
272 #pragma GCC diagnostic pop
273 #elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
275 mov frame_pointer
, ebp
277 frame_pointer
= (const void **)frame_pointer
[0];
279 frame_pointer
= NULL
;
284 const void **next_frame_pointer
;
292 backtrace
[i
++].function
= frame_pointer
[1];
296 next_frame_pointer
= (const void **)frame_pointer
[0];
298 /* Limit the stack walk to avoid referencing undefined memory */
299 if ((uintptr_t)next_frame_pointer
<= (uintptr_t)frame_pointer
||
300 (uintptr_t)next_frame_pointer
> (uintptr_t)frame_pointer
+ 64*1024)
303 frame_pointer
= next_frame_pointer
;
306 (void) frame_pointer
;
310 backtrace
[i
++].function
= NULL
;
317 debug_backtrace_dump(const struct debug_stack_frame
*backtrace
,
322 for (i
= 0; i
< nr_frames
; ++i
) {
323 if (!backtrace
[i
].function
)
325 debug_symbol_print(backtrace
[i
].function
);
331 debug_backtrace_print(FILE *f
,
332 const struct debug_stack_frame
*backtrace
,
337 for (i
= 0; i
< nr_frames
; ++i
) {
339 if (!backtrace
[i
].function
)
341 symbol
= debug_symbol_name_cached(backtrace
[i
].function
);
343 fprintf(f
, "%s\n", symbol
);
347 #endif /* HAVE_LIBUNWIND */