Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : /*
4 : : stackwalk.c
5 : : utilities for walking the stack and looking up information about code addresses
6 : : */
7 : : #include <inttypes.h>
8 : : #include "julia.h"
9 : : #include "julia_internal.h"
10 : : #include "threading.h"
11 : : #include "julia_assert.h"
12 : :
13 : : // define `jl_unw_get` as a macro, since (like setjmp)
14 : : // returning from the callee function will invalidate the context
15 : : #ifdef _OS_WINDOWS_
16 : : uv_mutex_t jl_in_stackwalk;
17 : : #define jl_unw_get(context) (RtlCaptureContext(context), 0)
18 : : #elif !defined(JL_DISABLE_LIBUNWIND)
19 : : #define jl_unw_get(context) unw_getcontext(context)
20 : : #else
21 : : int jl_unw_get(void *context) { return -1; }
22 : : #endif
23 : :
24 : : #ifdef __cplusplus
25 : : extern "C" {
26 : : #endif
27 : :
28 : : static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context) JL_NOTSAFEPOINT;
29 : : static int jl_unw_step(bt_cursor_t *cursor, int from_signal_handler, uintptr_t *ip, uintptr_t *sp) JL_NOTSAFEPOINT;
30 : :
31 : 2925970 : static jl_gcframe_t *is_enter_interpreter_frame(jl_gcframe_t **ppgcstack, uintptr_t sp) JL_NOTSAFEPOINT
32 : : {
33 : 2925970 : jl_gcframe_t *pgcstack = *ppgcstack;
34 [ + + ]: 4983420 : while (pgcstack != NULL) {
35 : 4530330 : jl_gcframe_t *prev = pgcstack->prev;
36 [ + + ]: 4530330 : if (pgcstack->nroots & 2) { // tagged frame
37 : 2472880 : uintptr_t frame_fp = ((uintptr_t*)pgcstack)[-1];
38 [ + - ]: 2472880 : if (frame_fp != 0) { // check that frame was fully initialized
39 [ + + ]: 2472880 : if (frame_fp >= sp)
40 : 2464100 : break; // stack grows down, so frame pointer is monotonically increasing
41 : 8773 : *ppgcstack = prev;
42 : 8773 : return pgcstack;
43 : : }
44 : : }
45 : 2057450 : *ppgcstack = pgcstack = prev;
46 : : }
47 : 2917200 : return NULL;
48 : : }
49 : :
50 : :
51 : : // Record backtrace entries into bt_data by stepping cursor with jl_unw_step
52 : : // until the outermost frame is encountered or the buffer bt_data is (close to)
53 : : // full. Returned instruction pointers are adjusted to point to the address of
54 : : // the call instruction. The first `skip` frames are not included in `bt_data`.
55 : : //
56 : : // `maxsize` is the size of the buffer `bt_data` (and `sp` if non-NULL). It
57 : : // must be at least `JL_BT_MAX_ENTRY_SIZE + 1` to accommodate extended backtrace
58 : : // entries. If `sp != NULL`, the stack pointer corresponding `bt_data[i]` is
59 : : // stored in `sp[i]`.
60 : : //
61 : : // `*ppgcstack` should be given if you want to record extended backtrace
62 : : // entries in `bt_data` for each julia interpreter frame.
63 : : //
64 : : // Flag `from_signal_handler==1` should be set if the cursor was obtained by
65 : : // asynchronously interrupting the code.
66 : : //
67 : : // jl_unw_stepn will return 1 if there are more frames to come. The number of
68 : : // elements written to bt_data (and sp if non-NULL) are returned in bt_size.
69 : 9090 : static int jl_unw_stepn(bt_cursor_t *cursor, jl_bt_element_t *bt_data, size_t *bt_size,
70 : : uintptr_t *sp, size_t maxsize, int skip, jl_gcframe_t **ppgcstack,
71 : : int from_signal_handler) JL_NOTSAFEPOINT
72 : : {
73 : 9090 : volatile size_t n = 0;
74 : 9090 : volatile int need_more_space = 0;
75 : 9090 : uintptr_t return_ip = 0;
76 : 9090 : uintptr_t thesp = 0;
77 : : #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_)
78 : : uv_mutex_lock(&jl_in_stackwalk);
79 : : if (!from_signal_handler) {
80 : : // Workaround 32-bit windows bug missing top frame
81 : : // See for example https://bugs.chromium.org/p/crashpad/issues/detail?id=53
82 : : skip--;
83 : : }
84 : : #endif
85 : : #if !defined(_OS_WINDOWS_)
86 : 9090 : jl_jmp_buf *old_buf = jl_get_safe_restore();
87 : : jl_jmp_buf buf;
88 : 9090 : jl_set_safe_restore(&buf);
89 [ + - ]: 9090 : if (!jl_setjmp(buf, 0)) {
90 : : #endif
91 : 9090 : int have_more_frames = 1;
92 [ + + ]: 2953290 : while (have_more_frames) {
93 [ - + ]: 2944200 : if (n + JL_BT_MAX_ENTRY_SIZE + 1 > maxsize) {
94 : : // Postpone advancing the cursor: may need more space
95 : 0 : need_more_space = 1;
96 : 0 : break;
97 : : }
98 : 2944200 : uintptr_t oldsp = thesp;
99 : 2944200 : have_more_frames = jl_unw_step(cursor, from_signal_handler, &return_ip, &thesp);
100 [ - + - - ]: 2944200 : if (oldsp >= thesp && !jl_running_under_rr(0)) {
101 : : // The stack pointer is clearly bad, as it must grow downwards.
102 : : // But sometimes the external unwinder doesn't check that.
103 : 0 : have_more_frames = 0;
104 : : }
105 [ - + ]: 2944200 : if (return_ip == 0) {
106 : : // The return address is clearly wrong, and while the unwinder
107 : : // might try to continue (by popping another stack frame), that
108 : : // likely won't work well, and it'll confuse the stack frame
109 : : // separator detection logic (double-NULL).
110 : 0 : have_more_frames = 0;
111 : : }
112 [ + + ]: 2944200 : if (skip > 0) {
113 : 27000 : skip--;
114 : 27000 : from_signal_handler = 0;
115 : 27000 : continue;
116 : : }
117 : : // For the purposes of looking up debug info for functions, we want
118 : : // to harvest addresses for the *call* instruction `call_ip` during
119 : : // stack walking. However, this information isn't directly
120 : : // available. Instead, the stack walk discovers the address
121 : : // `return_ip` which would be *returned to* as the stack is
122 : : // unwound.
123 : : //
124 : : // To infer `call_ip` in full generality we need to understand each
125 : : // platform ABI instruction pointer encoding and calling
126 : : // conventions, noting that the latter may vary per stack frame.
127 : : //
128 : : // See also:
129 : : // * The LLVM unwinder functions step() and setInfoBasedOnIPRegister()
130 : : // https://github.com/llvm/llvm-project/blob/master/libunwind/src/UnwindCursor.hpp
131 : : // * The way that libunwind handles it in `unw_get_proc_name`:
132 : : // https://lists.nongnu.org/archive/html/libunwind-devel/2014-06/msg00025.html
133 : 2917200 : uintptr_t call_ip = return_ip;
134 : : // ARM instruction pointer encoding uses the low bit as a flag for
135 : : // thumb mode, which must be cleared before further use. (Note not
136 : : // needed for ARM AArch64.) See
137 : : // https://github.com/libunwind/libunwind/pull/131
138 : : #ifdef _CPU_ARM_
139 : : call_ip &= ~(uintptr_t)0x1;
140 : : #endif
141 : : // Now there's two main cases to adjust for:
142 : : // * Normal stack frames where compilers emit a `call` instruction
143 : : // which we can get from the return address via `call_ip = return_ip - 1`.
144 : : // * Code which was interrupted asynchronously (eg, via a signal)
145 : : // is expected to have `call_ip == return_ip`.
146 [ + + ]: 2917200 : if (!from_signal_handler)
147 : 2917110 : call_ip -= 1; // normal frame
148 : 2917200 : from_signal_handler = 0;
149 [ + - - + ]: 2917200 : if (call_ip == JL_BT_NON_PTR_ENTRY || call_ip == 0) {
150 : : // Never leave special marker in the bt data as it can corrupt the GC.
151 : 0 : have_more_frames = 0;
152 : 0 : call_ip = 0;
153 : : }
154 : 2917200 : jl_bt_element_t *bt_entry = bt_data + n;
155 : : jl_gcframe_t *pgcstack;
156 [ + + ]: 2917200 : if ((pgcstack = is_enter_interpreter_frame(ppgcstack, thesp))) {
157 : 8773 : size_t add = jl_capture_interp_frame(bt_entry, (void*)((char*)pgcstack - sizeof(void*)), maxsize - n);
158 : 8773 : n += add;
159 : 8773 : bt_entry += add;
160 [ - + ]: 8773 : while ((pgcstack = is_enter_interpreter_frame(ppgcstack, thesp))) {
161 : : // If the compiler got inlining-happy, or the user tried to
162 : : // push multiple frames (or the unwinder got very
163 : : // confused), we could end up here. That doesn't happen
164 : : // now, so just ignore this possibility. If we want this,
165 : : // we can work on adding support for it later.
166 : : }
167 : : }
168 : 2917200 : bt_entry->uintptr = call_ip;
169 [ - + ]: 2917200 : if (sp)
170 : 0 : sp[n] = thesp;
171 : 2917200 : n++;
172 : : }
173 : : // NOTE: if we have some pgcstack entries remaining (because the
174 : : // unwinder failed and returned !have_more_frames early), we could
175 : : // consider still appending those frames here
176 : : #if !defined(_OS_WINDOWS_)
177 : : }
178 : : else {
179 : : // The unwinding fails likely because a invalid memory read.
180 : : // Back off one frame since it is likely invalid.
181 : : // This seems to be good enough on x86 to make the LLVM debug info
182 : : // reader happy.
183 [ # # ]: 0 : if (n > 0) n -= 1;
184 : : }
185 : 9090 : jl_set_safe_restore(old_buf);
186 : : #endif
187 : : #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_)
188 : : uv_mutex_unlock(&jl_in_stackwalk);
189 : : #endif
190 : 9090 : *bt_size = n;
191 : 9090 : return need_more_space;
192 : : }
193 : :
194 : 90 : NOINLINE size_t rec_backtrace_ctx(jl_bt_element_t *bt_data, size_t maxsize,
195 : : bt_context_t *context, jl_gcframe_t *pgcstack) JL_NOTSAFEPOINT
196 : : {
197 : : bt_cursor_t cursor;
198 [ - + ]: 90 : if (!jl_unw_init(&cursor, context))
199 : 0 : return 0;
200 : 90 : size_t bt_size = 0;
201 : 90 : jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, 0, &pgcstack, 1);
202 : 90 : return bt_size;
203 : : }
204 : :
205 : : // Record backtrace into buffer `bt_data`, using a maximum of `maxsize`
206 : : // elements, and returning the number of elements written.
207 : : //
208 : : // The first `skip` frames are omitted, in addition to omitting the frame from
209 : : // `rec_backtrace` itself.
210 : 9000 : NOINLINE size_t rec_backtrace(jl_bt_element_t *bt_data, size_t maxsize, int skip)
211 : : {
212 : : bt_context_t context;
213 : 9000 : memset(&context, 0, sizeof(context));
214 : 9000 : int r = jl_unw_get(&context);
215 [ - + ]: 9000 : if (r < 0)
216 : 0 : return 0;
217 : 9000 : jl_gcframe_t *pgcstack = jl_pgcstack;
218 : : bt_cursor_t cursor;
219 [ - + ]: 9000 : if (!jl_unw_init(&cursor, &context))
220 : 0 : return 0;
221 : 9000 : size_t bt_size = 0;
222 : 9000 : jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, skip + 1, &pgcstack, 0);
223 : 9000 : return bt_size;
224 : : }
225 : :
226 : : static jl_value_t *array_ptr_void_type JL_ALWAYS_LEAFTYPE = NULL;
227 : : // Return backtrace information as an svec of (bt1, bt2, [sp])
228 : : //
229 : : // The stack pointers `sp` are returned only when `returnsp` evaluates to true.
230 : : // bt1 contains raw backtrace entries, while bt2 exists to root any julia
231 : : // objects associated with the entries in bt1.
232 : : //
233 : : // The frame from jl_backtrace_from_here will be skipped; set `skip > 0` to
234 : : // skip additional native frames from the start of the backtrace.
235 : 0 : JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip)
236 : : {
237 : 0 : jl_array_t *ip = NULL;
238 : 0 : jl_array_t *sp = NULL;
239 : 0 : jl_array_t *bt2 = NULL;
240 : 0 : JL_GC_PUSH3(&ip, &sp, &bt2);
241 [ # # ]: 0 : if (array_ptr_void_type == NULL) {
242 : 0 : array_ptr_void_type = jl_apply_type2((jl_value_t*)jl_array_type, (jl_value_t*)jl_voidpointer_type, jl_box_long(1));
243 : : }
244 : 0 : ip = jl_alloc_array_1d(array_ptr_void_type, 0);
245 [ # # ]: 0 : sp = returnsp ? jl_alloc_array_1d(array_ptr_void_type, 0) : NULL;
246 : 0 : bt2 = jl_alloc_array_1d(jl_array_any_type, 0);
247 : 0 : const size_t maxincr = 1000;
248 : : bt_context_t context;
249 : : bt_cursor_t cursor;
250 : 0 : memset(&context, 0, sizeof(context));
251 : 0 : int r = jl_unw_get(&context);
252 : 0 : jl_gcframe_t *pgcstack = jl_pgcstack;
253 [ # # # # ]: 0 : if (r == 0 && jl_unw_init(&cursor, &context)) {
254 : : // Skip frame for jl_backtrace_from_here itself
255 : 0 : skip += 1;
256 : 0 : size_t offset = 0;
257 : 0 : int have_more_frames = 1;
258 [ # # ]: 0 : while (have_more_frames) {
259 : 0 : jl_array_grow_end(ip, maxincr);
260 : 0 : uintptr_t *sp_ptr = NULL;
261 [ # # ]: 0 : if (returnsp) {
262 : 0 : jl_array_grow_end(sp, maxincr);
263 : 0 : sp_ptr = (uintptr_t*)jl_array_data(sp) + offset;
264 : : }
265 : 0 : size_t size_incr = 0;
266 : 0 : have_more_frames = jl_unw_stepn(&cursor, (jl_bt_element_t*)jl_array_data(ip) + offset,
267 : : &size_incr, sp_ptr, maxincr, skip, &pgcstack, 0);
268 : 0 : skip = 0;
269 : 0 : offset += size_incr;
270 : : }
271 : 0 : jl_array_del_end(ip, jl_array_len(ip) - offset);
272 [ # # ]: 0 : if (returnsp)
273 : 0 : jl_array_del_end(sp, jl_array_len(sp) - offset);
274 : :
275 : 0 : size_t n = 0;
276 : 0 : jl_bt_element_t *bt_data = (jl_bt_element_t*)jl_array_data(ip);
277 [ # # ]: 0 : while (n < jl_array_len(ip)) {
278 : 0 : jl_bt_element_t *bt_entry = bt_data + n;
279 [ # # ]: 0 : if (!jl_bt_is_native(bt_entry)) {
280 : 0 : size_t njlvals = jl_bt_num_jlvals(bt_entry);
281 [ # # ]: 0 : for (size_t j = 0; j < njlvals; j++) {
282 : 0 : jl_value_t *v = jl_bt_entry_jlvalue(bt_entry, j);
283 : : JL_GC_PROMISE_ROOTED(v);
284 : 0 : jl_array_ptr_1d_push(bt2, v);
285 : : }
286 : : }
287 : 0 : n += jl_bt_entry_size(bt_entry);
288 : : }
289 : : }
290 [ # # ]: 0 : jl_value_t *bt = returnsp ? (jl_value_t*)jl_svec(3, ip, bt2, sp) : (jl_value_t*)jl_svec(2, ip, bt2);
291 : 0 : JL_GC_POP();
292 : 0 : return bt;
293 : : }
294 : :
295 : 4 : static void decode_backtrace(jl_bt_element_t *bt_data, size_t bt_size,
296 : : jl_array_t **btout JL_REQUIRE_ROOTED_SLOT,
297 : : jl_array_t **bt2out JL_REQUIRE_ROOTED_SLOT)
298 : : {
299 : : jl_array_t *bt, *bt2;
300 [ + + ]: 4 : if (array_ptr_void_type == NULL) {
301 : 2 : array_ptr_void_type = jl_apply_type2((jl_value_t*)jl_array_type, (jl_value_t*)jl_voidpointer_type, jl_box_long(1));
302 : : }
303 : 4 : bt = *btout = jl_alloc_array_1d(array_ptr_void_type, bt_size);
304 : : static_assert(sizeof(jl_bt_element_t) == sizeof(void*),
305 : : "jl_bt_element_t is presented as Ptr{Cvoid} on julia side");
306 : 4 : memcpy(bt->data, bt_data, bt_size * sizeof(jl_bt_element_t));
307 : 4 : bt2 = *bt2out = jl_alloc_array_1d(jl_array_any_type, 0);
308 : : // Scan the backtrace buffer for any gc-managed values
309 [ + + ]: 174 : for (size_t i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
310 : 170 : jl_bt_element_t* bt_entry = bt_data + i;
311 [ + + ]: 170 : if (jl_bt_is_native(bt_entry))
312 : 166 : continue;
313 : 4 : size_t njlvals = jl_bt_num_jlvals(bt_entry);
314 [ + + ]: 12 : for (size_t j = 0; j < njlvals; j++) {
315 : 8 : jl_value_t *v = jl_bt_entry_jlvalue(bt_entry, j);
316 : : JL_GC_PROMISE_ROOTED(v);
317 : 8 : jl_array_ptr_1d_push(bt2, v);
318 : : }
319 : : }
320 : 4 : }
321 : :
322 : 0 : JL_DLLEXPORT jl_value_t *jl_get_backtrace(void)
323 : : {
324 : 0 : jl_excstack_t *s = jl_current_task->excstack;
325 : 0 : jl_bt_element_t *bt_data = NULL;
326 : 0 : size_t bt_size = 0;
327 [ # # # # ]: 0 : if (s && s->top) {
328 : 0 : bt_data = jl_excstack_bt_data(s, s->top);
329 : 0 : bt_size = jl_excstack_bt_size(s, s->top);
330 : : }
331 : 0 : jl_array_t *bt = NULL, *bt2 = NULL;
332 : 0 : JL_GC_PUSH2(&bt, &bt2);
333 : 0 : decode_backtrace(bt_data, bt_size, &bt, &bt2);
334 : 0 : jl_svec_t *pair = jl_svec2(bt, bt2);
335 : 0 : JL_GC_POP();
336 : 0 : return (jl_value_t*)pair;
337 : : }
338 : :
339 : : // Return data from the exception stack for `task` as an array of Any, starting
340 : : // with the top of the stack and returning up to `max_entries`. If requested by
341 : : // setting the `include_bt` flag, backtrace data in bt,bt2 format is
342 : : // interleaved.
343 : 4 : JL_DLLEXPORT jl_value_t *jl_get_excstack(jl_task_t* task, int include_bt, int max_entries)
344 : : {
345 [ - + ]: 4 : JL_TYPECHK(current_exceptions, task, (jl_value_t*)task);
346 : 4 : jl_task_t *ct = jl_current_task;
347 [ - + - - ]: 4 : if (task != ct && jl_atomic_load_relaxed(&task->_state) == JL_TASK_STATE_RUNNABLE) {
348 : 0 : jl_error("Inspecting the exception stack of a task which might "
349 : : "be running concurrently isn't allowed.");
350 : : }
351 : 4 : jl_array_t *stack = NULL;
352 : 4 : jl_array_t *bt = NULL;
353 : 4 : jl_array_t *bt2 = NULL;
354 : 4 : JL_GC_PUSH3(&stack, &bt, &bt2);
355 : 4 : stack = jl_alloc_array_1d(jl_array_any_type, 0);
356 : 4 : jl_excstack_t *excstack = task->excstack;
357 [ + - ]: 4 : size_t itr = excstack ? excstack->top : 0;
358 : 4 : int i = 0;
359 [ + + + - ]: 8 : while (itr > 0 && i < max_entries) {
360 : 4 : jl_array_ptr_1d_push(stack, jl_excstack_exception(excstack, itr));
361 [ + - ]: 4 : if (include_bt) {
362 : 4 : decode_backtrace(jl_excstack_bt_data(excstack, itr),
363 : : jl_excstack_bt_size(excstack, itr),
364 : : &bt, &bt2);
365 : 4 : jl_array_ptr_1d_push(stack, (jl_value_t*)bt);
366 : 4 : jl_array_ptr_1d_push(stack, (jl_value_t*)bt2);
367 : : }
368 : 4 : itr = jl_excstack_next(excstack, itr);
369 : 4 : i++;
370 : : }
371 : 4 : JL_GC_POP();
372 : 4 : return (jl_value_t*)stack;
373 : : }
374 : :
375 : : #if defined(_OS_WINDOWS_)
376 : : // XXX: these caches should be per-thread
377 : : #ifdef _CPU_X86_64_
378 : : static UNWIND_HISTORY_TABLE HistoryTable;
379 : : #else
380 : : static struct {
381 : : DWORD64 dwAddr;
382 : : DWORD64 ImageBase;
383 : : } HistoryTable;
384 : : #endif
385 : : static PVOID CALLBACK JuliaFunctionTableAccess64(
386 : : _In_ HANDLE hProcess,
387 : : _In_ DWORD64 AddrBase)
388 : : {
389 : : //jl_printf(JL_STDOUT, "lookup %d\n", AddrBase);
390 : : #ifdef _CPU_X86_64_
391 : : DWORD64 ImageBase;
392 : : PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(AddrBase, &ImageBase, &HistoryTable);
393 : : if (fn)
394 : : return fn;
395 : : uv_mutex_lock(&jl_in_stackwalk);
396 : : PVOID ftable = SymFunctionTableAccess64(hProcess, AddrBase);
397 : : uv_mutex_unlock(&jl_in_stackwalk);
398 : : return ftable;
399 : : #else
400 : : return SymFunctionTableAccess64(hProcess, AddrBase);
401 : : #endif
402 : : }
403 : : static DWORD64 WINAPI JuliaGetModuleBase64(
404 : : _In_ HANDLE hProcess,
405 : : _In_ DWORD64 dwAddr)
406 : : {
407 : : //jl_printf(JL_STDOUT, "lookup base %d\n", dwAddr);
408 : : #ifdef _CPU_X86_64_
409 : : DWORD64 ImageBase;
410 : : PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(dwAddr, &ImageBase, &HistoryTable);
411 : : if (fn)
412 : : return ImageBase;
413 : : uv_mutex_lock(&jl_in_stackwalk);
414 : : DWORD64 fbase = SymGetModuleBase64(hProcess, dwAddr);
415 : : uv_mutex_unlock(&jl_in_stackwalk);
416 : : return fbase;
417 : : #else
418 : : if (dwAddr == HistoryTable.dwAddr)
419 : : return HistoryTable.ImageBase;
420 : : DWORD64 ImageBase = jl_getUnwindInfo(dwAddr);
421 : : if (ImageBase) {
422 : : HistoryTable.dwAddr = dwAddr;
423 : : HistoryTable.ImageBase = ImageBase;
424 : : return ImageBase;
425 : : }
426 : : return SymGetModuleBase64(hProcess, dwAddr);
427 : : #endif
428 : : }
429 : :
430 : : // Might be called from unmanaged thread.
431 : : volatile int needsSymRefreshModuleList;
432 : : BOOL (WINAPI *hSymRefreshModuleList)(HANDLE);
433 : :
434 : : JL_DLLEXPORT void jl_refresh_dbg_module_list(void)
435 : : {
436 : : if (needsSymRefreshModuleList && hSymRefreshModuleList != NULL) {
437 : : hSymRefreshModuleList(GetCurrentProcess());
438 : : needsSymRefreshModuleList = 0;
439 : : }
440 : : }
441 : : static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *Context)
442 : : {
443 : : int result;
444 : : uv_mutex_lock(&jl_in_stackwalk);
445 : : jl_refresh_dbg_module_list();
446 : : #if !defined(_CPU_X86_64_)
447 : : memset(&cursor->stackframe, 0, sizeof(cursor->stackframe));
448 : : cursor->stackframe.AddrPC.Offset = Context->Eip;
449 : : cursor->stackframe.AddrStack.Offset = Context->Esp;
450 : : cursor->stackframe.AddrFrame.Offset = Context->Ebp;
451 : : cursor->stackframe.AddrPC.Mode = AddrModeFlat;
452 : : cursor->stackframe.AddrStack.Mode = AddrModeFlat;
453 : : cursor->stackframe.AddrFrame.Mode = AddrModeFlat;
454 : : cursor->context = *Context;
455 : : result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread,
456 : : &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64,
457 : : JuliaGetModuleBase64, NULL);
458 : : #else
459 : : *cursor = *Context;
460 : : result = 1;
461 : : #endif
462 : : uv_mutex_unlock(&jl_in_stackwalk);
463 : : return result;
464 : : }
465 : :
466 : : static int readable_pointer(LPCVOID pointer)
467 : : {
468 : : // Check whether the pointer is valid and executable before dereferencing
469 : : // to avoid segfault while recording. See #10638.
470 : : MEMORY_BASIC_INFORMATION mInfo;
471 : : if (VirtualQuery(pointer, &mInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0)
472 : : return 0;
473 : : DWORD X = mInfo.AllocationProtect;
474 : : if (!((X&PAGE_READONLY) || (X&PAGE_READWRITE) || (X&PAGE_WRITECOPY) || (X&PAGE_EXECUTE_READ)) ||
475 : : (X&PAGE_GUARD) || (X&PAGE_NOACCESS))
476 : : return 0;
477 : : return 1;
478 : : }
479 : :
480 : : static int jl_unw_step(bt_cursor_t *cursor, int from_signal_handler, uintptr_t *ip, uintptr_t *sp)
481 : : {
482 : : // Might be called from unmanaged thread.
483 : : #ifndef _CPU_X86_64_
484 : : *ip = (uintptr_t)cursor->stackframe.AddrPC.Offset;
485 : : *sp = (uintptr_t)cursor->stackframe.AddrStack.Offset;
486 : : if (*ip == 0) {
487 : : if (!readable_pointer((LPCVOID)*sp))
488 : : return 0;
489 : : cursor->stackframe.AddrPC.Offset = *(DWORD32*)*sp; // POP EIP (aka RET)
490 : : cursor->stackframe.AddrStack.Offset += sizeof(void*);
491 : : return cursor->stackframe.AddrPC.Offset != 0;
492 : : }
493 : :
494 : : BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread,
495 : : &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL);
496 : : return result;
497 : : #else
498 : : *ip = (uintptr_t)cursor->Rip;
499 : : *sp = (uintptr_t)cursor->Rsp;
500 : : if (*ip == 0 && from_signal_handler) {
501 : : if (!readable_pointer((LPCVOID)*sp))
502 : : return 0;
503 : : cursor->Rip = *(DWORD64*)*sp; // POP RIP (aka RET)
504 : : cursor->Rsp += sizeof(void*);
505 : : return cursor->Rip != 0;
506 : : }
507 : :
508 : : DWORD64 ImageBase = JuliaGetModuleBase64(GetCurrentProcess(), cursor->Rip - !from_signal_handler);
509 : : if (!ImageBase)
510 : : return 0;
511 : :
512 : : PRUNTIME_FUNCTION FunctionEntry = (PRUNTIME_FUNCTION)JuliaFunctionTableAccess64(
513 : : GetCurrentProcess(), cursor->Rip - !from_signal_handler);
514 : : if (!FunctionEntry) {
515 : : // Not code or bad unwind?
516 : : return 0;
517 : : }
518 : : else {
519 : : PVOID HandlerData;
520 : : DWORD64 EstablisherFrame;
521 : : (void)RtlVirtualUnwind(
522 : : 0 /*UNW_FLAG_NHANDLER*/,
523 : : ImageBase,
524 : : cursor->Rip,
525 : : FunctionEntry,
526 : : cursor,
527 : : &HandlerData,
528 : : &EstablisherFrame,
529 : : NULL);
530 : : }
531 : : return cursor->Rip != 0;
532 : : #endif
533 : : }
534 : :
535 : : #elif !defined(JL_DISABLE_LIBUNWIND)
536 : : // stacktrace using libunwind
537 : :
538 : 9090 : static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context)
539 : : {
540 : 9090 : return unw_init_local(cursor, context) == 0;
541 : : }
542 : :
543 : 2944200 : static int jl_unw_step(bt_cursor_t *cursor, int from_signal_handler, uintptr_t *ip, uintptr_t *sp)
544 : : {
545 : : (void)from_signal_handler; // libunwind also tracks this
546 : : unw_word_t reg;
547 [ - + ]: 2944200 : if (unw_get_reg(cursor, UNW_REG_IP, ®) < 0)
548 : 0 : return 0;
549 : 2944200 : *ip = reg;
550 [ - + ]: 2944200 : if (unw_get_reg(cursor, UNW_REG_SP, ®) < 0)
551 : 0 : return 0;
552 : 2944200 : *sp = reg;
553 : 2944200 : return unw_step(cursor) > 0;
554 : : }
555 : :
556 : : #ifdef LLVMLIBUNWIND
557 : : NOINLINE size_t rec_backtrace_ctx_dwarf(jl_bt_element_t *bt_data, size_t maxsize,
558 : : bt_context_t *context, jl_gcframe_t *pgcstack)
559 : : {
560 : : size_t bt_size = 0;
561 : : bt_cursor_t cursor;
562 : : if (unw_init_local_dwarf(&cursor, context) != UNW_ESUCCESS)
563 : : return 0;
564 : : jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, 0, &pgcstack, 1);
565 : : return bt_size;
566 : : }
567 : : #endif
568 : :
569 : : #else
570 : : // stacktraces are disabled
571 : : static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context)
572 : : {
573 : : return 0;
574 : : }
575 : :
576 : : static int jl_unw_step(bt_cursor_t *cursor, int from_signal_handler, uintptr_t *ip, uintptr_t *sp)
577 : : {
578 : : return 0;
579 : : }
580 : : #endif
581 : :
582 : 366 : JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC)
583 : : {
584 : 366 : jl_task_t *ct = jl_current_task;
585 : 366 : jl_frame_t *frames = NULL;
586 : 366 : int8_t gc_state = jl_gc_safe_enter(ct->ptls);
587 : 366 : int n = jl_getFunctionInfo(&frames, (uintptr_t)ip, skipC, 0);
588 : 366 : jl_gc_safe_leave(ct->ptls, gc_state);
589 : 366 : jl_value_t *rs = (jl_value_t*)jl_alloc_svec(n);
590 : 366 : JL_GC_PUSH1(&rs);
591 [ + + ]: 819 : for (int i = 0; i < n; i++) {
592 : 453 : jl_frame_t frame = frames[i];
593 : 453 : jl_value_t *r = (jl_value_t*)jl_alloc_svec(6);
594 : 453 : jl_svecset(rs, i, r);
595 [ + + ]: 453 : if (frame.func_name)
596 : 429 : jl_svecset(r, 0, jl_symbol(frame.func_name));
597 : : else
598 : 24 : jl_svecset(r, 0, jl_empty_sym);
599 : 453 : free(frame.func_name);
600 [ + + ]: 453 : if (frame.file_name)
601 : 430 : jl_svecset(r, 1, jl_symbol(frame.file_name));
602 : : else
603 : 23 : jl_svecset(r, 1, jl_empty_sym);
604 : 453 : free(frame.file_name);
605 : 453 : jl_svecset(r, 2, jl_box_long(frame.line));
606 [ + + ]: 453 : jl_svecset(r, 3, frame.linfo != NULL ? (jl_value_t*)frame.linfo : jl_nothing);
607 : 453 : jl_svecset(r, 4, jl_box_bool(frame.fromC));
608 : 453 : jl_svecset(r, 5, jl_box_bool(frame.inlined));
609 : : }
610 : 366 : free(frames);
611 : 366 : JL_GC_POP();
612 : 366 : return rs;
613 : : }
614 : :
615 : 0 : static void jl_safe_print_codeloc(const char* func_name, const char* file_name,
616 : : int line, int inlined) JL_NOTSAFEPOINT
617 : : {
618 [ # # ]: 0 : const char *inlined_str = inlined ? " [inlined]" : "";
619 [ # # ]: 0 : if (line != -1) {
620 : 0 : jl_safe_printf("%s at %s:%d%s\n", func_name, file_name, line, inlined_str);
621 : : }
622 : : else {
623 : 0 : jl_safe_printf("%s at %s (unknown line)%s\n", func_name, file_name, inlined_str);
624 : : }
625 : 0 : }
626 : :
627 : : // Print function, file and line containing native instruction pointer `ip` by
628 : : // looking up debug info. Prints multiple such frames when `ip` points to
629 : : // inlined code.
630 : 0 : void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT
631 : : {
632 : : // This function is not allowed to reference any TLS variables since
633 : : // it can be called from an unmanaged thread on OSX.
634 : : // it means calling getFunctionInfo with noInline = 1
635 : 0 : jl_frame_t *frames = NULL;
636 : 0 : int n = jl_getFunctionInfo(&frames, ip, 0, 0);
637 : : int i;
638 : :
639 [ # # ]: 0 : for (i = 0; i < n; i++) {
640 : 0 : jl_frame_t frame = frames[i];
641 [ # # ]: 0 : if (!frame.func_name) {
642 : 0 : jl_safe_printf("unknown function (ip: %p)\n", (void*)ip);
643 : : }
644 : : else {
645 : 0 : jl_safe_print_codeloc(frame.func_name, frame.file_name, frame.line, frame.inlined);
646 : 0 : free(frame.func_name);
647 : 0 : free(frame.file_name);
648 : : }
649 : : }
650 : 0 : free(frames);
651 : 0 : }
652 : :
653 : : // Print code location for backtrace buffer entry at *bt_entry
654 : 0 : void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT
655 : : {
656 [ # # ]: 0 : if (jl_bt_is_native(bt_entry)) {
657 : 0 : jl_print_native_codeloc(bt_entry[0].uintptr);
658 : : }
659 [ # # ]: 0 : else if (jl_bt_entry_tag(bt_entry) == JL_BT_INTERP_FRAME_TAG) {
660 : 0 : size_t ip = jl_bt_entry_header(bt_entry);
661 : 0 : jl_value_t *code = jl_bt_entry_jlvalue(bt_entry, 0);
662 [ # # ]: 0 : if (jl_is_method_instance(code)) {
663 : : // When interpreting a method instance, need to unwrap to find the code info
664 : 0 : code = ((jl_method_instance_t*)code)->uninferred;
665 : : }
666 [ # # ]: 0 : if (jl_is_code_info(code)) {
667 : 0 : jl_code_info_t *src = (jl_code_info_t*)code;
668 : : // See also the debug info handling in codegen.cpp.
669 : : // NB: debuginfoloc is 1-based!
670 : 0 : intptr_t debuginfoloc = ((int32_t*)jl_array_data(src->codelocs))[ip];
671 [ # # ]: 0 : while (debuginfoloc != 0) {
672 : : jl_line_info_node_t *locinfo = (jl_line_info_node_t*)
673 : 0 : jl_array_ptr_ref(src->linetable, debuginfoloc - 1);
674 [ # # ]: 0 : assert(jl_typeis(locinfo, jl_lineinfonode_type));
675 : 0 : const char *func_name = "Unknown";
676 : 0 : jl_value_t *method = locinfo->method;
677 [ # # ]: 0 : if (jl_is_method_instance(method))
678 : 0 : method = ((jl_method_instance_t*)method)->def.value;
679 [ # # ]: 0 : if (jl_is_method(method))
680 : 0 : method = (jl_value_t*)((jl_method_t*)method)->name;
681 [ # # ]: 0 : if (jl_is_symbol(method))
682 : 0 : func_name = jl_symbol_name((jl_sym_t*)method);
683 : 0 : jl_safe_print_codeloc(func_name, jl_symbol_name(locinfo->file),
684 : 0 : locinfo->line, locinfo->inlined_at);
685 : 0 : debuginfoloc = locinfo->inlined_at;
686 : : }
687 : : }
688 : : else {
689 : : // If we're using this function something bad has already happened;
690 : : // be a bit defensive to avoid crashing while reporting the crash.
691 : 0 : jl_safe_printf("No code info - unknown interpreter state!\n");
692 : : }
693 : : }
694 : : else {
695 : 0 : jl_safe_printf("Non-native bt entry with tag and header bits 0x%" PRIxPTR "\n",
696 : 0 : bt_entry[1].uintptr);
697 : : }
698 : 0 : }
699 : :
700 : :
701 : : #ifdef _OS_LINUX_
702 : : #if defined(__GLIBC__) && defined(_CPU_AARCH64_)
703 : : #define LONG_JMP_SP_ENV_SLOT 13
704 : : static uintptr_t julia_longjmp_xor_key;
705 : : // GLIBC mangles the function pointers in jmp_buf (used in {set,long}*jmp
706 : : // functions) by XORing them with a random key. For AArch64 it is a global
707 : : // variable rather than a TCB one (as for x86_64/powerpc). We obtain the key by
708 : : // issuing a setjmp and XORing the SP pointer values to derive the key.
709 : : static void JuliaInitializeLongjmpXorKey(void)
710 : : {
711 : : // 1. Call REAL(setjmp), which stores the mangled SP in env.
712 : : jmp_buf env;
713 : : _setjmp(env);
714 : :
715 : : // 2. Retrieve vanilla/mangled SP.
716 : : uintptr_t sp;
717 : : asm("mov %0, sp" : "=r" (sp));
718 : : uintptr_t mangled_sp = ((uintptr_t*)&env)[LONG_JMP_SP_ENV_SLOT];
719 : :
720 : : // 3. xor SPs to obtain key.
721 : : julia_longjmp_xor_key = mangled_sp ^ sp;
722 : : }
723 : : #endif
724 : :
725 : 0 : JL_UNUSED static uintptr_t ptr_demangle(uintptr_t p)
726 : : {
727 : : #if defined(__GLIBC__)
728 : : #if defined(_CPU_X86_)
729 : : // from https://github.com/bminor/glibc/blame/master/sysdeps/unix/sysv/linux/i386/sysdep.h
730 : : // last changed for GLIBC_2.6 on 2007-02-01
731 : : asm(" rorl $9, %0\n"
732 : : " xorl %%gs:0x18, %0"
733 : : : "=r"(p) : "0"(p) : );
734 : : #elif defined(_CPU_X86_64_)
735 : : // from https://github.com/bminor/glibc/blame/master/sysdeps/unix/sysv/linux/i386/sysdep.h
736 : 0 : asm(" rorq $17, %0\n"
737 : : " xorq %%fs:0x30, %0"
738 : : : "=r"(p) : "0"(p) : );
739 : : #elif defined(_CPU_AARCH64_)
740 : : // from https://github.com/bminor/glibc/blame/master/sysdeps/unix/sysv/linux/aarch64/sysdep.h
741 : : // We need to use a trick like this (from GCC/LLVM TSAN) to get access to it:
742 : : // https://github.com/llvm/llvm-project/commit/daa3ebce283a753f280c549cdb103fbb2972f08e
743 : : static pthread_once_t once = PTHREAD_ONCE_INIT;
744 : : pthread_once(&once, &JuliaInitializeLongjmpXorKey);
745 : : p ^= julia_longjmp_xor_key;
746 : : #elif defined(_CPU_ARM_)
747 : : // from https://github.com/bminor/glibc/blame/master/sysdeps/unix/sysv/linux/arm/sysdep.h
748 : : ; // nothing to do
749 : : #endif
750 : : #endif
751 : 0 : return p;
752 : : }
753 : : #endif
754 : :
755 : : // n.b. musl does not mangle pointers, but intentionally makes that impossible
756 : : // to determine (https://www.openwall.com/lists/musl/2013/03/29/13) so we do
757 : : // not support musl here.
758 : :
759 : : // n.b. We have not looked at other libc (e.g. ulibc), though they are probably
760 : : // often compatible with glibc (perhaps with or without pointer mangling).
761 : :
762 : :
763 : : #ifdef _OS_DARWIN_
764 : : // from https://github.com/apple/darwin-xnu/blame/main/libsyscall/os/tsd.h
765 : : #define __TSD_PTR_MUNGE 7
766 : :
767 : : #if defined(__i386__) || defined(__x86_64__)
768 : :
769 : : #if defined(__has_attribute)
770 : : #if __has_attribute(address_space)
771 : : #define OS_GS_RELATIVE __attribute__((address_space(256)))
772 : : #endif
773 : : #endif
774 : :
775 : : #ifdef OS_GS_RELATIVE
776 : : #define _os_tsd_get_base() ((void * OS_GS_RELATIVE *)0)
777 : : #else
778 : : __attribute__((always_inline))
779 : : static __inline__ void*
780 : : _os_tsd_get_direct(unsigned long slot)
781 : : {
782 : : void *ret;
783 : : __asm__("mov %%gs:%1, %0" : "=r" (ret) : "m" (*(void **)(slot * sizeof(void *))));
784 : : return ret;
785 : : }
786 : : #endif
787 : :
788 : : #elif defined(__arm__) || defined(__arm64__)
789 : : // Unconditionally defined ptrauth_strip (instead of using the ptrauth.h header)
790 : : // since libsystem will likely be compiled with -mbranch-protection, and we currently are not.
791 : : // code from https://github.com/llvm/llvm-project/blob/7714e0317520207572168388f22012dd9e152e9e/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
792 : : static inline uint64_t ptrauth_strip(uint64_t __value, unsigned int __key) {
793 : : // On the stack the link register is protected with Pointer
794 : : // Authentication Code when compiled with -mbranch-protection.
795 : : // Let's strip the PAC unconditionally because xpaclri is in the NOP space,
796 : : // so will do nothing when it is not enabled or not available.
797 : : uint64_t ret;
798 : : asm volatile(
799 : : "mov x30, %1\n\t"
800 : : "hint #7\n\t" // xpaclri
801 : : "mov %0, x30\n\t"
802 : : : "=r"(ret)
803 : : : "r"(__value)
804 : : : "x30");
805 : : return ret;
806 : : }
807 : :
808 : : __attribute__((always_inline, pure))
809 : : static __inline__ void**
810 : : _os_tsd_get_base(void)
811 : : {
812 : : #if defined(__arm__)
813 : : uintptr_t tsd;
814 : : __asm__("mrc p15, 0, %0, c13, c0, 3\n"
815 : : "bic %0, %0, #0x3\n" : "=r" (tsd));
816 : : /* lower 2-bits contain CPU number */
817 : : #elif defined(__arm64__)
818 : : uint64_t tsd;
819 : : __asm__("mrs %0, TPIDRRO_EL0\n"
820 : : "bic %0, %0, #0x7\n" : "=r" (tsd));
821 : : /* lower 3-bits contain CPU number */
822 : : #endif
823 : :
824 : : return (void**)(uintptr_t)tsd;
825 : : }
826 : : #define _os_tsd_get_base() _os_tsd_get_base()
827 : : #endif
828 : :
829 : : #ifdef _os_tsd_get_base
830 : : __attribute__((always_inline))
831 : : static __inline__ void*
832 : : _os_tsd_get_direct(unsigned long slot)
833 : : {
834 : : return _os_tsd_get_base()[slot];
835 : : }
836 : : #endif
837 : :
838 : : __attribute__((always_inline, pure))
839 : : static __inline__ uintptr_t
840 : : _os_ptr_munge_token(void)
841 : : {
842 : : return (uintptr_t)_os_tsd_get_direct(__TSD_PTR_MUNGE);
843 : : }
844 : :
845 : : __attribute__((always_inline, pure))
846 : : JL_UNUSED static __inline__ uintptr_t
847 : : _os_ptr_munge(uintptr_t ptr)
848 : : {
849 : : return ptr ^ _os_ptr_munge_token();
850 : : }
851 : : #define _OS_PTR_UNMUNGE(_ptr) _os_ptr_munge((uintptr_t)(_ptr))
852 : : #endif
853 : :
854 : :
855 : : extern bt_context_t *jl_to_bt_context(void *sigctx);
856 : :
857 : 0 : void jl_rec_backtrace(jl_task_t *t)
858 : : {
859 : 0 : jl_task_t *ct = jl_current_task;
860 : 0 : jl_ptls_t ptls = ct->ptls;
861 : 0 : ptls->bt_size = 0;
862 [ # # ]: 0 : if (t == ct) {
863 : 0 : ptls->bt_size = rec_backtrace(ptls->bt_data, JL_MAX_BT_SIZE, 0);
864 : 0 : return;
865 : : }
866 [ # # # # : 0 : if (t->copy_stack || !t->started || t->stkbuf == NULL)
# # ]
867 : 0 : return;
868 : 0 : int16_t old = -1;
869 [ # # # # ]: 0 : if (!jl_atomic_cmpswap(&t->tid, &old, ptls->tid) && old != ptls->tid)
870 : 0 : return;
871 : 0 : bt_context_t *context = NULL;
872 : : #if defined(_OS_WINDOWS_)
873 : : bt_context_t c;
874 : : memset(&c, 0, sizeof(c));
875 : : _JUMP_BUFFER *mctx = (_JUMP_BUFFER*)&t->ctx.ctx.uc_mcontext;
876 : : #if defined(_CPU_X86_64_)
877 : : c.Rbx = mctx->Rbx;
878 : : c.Rsp = mctx->Rsp;
879 : : c.Rbp = mctx->Rbp;
880 : : c.Rsi = mctx->Rsi;
881 : : c.Rdi = mctx->Rdi;
882 : : c.R12 = mctx->R12;
883 : : c.R13 = mctx->R13;
884 : : c.R14 = mctx->R14;
885 : : c.R15 = mctx->R15;
886 : : c.Rip = mctx->Rip;
887 : : memcpy(&c.Xmm6, &mctx->Xmm6, 10 * sizeof(mctx->Xmm6)); // Xmm6-Xmm15
888 : : #else
889 : : c.Eip = mctx->Eip;
890 : : c.Esp = mctx->Esp;
891 : : c.Ebp = mctx->Ebp;
892 : : #endif
893 : : context = &c;
894 : : #elif defined(JL_HAVE_UNW_CONTEXT)
895 : : context = &t->ctx.ctx;
896 : : #elif defined(JL_HAVE_UCONTEXT)
897 : : context = jl_to_bt_context(&t->ctx.ctx);
898 : : #elif defined(JL_HAVE_ASM)
899 : : bt_context_t c;
900 : 0 : memset(&c, 0, sizeof(c));
901 : : #if defined(_OS_LINUX_) && defined(__GLIBC__)
902 : 0 : __jmp_buf *mctx = &t->ctx.ctx.uc_mcontext->__jmpbuf;
903 : 0 : mcontext_t *mc = &c.uc_mcontext;
904 : : #if defined(_CPU_X86_)
905 : : // https://github.com/bminor/glibc/blame/master/sysdeps/i386/__longjmp.S
906 : : // https://github.com/bminor/glibc/blame/master/sysdeps/i386/jmpbuf-offsets.h
907 : : // https://github.com/bminor/musl/blame/master/src/setjmp/i386/longjmp.s
908 : : mc->gregs[REG_EBX] = (*mctx)[0];
909 : : mc->gregs[REG_ESI] = (*mctx)[1];
910 : : mc->gregs[REG_EDI] = (*mctx)[2];
911 : : mc->gregs[REG_EBP] = (*mctx)[3];
912 : : mc->gregs[REG_ESP] = (*mctx)[4];
913 : : mc->gregs[REG_EIP] = (*mctx)[5];
914 : : // ifdef PTR_DEMANGLE ?
915 : : mc->gregs[REG_ESP] = ptr_demangle(mc->gregs[REG_ESP]);
916 : : mc->gregs[REG_EIP] = ptr_demangle(mc->gregs[REG_EIP]);
917 : : context = &c;
918 : : #elif defined(_CPU_X86_64_)
919 : : // https://github.com/bminor/glibc/blame/master/sysdeps/x86_64/__longjmp.S
920 : : // https://github.com/bminor/glibc/blame/master/sysdeps/x86_64/jmpbuf-offsets.h
921 : : // https://github.com/bminor/musl/blame/master/src/setjmp/x86_64/setjmp.s
922 : 0 : mc->gregs[REG_RBX] = (*mctx)[0];
923 : 0 : mc->gregs[REG_RBP] = (*mctx)[1];
924 : 0 : mc->gregs[REG_R12] = (*mctx)[2];
925 : 0 : mc->gregs[REG_R13] = (*mctx)[3];
926 : 0 : mc->gregs[REG_R14] = (*mctx)[4];
927 : 0 : mc->gregs[REG_R15] = (*mctx)[5];
928 : 0 : mc->gregs[REG_RSP] = (*mctx)[6];
929 : 0 : mc->gregs[REG_RIP] = (*mctx)[7];
930 : : // ifdef PTR_DEMANGLE ?
931 : 0 : mc->gregs[REG_RBP] = ptr_demangle(mc->gregs[REG_RBP]);
932 : 0 : mc->gregs[REG_RSP] = ptr_demangle(mc->gregs[REG_RSP]);
933 : 0 : mc->gregs[REG_RIP] = ptr_demangle(mc->gregs[REG_RIP]);
934 : 0 : context = &c;
935 : : #elif defined(_CPU_ARM_)
936 : : // https://github.com/bminor/glibc/blame/master/sysdeps/arm/__longjmp.S
937 : : // https://github.com/bminor/glibc/blame/master/sysdeps/arm/include/bits/setjmp.h
938 : : // https://github.com/bminor/musl/blame/master/src/setjmp/arm/longjmp.S
939 : : mc->arm_sp = (*mctx)[0];
940 : : mc->arm_lr = (*mctx)[1];
941 : : mc->arm_r4 = (*mctx)[2]; // aka v1
942 : : mc->arm_r5 = (*mctx)[3]; // aka v2
943 : : mc->arm_r6 = (*mctx)[4]; // aka v3
944 : : mc->arm_r7 = (*mctx)[5]; // aka v4
945 : : mc->arm_r8 = (*mctx)[6]; // aka v5
946 : : mc->arm_r9 = (*mctx)[7]; // aka v6 aka sb
947 : : mc->arm_r10 = (*mctx)[8]; // aka v7 aka sl
948 : : mc->arm_fp = (*mctx)[10]; // aka v8 aka r11
949 : : // ifdef PTR_DEMANGLE ?
950 : : mc->arm_sp = ptr_demangle(mc->arm_sp);
951 : : mc->arm_lr = ptr_demangle(mc->arm_lr);
952 : : mc->arm_pc = mc->arm_lr;
953 : : context = &c;
954 : : #elif defined(_CPU_AARCH64_)
955 : : // https://github.com/bminor/glibc/blame/master/sysdeps/aarch64/__longjmp.S
956 : : // https://github.com/bminor/glibc/blame/master/sysdeps/aarch64/jmpbuf-offsets.h
957 : : // https://github.com/bminor/musl/blame/master/src/setjmp/aarch64/longjmp.s
958 : : // https://github.com/libunwind/libunwind/blob/ec171c9ba7ea3abb2a1383cee2988a7abd483a1f/src/aarch64/unwind_i.h#L62
959 : : unw_fpsimd_context_t *mcfp = (unw_fpsimd_context_t*)&mc->__reserved;
960 : : mc->regs[19] = (*mctx)[0];
961 : : mc->regs[20] = (*mctx)[1];
962 : : mc->regs[21] = (*mctx)[2];
963 : : mc->regs[22] = (*mctx)[3];
964 : : mc->regs[23] = (*mctx)[4];
965 : : mc->regs[24] = (*mctx)[5];
966 : : mc->regs[25] = (*mctx)[6];
967 : : mc->regs[26] = (*mctx)[7];
968 : : mc->regs[27] = (*mctx)[8];
969 : : mc->regs[28] = (*mctx)[9];
970 : : mc->regs[29] = (*mctx)[10]; // aka fp
971 : : mc->regs[30] = (*mctx)[11]; // aka lr
972 : : // Yes, they did skip 12 why writing the code originally; and, no, I do not know why.
973 : : mc->sp = (*mctx)[13];
974 : : mcfp->vregs[7] = (*mctx)[14]; // aka d8
975 : : mcfp->vregs[8] = (*mctx)[15]; // aka d9
976 : : mcfp->vregs[9] = (*mctx)[16]; // aka d10
977 : : mcfp->vregs[10] = (*mctx)[17]; // aka d11
978 : : mcfp->vregs[11] = (*mctx)[18]; // aka d12
979 : : mcfp->vregs[12] = (*mctx)[19]; // aka d13
980 : : mcfp->vregs[13] = (*mctx)[20]; // aka d14
981 : : mcfp->vregs[14] = (*mctx)[21]; // aka d15
982 : : // ifdef PTR_DEMANGLE ?
983 : : mc->sp = ptr_demangle(mc->sp);
984 : : mc->regs[30] = ptr_demangle(mc->regs[30]);
985 : : mc->pc = mc->regs[30];
986 : : context = &c;
987 : : #else
988 : : #pragma message("jl_rec_backtrace not defined for ASM/SETJMP on unknown linux")
989 : : (void)mc;
990 : : (void)c;
991 : : (void)mctx;
992 : : #endif
993 : : #elif defined(_OS_DARWIN_)
994 : : sigjmp_buf *mctx = &t->ctx.ctx.uc_mcontext;
995 : : #if defined(_CPU_X86_64_)
996 : : // from https://github.com/apple/darwin-libplatform/blob/main/src/setjmp/x86_64/_setjmp.s
997 : : x86_thread_state64_t *mc = (x86_thread_state64_t*)&c;
998 : : mc->__rbx = ((uint64_t*)mctx)[0];
999 : : mc->__rbp = ((uint64_t*)mctx)[1];
1000 : : mc->__rsp = ((uint64_t*)mctx)[2];
1001 : : mc->__r12 = ((uint64_t*)mctx)[3];
1002 : : mc->__r13 = ((uint64_t*)mctx)[4];
1003 : : mc->__r14 = ((uint64_t*)mctx)[5];
1004 : : mc->__r15 = ((uint64_t*)mctx)[6];
1005 : : mc->__rip = ((uint64_t*)mctx)[7];
1006 : : // added in libsystem_plaform 177.200.16 (macOS Mojave 10.14.3)
1007 : : // prior to that _os_ptr_munge_token was (hopefully) typically 0,
1008 : : // so x ^ 0 == x and this is a no-op
1009 : : mc->__rbp = _OS_PTR_UNMUNGE(mc->__rbp);
1010 : : mc->__rsp = _OS_PTR_UNMUNGE(mc->__rsp);
1011 : : mc->__rip = _OS_PTR_UNMUNGE(mc->__rip);
1012 : : context = &c;
1013 : : #elif defined(_CPU_AARCH64_)
1014 : : // from https://github.com/apple/darwin-libplatform/blob/main/src/setjmp/arm64/setjmp.s
1015 : : // https://github.com/apple/darwin-xnu/blob/main/osfmk/mach/arm/_structs.h
1016 : : // https://github.com/llvm/llvm-project/blob/7714e0317520207572168388f22012dd9e152e9e/libunwind/src/Registers.hpp -> Registers_arm64
1017 : : arm_thread_state64_t *mc = (arm_thread_state64_t*)&c;
1018 : : mc->__x[19] = ((uint64_t*)mctx)[0];
1019 : : mc->__x[20] = ((uint64_t*)mctx)[1];
1020 : : mc->__x[21] = ((uint64_t*)mctx)[2];
1021 : : mc->__x[22] = ((uint64_t*)mctx)[3];
1022 : : mc->__x[23] = ((uint64_t*)mctx)[4];
1023 : : mc->__x[24] = ((uint64_t*)mctx)[5];
1024 : : mc->__x[25] = ((uint64_t*)mctx)[6];
1025 : : mc->__x[26] = ((uint64_t*)mctx)[7];
1026 : : mc->__x[27] = ((uint64_t*)mctx)[8];
1027 : : mc->__x[28] = ((uint64_t*)mctx)[9];
1028 : : mc->__x[10] = ((uint64_t*)mctx)[10];
1029 : : mc->__x[11] = ((uint64_t*)mctx)[11];
1030 : : mc->__x[12] = ((uint64_t*)mctx)[12];
1031 : : // 13 is reserved/unused
1032 : : double *mcfp = (double*)&mc[1];
1033 : : mcfp[7] = ((uint64_t*)mctx)[14]; // aka d8
1034 : : mcfp[8] = ((uint64_t*)mctx)[15]; // aka d9
1035 : : mcfp[9] = ((uint64_t*)mctx)[16]; // aka d10
1036 : : mcfp[10] = ((uint64_t*)mctx)[17]; // aka d11
1037 : : mcfp[11] = ((uint64_t*)mctx)[18]; // aka d12
1038 : : mcfp[12] = ((uint64_t*)mctx)[19]; // aka d13
1039 : : mcfp[13] = ((uint64_t*)mctx)[20]; // aka d14
1040 : : mcfp[14] = ((uint64_t*)mctx)[21]; // aka d15
1041 : : mc->__fp = _OS_PTR_UNMUNGE(mc->__x[10]);
1042 : : mc->__lr = _OS_PTR_UNMUNGE(mc->__x[11]);
1043 : : mc->__x[12] = _OS_PTR_UNMUNGE(mc->__x[12]);
1044 : : mc->__sp = mc->__x[12];
1045 : : // libunwind is broken for signed-pointers, but perhaps best not to leave the signed pointer lying around either
1046 : : mc->__pc = ptrauth_strip(mc->__lr, 0);
1047 : : mc->__pad = 0; // aka __ra_sign_state = not signed
1048 : : context = &c;
1049 : : #else
1050 : : #pragma message("jl_rec_backtrace not defined for ASM/SETJMP on unknown darwin")
1051 : : (void)mctx;
1052 : : (void)c;
1053 : : #endif
1054 : : #else
1055 : : #pragma message("jl_rec_backtrace not defined for ASM/SETJMP on unknown system")
1056 : : (void)c;
1057 : : #endif
1058 : : #elif defined(JL_HAVE_ASYNCIFY)
1059 : : #pragma message("jl_rec_backtrace not defined for ASYNCIFY")
1060 : : #elif defined(JL_HAVE_SIGALTSTACK)
1061 : : #pragma message("jl_rec_backtrace not defined for SIGALTSTACK")
1062 : : #else
1063 : : #pragma message("jl_rec_backtrace not defined for unknown task system")
1064 : : #endif
1065 [ # # ]: 0 : if (context)
1066 : 0 : ptls->bt_size = rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE, context, t->gcstack);
1067 [ # # ]: 0 : if (old == -1)
1068 : 0 : jl_atomic_store_relaxed(&t->tid, old);
1069 : : }
1070 : :
1071 : : //--------------------------------------------------
1072 : : // Tools for interactive debugging in gdb
1073 : :
1074 : 0 : JL_DLLEXPORT void jl_gdblookup(void* ip)
1075 : : {
1076 : 0 : jl_print_native_codeloc((uintptr_t)ip);
1077 : 0 : }
1078 : :
1079 : : // Print backtrace for current exception in catch block
1080 : 0 : JL_DLLEXPORT void jlbacktrace(void) JL_NOTSAFEPOINT
1081 : : {
1082 : 0 : jl_task_t *ct = jl_current_task;
1083 [ # # ]: 0 : if (ct->ptls == NULL)
1084 : 0 : return;
1085 : 0 : jl_excstack_t *s = ct->excstack;
1086 [ # # ]: 0 : if (!s)
1087 : 0 : return;
1088 : 0 : size_t i, bt_size = jl_excstack_bt_size(s, s->top);
1089 : 0 : jl_bt_element_t *bt_data = jl_excstack_bt_data(s, s->top);
1090 [ # # ]: 0 : for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
1091 : 0 : jl_print_bt_entry_codeloc(bt_data + i);
1092 : : }
1093 : : }
1094 : 0 : JL_DLLEXPORT void jlbacktracet(jl_task_t *t)
1095 : : {
1096 : 0 : jl_task_t *ct = jl_current_task;
1097 : 0 : jl_ptls_t ptls = ct->ptls;
1098 : 0 : jl_rec_backtrace(t);
1099 : 0 : size_t i, bt_size = ptls->bt_size;
1100 : 0 : jl_bt_element_t *bt_data = ptls->bt_data;
1101 [ # # ]: 0 : for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
1102 : 0 : jl_print_bt_entry_codeloc(bt_data + i);
1103 : : }
1104 : 0 : }
1105 : :
1106 : 0 : JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT
1107 : : {
1108 : 0 : jlbacktrace();
1109 : 0 : }
1110 : :
1111 : : #ifdef __cplusplus
1112 : : }
1113 : : #endif
|