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>
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
]));
197 #else /* ! HAVE_LIBUNWIND */
199 #if defined(PIPE_OS_WINDOWS)
205 * Capture stack backtrace.
207 * NOTE: The implementation of this function is quite big, but it is important
208 * not to break it down in smaller functions to avoid adding new frames to the
212 debug_backtrace_capture(struct debug_stack_frame
*backtrace
,
213 unsigned start_frame
,
216 const void **frame_pointer
= NULL
;
224 * On Windows try obtaining the stack backtrace via CaptureStackBackTrace.
226 * It works reliably both for x86 for x86_64.
228 #if defined(PIPE_OS_WINDOWS)
230 typedef USHORT (WINAPI
*PFNCAPTURESTACKBACKTRACE
)(ULONG
, ULONG
,
232 static PFNCAPTURESTACKBACKTRACE pfnCaptureStackBackTrace
= NULL
;
234 if (!pfnCaptureStackBackTrace
) {
235 static HMODULE hModule
= NULL
;
237 hModule
= LoadLibraryA("kernel32");
241 pfnCaptureStackBackTrace
=
242 (PFNCAPTURESTACKBACKTRACE
)GetProcAddress(hModule
,
243 "RtlCaptureStackBackTrace");
246 if (pfnCaptureStackBackTrace
) {
248 * Skip this (debug_backtrace_capture) function's frame.
253 assert(start_frame
+ nr_frames
< 63);
254 i
= pfnCaptureStackBackTrace(start_frame
, nr_frames
,
255 (PVOID
*) &backtrace
->function
, NULL
);
257 /* Pad remaing requested frames with NULL */
258 while (i
< nr_frames
) {
259 backtrace
[i
++].function
= NULL
;
267 #if defined(PIPE_CC_GCC)
268 frame_pointer
= ((const void **)__builtin_frame_address(1));
269 #elif defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)
271 mov frame_pointer
, ebp
273 frame_pointer
= (const void **)frame_pointer
[0];
275 frame_pointer
= NULL
;
280 const void **next_frame_pointer
;
288 backtrace
[i
++].function
= frame_pointer
[1];
292 next_frame_pointer
= (const void **)frame_pointer
[0];
294 /* Limit the stack walk to avoid referencing undefined memory */
295 if ((uintptr_t)next_frame_pointer
<= (uintptr_t)frame_pointer
||
296 (uintptr_t)next_frame_pointer
> (uintptr_t)frame_pointer
+ 64*1024)
299 frame_pointer
= next_frame_pointer
;
302 (void) frame_pointer
;
306 backtrace
[i
++].function
= NULL
;
313 debug_backtrace_dump(const struct debug_stack_frame
*backtrace
,
318 for (i
= 0; i
< nr_frames
; ++i
) {
319 if (!backtrace
[i
].function
)
321 debug_symbol_print(backtrace
[i
].function
);
327 debug_backtrace_print(FILE *f
,
328 const struct debug_stack_frame
*backtrace
,
333 for (i
= 0; i
< nr_frames
; ++i
) {
335 if (!backtrace
[i
].function
)
337 symbol
= debug_symbol_name_cached(backtrace
[i
].function
);
339 fprintf(f
, "%s\n", symbol
);
343 #endif /* HAVE_LIBUNWIND */