LCOV - code coverage report
Current view: top level - src - stackwalk.c (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 250 314 79.6 %
Date: 2022-07-16 23:42:53 Functions: 15 20 75.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 109 152 71.7 %

           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                 :   28358800 : static jl_gcframe_t *is_enter_interpreter_frame(jl_gcframe_t **ppgcstack, uintptr_t sp) JL_NOTSAFEPOINT
      32                 :            : {
      33                 :   28358800 :     jl_gcframe_t *pgcstack = *ppgcstack;
      34         [ +  + ]:   39992000 :     while (pgcstack != NULL) {
      35                 :   22140600 :         jl_gcframe_t *prev = pgcstack->prev;
      36         [ +  + ]:   22140600 :         if (pgcstack->nroots & 2) { // tagged frame
      37                 :   10507400 :             uintptr_t frame_fp = ((uintptr_t*)pgcstack)[-1];
      38         [ +  - ]:   10507400 :             if (frame_fp != 0) { // check that frame was fully initialized
      39         [ +  + ]:   10507400 :                 if (frame_fp >= sp)
      40                 :   10200300 :                     break; // stack grows down, so frame pointer is monotonically increasing
      41                 :     307145 :                 *ppgcstack = prev;
      42                 :     307145 :                 return pgcstack;
      43                 :            :             }
      44                 :            :         }
      45                 :   11633100 :         *ppgcstack = pgcstack = prev;
      46                 :            :     }
      47                 :   28051700 :     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                 :     348939 : 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                 :     348939 :     volatile size_t n = 0;
      74                 :     348939 :     volatile int need_more_space = 0;
      75                 :     348939 :     uintptr_t return_ip = 0;
      76                 :     348939 :     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                 :     348939 :     jl_jmp_buf *old_buf = jl_get_safe_restore();
      87                 :            :     jl_jmp_buf buf;
      88                 :     348939 :     jl_set_safe_restore(&buf);
      89         [ +  - ]:     348939 :     if (!jl_setjmp(buf, 0)) {
      90                 :            : #endif
      91                 :     348939 :         int have_more_frames = 1;
      92         [ +  + ]:   29431400 :         while (have_more_frames) {
      93         [ +  + ]:   29082500 :             if (n + JL_BT_MAX_ENTRY_SIZE + 1 > maxsize) {
      94                 :            :                 // Postpone advancing the cursor: may need more space
      95                 :         49 :                 need_more_space = 1;
      96                 :         49 :                 break;
      97                 :            :             }
      98                 :   29082500 :             uintptr_t oldsp = thesp;
      99                 :   29082500 :             have_more_frames = jl_unw_step(cursor, from_signal_handler, &return_ip, &thesp);
     100   [ +  +  +  - ]:   29082500 :             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                 :         49 :                 have_more_frames = 0;
     104                 :            :             }
     105         [ +  + ]:   29082500 :             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                 :         45 :                 have_more_frames = 0;
     111                 :            :             }
     112         [ +  + ]:   29082500 :             if (skip > 0) {
     113                 :    1030790 :                 skip--;
     114                 :    1030790 :                 from_signal_handler = 0;
     115                 :    1030790 :                 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                 :   28051700 :             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         [ +  + ]:   28051700 :             if (!from_signal_handler)
     147                 :   28046400 :                 call_ip -= 1; // normal frame
     148                 :   28051700 :             from_signal_handler = 0;
     149   [ +  +  +  + ]:   28051700 :             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                 :         54 :                 have_more_frames = 0;
     152                 :         54 :                 call_ip = 0;
     153                 :            :             }
     154                 :   28051700 :             jl_bt_element_t *bt_entry = bt_data + n;
     155                 :            :             jl_gcframe_t *pgcstack;
     156         [ +  + ]:   28051700 :             if ((pgcstack = is_enter_interpreter_frame(ppgcstack, thesp))) {
     157                 :     307145 :                 size_t add = jl_capture_interp_frame(bt_entry, (void*)((char*)pgcstack - sizeof(void*)), maxsize - n);
     158                 :     307145 :                 n += add;
     159                 :     307145 :                 bt_entry += add;
     160         [ -  + ]:     307145 :                 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                 :   28051700 :             bt_entry->uintptr = call_ip;
     169         [ +  + ]:   28051700 :             if (sp)
     170                 :         58 :                 sp[n] = thesp;
     171                 :   28051700 :             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                 :     348939 :     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                 :     348940 :     *bt_size = n;
     191                 :     348940 :     return need_more_space;
     192                 :            : }
     193                 :            : 
     194                 :       5265 : 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         [ -  + ]:       5265 :     if (!jl_unw_init(&cursor, context))
     199                 :          0 :         return 0;
     200                 :       5265 :     size_t bt_size = 0;
     201                 :       5265 :     jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, 0, &pgcstack, 1);
     202                 :       5265 :     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                 :     343535 : NOINLINE size_t rec_backtrace(jl_bt_element_t *bt_data, size_t maxsize, int skip)
     211                 :            : {
     212                 :            :     bt_context_t context;
     213                 :     343535 :     memset(&context, 0, sizeof(context));
     214                 :     343535 :     int r = jl_unw_get(&context);
     215         [ -  + ]:     343536 :     if (r < 0)
     216                 :          0 :         return 0;
     217                 :     343536 :     jl_gcframe_t *pgcstack = jl_pgcstack;
     218                 :            :     bt_cursor_t cursor;
     219         [ -  + ]:     343536 :     if (!jl_unw_init(&cursor, &context))
     220                 :          0 :         return 0;
     221                 :     343535 :     size_t bt_size = 0;
     222                 :     343535 :     jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, skip + 1, &pgcstack, 0);
     223                 :     343536 :     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                 :         92 : JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip)
     236                 :            : {
     237                 :         92 :     jl_array_t *ip = NULL;
     238                 :         92 :     jl_array_t *sp = NULL;
     239                 :         92 :     jl_array_t *bt2 = NULL;
     240                 :         92 :     JL_GC_PUSH3(&ip, &sp, &bt2);
     241         [ +  + ]:         92 :     if (array_ptr_void_type == NULL) {
     242                 :         13 :         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                 :         92 :     ip = jl_alloc_array_1d(array_ptr_void_type, 0);
     245         [ +  + ]:         92 :     sp = returnsp ? jl_alloc_array_1d(array_ptr_void_type, 0) : NULL;
     246                 :         92 :     bt2 = jl_alloc_array_1d(jl_array_any_type, 0);
     247                 :         92 :     const size_t maxincr = 1000;
     248                 :            :     bt_context_t context;
     249                 :            :     bt_cursor_t cursor;
     250                 :         92 :     memset(&context, 0, sizeof(context));
     251                 :         92 :     int r = jl_unw_get(&context);
     252                 :         92 :     jl_gcframe_t *pgcstack = jl_pgcstack;
     253   [ +  -  +  - ]:         92 :     if (r == 0 && jl_unw_init(&cursor, &context)) {
     254                 :            :         // Skip frame for jl_backtrace_from_here itself
     255                 :         92 :         skip += 1;
     256                 :         92 :         size_t offset = 0;
     257                 :         92 :         int have_more_frames = 1;
     258         [ +  + ]:        231 :         while (have_more_frames) {
     259                 :        139 :             jl_array_grow_end(ip, maxincr);
     260                 :        139 :             uintptr_t *sp_ptr = NULL;
     261         [ +  + ]:        139 :             if (returnsp) {
     262                 :          1 :                 jl_array_grow_end(sp, maxincr);
     263                 :          1 :                 sp_ptr = (uintptr_t*)jl_array_data(sp) + offset;
     264                 :            :             }
     265                 :        139 :             size_t size_incr = 0;
     266                 :        139 :             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                 :        139 :             skip = 0;
     269                 :        139 :             offset += size_incr;
     270                 :            :         }
     271                 :         92 :         jl_array_del_end(ip, jl_array_len(ip) - offset);
     272         [ +  + ]:         92 :         if (returnsp)
     273                 :          1 :             jl_array_del_end(sp, jl_array_len(sp) - offset);
     274                 :            : 
     275                 :         92 :         size_t n = 0;
     276                 :         92 :         jl_bt_element_t *bt_data = (jl_bt_element_t*)jl_array_data(ip);
     277         [ +  + ]:      47913 :         while (n < jl_array_len(ip)) {
     278                 :      47821 :             jl_bt_element_t *bt_entry = bt_data + n;
     279         [ +  + ]:      47821 :             if (!jl_bt_is_native(bt_entry)) {
     280                 :       2099 :                 size_t njlvals = jl_bt_num_jlvals(bt_entry);
     281         [ +  + ]:       4297 :                 for (size_t j = 0; j < njlvals; j++) {
     282                 :       2198 :                     jl_value_t *v = jl_bt_entry_jlvalue(bt_entry, j);
     283                 :            :                     JL_GC_PROMISE_ROOTED(v);
     284                 :       2198 :                     jl_array_ptr_1d_push(bt2, v);
     285                 :            :                 }
     286                 :            :             }
     287                 :      47821 :             n += jl_bt_entry_size(bt_entry);
     288                 :            :         }
     289                 :            :     }
     290         [ +  + ]:         92 :     jl_value_t *bt = returnsp ? (jl_value_t*)jl_svec(3, ip, bt2, sp) : (jl_value_t*)jl_svec(2, ip, bt2);
     291                 :         92 :     JL_GC_POP();
     292                 :         92 :     return bt;
     293                 :            : }
     294                 :            : 
     295                 :      25269 : 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         [ +  + ]:      25269 :     if (array_ptr_void_type == NULL) {
     301                 :         55 :         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                 :      25269 :     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                 :      25269 :     memcpy(bt->data, bt_data, bt_size * sizeof(jl_bt_element_t));
     307                 :      25269 :     bt2 = *bt2out = jl_alloc_array_1d(jl_array_any_type, 0);
     308                 :            :     // Scan the backtrace buffer for any gc-managed values
     309         [ +  + ]:    1538210 :     for (size_t i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
     310                 :    1512940 :         jl_bt_element_t* bt_entry = bt_data + i;
     311         [ +  + ]:    1512940 :         if (jl_bt_is_native(bt_entry))
     312                 :    1512570 :             continue;
     313                 :        369 :         size_t njlvals = jl_bt_num_jlvals(bt_entry);
     314         [ +  + ]:       1105 :         for (size_t j = 0; j < njlvals; j++) {
     315                 :        736 :             jl_value_t *v = jl_bt_entry_jlvalue(bt_entry, j);
     316                 :            :             JL_GC_PROMISE_ROOTED(v);
     317                 :        736 :             jl_array_ptr_1d_push(bt2, v);
     318                 :            :         }
     319                 :            :     }
     320                 :      25269 : }
     321                 :            : 
     322                 :        144 : JL_DLLEXPORT jl_value_t *jl_get_backtrace(void)
     323                 :            : {
     324                 :        144 :     jl_excstack_t *s = jl_current_task->excstack;
     325                 :        144 :     jl_bt_element_t *bt_data = NULL;
     326                 :        144 :     size_t bt_size = 0;
     327   [ +  -  +  + ]:        144 :     if (s && s->top) {
     328                 :        139 :         bt_data = jl_excstack_bt_data(s, s->top);
     329                 :        139 :         bt_size = jl_excstack_bt_size(s, s->top);
     330                 :            :     }
     331                 :        144 :     jl_array_t *bt = NULL, *bt2 = NULL;
     332                 :        144 :     JL_GC_PUSH2(&bt, &bt2);
     333                 :        144 :     decode_backtrace(bt_data, bt_size, &bt, &bt2);
     334                 :        144 :     jl_svec_t *pair = jl_svec2(bt, bt2);
     335                 :        144 :     JL_GC_POP();
     336                 :        144 :     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                 :      24944 : JL_DLLEXPORT jl_value_t *jl_get_excstack(jl_task_t* task, int include_bt, int max_entries)
     344                 :            : {
     345         [ -  + ]:      24944 :     JL_TYPECHK(current_exceptions, task, (jl_value_t*)task);
     346                 :      24944 :     jl_task_t *ct = jl_current_task;
     347   [ +  +  +  + ]:      24944 :     if (task != ct && jl_atomic_load_relaxed(&task->_state) == JL_TASK_STATE_RUNNABLE) {
     348                 :          1 :         jl_error("Inspecting the exception stack of a task which might "
     349                 :            :                  "be running concurrently isn't allowed.");
     350                 :            :     }
     351                 :      24943 :     jl_array_t *stack = NULL;
     352                 :      24943 :     jl_array_t *bt = NULL;
     353                 :      24943 :     jl_array_t *bt2 = NULL;
     354                 :      24943 :     JL_GC_PUSH3(&stack, &bt, &bt2);
     355                 :      24943 :     stack = jl_alloc_array_1d(jl_array_any_type, 0);
     356                 :      24943 :     jl_excstack_t *excstack = task->excstack;
     357         [ +  + ]:      24943 :     size_t itr = excstack ? excstack->top : 0;
     358                 :      24943 :     int i = 0;
     359   [ +  +  +  - ]:      50070 :     while (itr > 0 && i < max_entries) {
     360                 :      25127 :         jl_array_ptr_1d_push(stack, jl_excstack_exception(excstack, itr));
     361         [ +  + ]:      25127 :         if (include_bt) {
     362                 :      25125 :             decode_backtrace(jl_excstack_bt_data(excstack, itr),
     363                 :            :                              jl_excstack_bt_size(excstack, itr),
     364                 :            :                              &bt, &bt2);
     365                 :      25125 :             jl_array_ptr_1d_push(stack, (jl_value_t*)bt);
     366                 :      25125 :             jl_array_ptr_1d_push(stack, (jl_value_t*)bt2);
     367                 :            :         }
     368                 :      25127 :         itr = jl_excstack_next(excstack, itr);
     369                 :      25127 :         i++;
     370                 :            :     }
     371                 :      24943 :     JL_GC_POP();
     372                 :      24943 :     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                 :     348892 : static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context)
     539                 :            : {
     540                 :     348892 :     return unw_init_local(cursor, context) == 0;
     541                 :            : }
     542                 :            : 
     543                 :   29082500 : 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         [ -  + ]:   29082500 :     if (unw_get_reg(cursor, UNW_REG_IP, &reg) < 0)
     548                 :          0 :         return 0;
     549                 :   29082500 :     *ip = reg;
     550         [ -  + ]:   29082500 :     if (unw_get_reg(cursor, UNW_REG_SP, &reg) < 0)
     551                 :          0 :         return 0;
     552                 :   29082500 :     *sp = reg;
     553                 :   29082500 :     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                 :     206501 : JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC)
     583                 :            : {
     584                 :     206501 :     jl_task_t *ct = jl_current_task;
     585                 :     206501 :     jl_frame_t *frames = NULL;
     586                 :     206501 :     int8_t gc_state = jl_gc_safe_enter(ct->ptls);
     587                 :     206501 :     int n = jl_getFunctionInfo(&frames, (uintptr_t)ip, skipC, 0);
     588                 :     206501 :     jl_gc_safe_leave(ct->ptls, gc_state);
     589                 :     206501 :     jl_value_t *rs = (jl_value_t*)jl_alloc_svec(n);
     590                 :     206501 :     JL_GC_PUSH1(&rs);
     591         [ +  + ]:     421614 :     for (int i = 0; i < n; i++) {
     592                 :     215113 :         jl_frame_t frame = frames[i];
     593                 :     215113 :         jl_value_t *r = (jl_value_t*)jl_alloc_svec(6);
     594                 :     215113 :         jl_svecset(rs, i, r);
     595         [ +  + ]:     215113 :         if (frame.func_name)
     596                 :     208756 :             jl_svecset(r, 0, jl_symbol(frame.func_name));
     597                 :            :         else
     598                 :       6357 :             jl_svecset(r, 0, jl_empty_sym);
     599                 :     215113 :         free(frame.func_name);
     600         [ +  + ]:     215113 :         if (frame.file_name)
     601                 :     208870 :             jl_svecset(r, 1, jl_symbol(frame.file_name));
     602                 :            :         else
     603                 :       6243 :             jl_svecset(r, 1, jl_empty_sym);
     604                 :     215113 :         free(frame.file_name);
     605                 :     215113 :         jl_svecset(r, 2, jl_box_long(frame.line));
     606         [ +  + ]:     215113 :         jl_svecset(r, 3, frame.linfo != NULL ? (jl_value_t*)frame.linfo : jl_nothing);
     607                 :     215113 :         jl_svecset(r, 4, jl_box_bool(frame.fromC));
     608                 :     215113 :         jl_svecset(r, 5, jl_box_bool(frame.inlined));
     609                 :            :     }
     610                 :     206501 :     free(frames);
     611                 :     206501 :     JL_GC_POP();
     612                 :     206501 :     return rs;
     613                 :            : }
     614                 :            : 
     615                 :        605 : static void jl_safe_print_codeloc(const char* func_name, const char* file_name,
     616                 :            :                                   int line, int inlined) JL_NOTSAFEPOINT
     617                 :            : {
     618         [ +  + ]:        605 :     const char *inlined_str = inlined ? " [inlined]" : "";
     619         [ +  + ]:        605 :     if (line != -1) {
     620                 :        562 :         jl_safe_printf("%s at %s:%d%s\n", func_name, file_name, line, inlined_str);
     621                 :            :     }
     622                 :            :     else {
     623                 :         43 :         jl_safe_printf("%s at %s (unknown line)%s\n", func_name, file_name, inlined_str);
     624                 :            :     }
     625                 :        605 : }
     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                 :        555 : 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                 :        555 :     jl_frame_t *frames = NULL;
     636                 :        555 :     int n = jl_getFunctionInfo(&frames, ip, 0, 0);
     637                 :            :     int i;
     638                 :            : 
     639         [ +  + ]:       1167 :     for (i = 0; i < n; i++) {
     640                 :        619 :         jl_frame_t frame = frames[i];
     641         [ +  + ]:        619 :         if (!frame.func_name) {
     642                 :         17 :             jl_safe_printf("unknown function (ip: %p)\n", (void*)ip);
     643                 :            :         }
     644                 :            :         else {
     645                 :        602 :             jl_safe_print_codeloc(frame.func_name, frame.file_name, frame.line, frame.inlined);
     646                 :        602 :             free(frame.func_name);
     647                 :        602 :             free(frame.file_name);
     648                 :            :         }
     649                 :            :     }
     650                 :        548 :     free(frames);
     651                 :        548 : }
     652                 :            : 
     653                 :            : // Print code location for backtrace buffer entry at *bt_entry
     654                 :        558 : void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT
     655                 :            : {
     656         [ +  + ]:        558 :     if (jl_bt_is_native(bt_entry)) {
     657                 :        555 :         jl_print_native_codeloc(bt_entry[0].uintptr);
     658                 :            :     }
     659         [ +  - ]:          3 :     else if (jl_bt_entry_tag(bt_entry) == JL_BT_INTERP_FRAME_TAG) {
     660                 :          3 :         size_t ip = jl_bt_entry_header(bt_entry);
     661                 :          3 :         jl_value_t *code = jl_bt_entry_jlvalue(bt_entry, 0);
     662         [ -  + ]:          3 :         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         [ +  - ]:          3 :         if (jl_is_code_info(code)) {
     667                 :          3 :             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                 :          3 :             intptr_t debuginfoloc = ((int32_t*)jl_array_data(src->codelocs))[ip];
     671         [ +  + ]:          6 :             while (debuginfoloc != 0) {
     672                 :            :                 jl_line_info_node_t *locinfo = (jl_line_info_node_t*)
     673                 :          3 :                     jl_array_ptr_ref(src->linetable, debuginfoloc - 1);
     674         [ -  + ]:          3 :                 assert(jl_typeis(locinfo, jl_lineinfonode_type));
     675                 :          3 :                 const char *func_name = "Unknown";
     676                 :          3 :                 jl_value_t *method = locinfo->method;
     677         [ -  + ]:          3 :                 if (jl_is_method_instance(method))
     678                 :          0 :                     method = ((jl_method_instance_t*)method)->def.value;
     679         [ -  + ]:          3 :                 if (jl_is_method(method))
     680                 :          0 :                     method = (jl_value_t*)((jl_method_t*)method)->name;
     681         [ +  - ]:          3 :                 if (jl_is_symbol(method))
     682                 :          3 :                     func_name = jl_symbol_name((jl_sym_t*)method);
     683                 :          3 :                 jl_safe_print_codeloc(func_name, jl_symbol_name(locinfo->file),
     684                 :          3 :                                       locinfo->line, locinfo->inlined_at);
     685                 :          3 :                 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                 :        551 : }
     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                 :          8 : JL_DLLEXPORT void jlbacktrace(void) JL_NOTSAFEPOINT
    1081                 :            : {
    1082                 :          8 :     jl_task_t *ct = jl_current_task;
    1083         [ -  + ]:          8 :     if (ct->ptls == NULL)
    1084                 :          0 :         return;
    1085                 :          8 :     jl_excstack_t *s = ct->excstack;
    1086         [ -  + ]:          8 :     if (!s)
    1087                 :          0 :         return;
    1088                 :          8 :     size_t i, bt_size = jl_excstack_bt_size(s, s->top);
    1089                 :          8 :     jl_bt_element_t *bt_data = jl_excstack_bt_data(s, s->top);
    1090         [ +  + ]:        421 :     for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
    1091                 :        413 :         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

Generated by: LCOV version 1.14