@@ -84,14 +84,16 @@ extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
84
84
void * mach_segv_listener (void * arg )
85
85
{
86
86
(void )arg ;
87
+ (void )jl_get_ptls_states ();
87
88
while (1 ) {
88
89
int ret = mach_msg_server (exc_server , 2048 , segv_port , MACH_MSG_TIMEOUT_NONE );
89
90
jl_safe_printf ("mach_msg_server: %s\n" , mach_error_string (ret ));
90
91
jl_exit (128 + SIGSEGV );
91
92
}
92
93
}
93
94
94
- static void allocate_segv_handler ()
95
+
96
+ static void allocate_mach_handler ()
95
97
{
96
98
// ensure KEYMGR_GCC3_DW2_OBJ_LIST is initialized, as this requires malloc
97
99
// and thus can deadlock when used without first initializing it.
@@ -122,7 +124,7 @@ static void allocate_segv_handler()
122
124
jl_error ("pthread_create failed" );
123
125
}
124
126
pthread_attr_destroy (& attr );
125
- for (int16_t tid = 0 ;tid < jl_n_threads ;tid ++ ) {
127
+ for (int16_t tid = 0 ; tid < jl_n_threads ; tid ++ ) {
126
128
attach_exception_port (pthread_mach_thread_np (jl_all_tls_states [tid ]-> system_id ), 0 );
127
129
}
128
130
}
@@ -158,20 +160,31 @@ typedef arm_exception_state64_t host_exception_state_t;
158
160
static void jl_call_in_state (jl_ptls_t ptls2 , host_thread_state_t * state ,
159
161
void (* fptr )(void ))
160
162
{
161
- uint64_t rsp = (uint64_t )ptls2 -> signal_stack + sig_stack_size ;
163
+ #ifdef _CPU_X86_64_
164
+ uintptr_t rsp = state -> __rsp ;
165
+ #elif defined(_CPU_AARCH64_ )
166
+ uintptr_t rsp = state -> __sp ;
167
+ #else
168
+ #error "julia: throw-in-context not supported on this platform"
169
+ #endif
170
+ if (ptls2 -> signal_stack == NULL || is_addr_on_sigstack (ptls2 , (void * )rsp )) {
171
+ rsp = (rsp - 256 ) & ~(uintptr_t )15 ; // redzone and re-alignment
172
+ }
173
+ else {
174
+ rsp = (uintptr_t )ptls2 -> signal_stack + sig_stack_size ;
175
+ }
162
176
assert (rsp % 16 == 0 );
163
177
164
178
#ifdef _CPU_X86_64_
165
- // push (null) $RIP onto the stack
166
179
rsp -= sizeof (void * );
167
- * (void * * )rsp = NULL ;
168
-
169
180
state -> __rsp = rsp ; // set stack pointer
170
181
state -> __rip = (uint64_t )fptr ; // "call" the function
171
- #else
182
+ #elif defined( _CPU_AARCH64_ )
172
183
state -> __sp = rsp ;
173
184
state -> __pc = (uint64_t )fptr ;
174
185
state -> __lr = 0 ;
186
+ #else
187
+ #error "julia: throw-in-context not supported on this platform"
175
188
#endif
176
189
}
177
190
@@ -204,11 +217,22 @@ static void jl_throw_in_thread(int tid, mach_port_t thread, jl_value_t *exceptio
204
217
ptls2 -> sig_exception = exception ;
205
218
}
206
219
jl_call_in_state (ptls2 , & state , & jl_sig_throw );
207
- ret = thread_set_state (thread , THREAD_STATE ,
208
- (thread_state_t )& state , count );
220
+ ret = thread_set_state (thread , THREAD_STATE , (thread_state_t )& state , count );
209
221
HANDLE_MACH_ERROR ("thread_set_state" , ret );
210
222
}
211
223
224
+ static void segv_handler (int sig , siginfo_t * info , void * context )
225
+ {
226
+ jl_ptls_t ptls = jl_get_ptls_states ();
227
+ assert (sig == SIGSEGV || sig == SIGBUS );
228
+ if (ptls -> safe_restore ) { // restarting jl_ or jl_unwind_stepn
229
+ jl_call_in_state (ptls , (host_thread_state_t * )jl_to_bt_context (context ), & jl_sig_throw );
230
+ }
231
+ else {
232
+ sigdie_handler (sig , info , context );
233
+ }
234
+ }
235
+
212
236
//exc_server uses dlsym to find symbol
213
237
JL_DLLEXPORT
214
238
kern_return_t catch_exception_raise (mach_port_t exception_port ,
@@ -218,18 +242,16 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,
218
242
exception_data_t code ,
219
243
mach_msg_type_number_t code_count )
220
244
{
221
- unsigned int count = THREAD_STATE_COUNT ;
222
245
unsigned int exc_count = HOST_EXCEPTION_STATE_COUNT ;
223
246
host_exception_state_t exc_state ;
224
- host_thread_state_t state ;
225
247
#ifdef LLVMLIBUNWIND
226
248
if (thread == mach_profiler_thread ) {
227
249
return profiler_segv_handler (exception_port , thread , task , exception , code , code_count );
228
250
}
229
251
#endif
230
252
int16_t tid ;
231
253
jl_ptls_t ptls2 = NULL ;
232
- for (tid = 0 ;tid < jl_n_threads ;tid ++ ) {
254
+ for (tid = 0 ; tid < jl_n_threads ; tid ++ ) {
233
255
jl_ptls_t _ptls2 = jl_all_tls_states [tid ];
234
256
if (pthread_mach_thread_np (_ptls2 -> system_id ) == thread ) {
235
257
ptls2 = _ptls2 ;
@@ -298,11 +320,8 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,
298
320
return KERN_SUCCESS ;
299
321
}
300
322
else {
301
- kern_return_t ret = thread_get_state (thread , THREAD_STATE , (thread_state_t )& state , & count );
302
- HANDLE_MACH_ERROR ("thread_get_state" , ret );
303
- jl_critical_error (SIGSEGV , (unw_context_t * )& state ,
304
- ptls2 -> bt_data , & ptls2 -> bt_size );
305
- return KERN_INVALID_ARGUMENT ;
323
+ jl_exit_thread0 (128 + SIGSEGV , NULL , 0 );
324
+ return KERN_SUCCESS ;
306
325
}
307
326
}
308
327
@@ -317,24 +336,27 @@ static void attach_exception_port(thread_port_t thread, int segv_only)
317
336
HANDLE_MACH_ERROR ("thread_set_exception_ports" , ret );
318
337
}
319
338
320
- static void jl_thread_suspend_and_get_state (int tid , unw_context_t * * ctx )
339
+ static void jl_thread_suspend_and_get_state2 (int tid , host_thread_state_t * ctx )
321
340
{
322
341
jl_ptls_t ptls2 = jl_all_tls_states [tid ];
323
- mach_port_t tid_port = pthread_mach_thread_np (ptls2 -> system_id );
342
+ mach_port_t thread = pthread_mach_thread_np (ptls2 -> system_id );
324
343
325
- kern_return_t ret = thread_suspend (tid_port );
344
+ kern_return_t ret = thread_suspend (thread );
326
345
HANDLE_MACH_ERROR ("thread_suspend" , ret );
327
346
328
347
// Do the actual sampling
329
348
unsigned int count = THREAD_STATE_COUNT ;
330
- static unw_context_t state ;
331
- memset (& state , 0 , sizeof (unw_context_t ));
349
+ memset (ctx , 0 , sizeof (* ctx ));
332
350
333
351
// Get the state of the suspended thread
334
- ret = thread_get_state (tid_port , THREAD_STATE , (thread_state_t )& state , & count );
352
+ ret = thread_get_state (thread , THREAD_STATE , (thread_state_t )ctx , & count );
353
+ }
335
354
336
- // Initialize the unwind context with the suspend thread's state
337
- * ctx = & state ;
355
+ static void jl_thread_suspend_and_get_state (int tid , unw_context_t * * ctx )
356
+ {
357
+ static host_thread_state_t state ;
358
+ jl_thread_suspend_and_get_state2 (tid , & state );
359
+ * ctx = (unw_context_t * )& state ;
338
360
}
339
361
340
362
static void jl_thread_resume (int tid , int sig )
@@ -376,29 +398,46 @@ static void jl_try_deliver_sigint(void)
376
398
HANDLE_MACH_ERROR ("thread_resume" , ret );
377
399
}
378
400
379
- static void jl_exit_thread0 (int exitstate )
401
+ static void JL_NORETURN jl_exit_thread0_cb (int exitstate )
402
+ {
403
+ CFI_NORETURN
404
+ jl_critical_error (exitstate - 128 , NULL );
405
+ jl_exit (exitstate );
406
+ }
407
+
408
+ static void jl_exit_thread0 (int exitstate , jl_bt_element_t * bt_data , size_t bt_size )
380
409
{
381
410
jl_ptls_t ptls2 = jl_all_tls_states [0 ];
382
411
mach_port_t thread = pthread_mach_thread_np (ptls2 -> system_id );
383
- kern_return_t ret = thread_suspend (thread );
384
- HANDLE_MACH_ERROR ("thread_suspend" , ret );
412
+
413
+ host_thread_state_t state ;
414
+ jl_thread_suspend_and_get_state2 (0 , & state );
415
+ unw_context_t * uc = (unw_context_t * )& state ;
385
416
386
417
// This aborts `sleep` and other syscalls.
387
- ret = thread_abort (thread );
418
+ kern_return_t ret = thread_abort (thread );
388
419
HANDLE_MACH_ERROR ("thread_abort" , ret );
389
420
390
- unsigned int count = THREAD_STATE_COUNT ;
391
- host_thread_state_t state ;
392
- ret = thread_get_state (thread , THREAD_STATE ,
393
- (thread_state_t )& state , & count );
421
+ if (bt_data == NULL ) {
422
+ // Must avoid extended backtrace frames here unless we're sure bt_data
423
+ // is properly rooted.
424
+ ptls2 -> bt_size = rec_backtrace_ctx (ptls2 -> bt_data , JL_MAX_BT_SIZE , uc , NULL );
425
+ }
426
+ else {
427
+ ptls2 -> bt_size = bt_size ; // <= JL_MAX_BT_SIZE
428
+ memcpy (ptls2 -> bt_data , bt_data , ptls2 -> bt_size * sizeof (bt_data [0 ]));
429
+ }
394
430
395
431
void (* exit_func )(int ) = & _exit ;
396
432
if (thread0_exit_count <= 1 ) {
397
- exit_func = & jl_exit ;
433
+ exit_func = & jl_exit_thread0_cb ;
398
434
}
399
435
else if (thread0_exit_count == 2 ) {
400
436
exit_func = & exit ;
401
437
}
438
+ else {
439
+ exit_func = & _exit ;
440
+ }
402
441
403
442
#ifdef _CPU_X86_64_
404
443
// First integer argument. Not portable but good enough =)
@@ -409,8 +448,8 @@ static void jl_exit_thread0(int exitstate)
409
448
#error Fill in first integer argument here
410
449
#endif
411
450
jl_call_in_state (ptls2 , & state , (void (* )(void ))exit_func );
412
- ret = thread_set_state ( thread , THREAD_STATE ,
413
- (thread_state_t )& state , count );
451
+ unsigned int count = THREAD_STATE_COUNT ;
452
+ ret = thread_set_state ( thread , THREAD_STATE , (thread_state_t )& state , count );
414
453
HANDLE_MACH_ERROR ("thread_set_state" , ret );
415
454
416
455
ret = thread_resume (thread );
@@ -508,8 +547,10 @@ void *mach_profile_listener(void *arg)
508
547
break ;
509
548
}
510
549
511
- unw_context_t * uc ;
512
- jl_thread_suspend_and_get_state (i , & uc );
550
+ host_thread_state_t state ;
551
+ jl_thread_suspend_and_get_state2 (i , & state );
552
+ unw_context_t * uc = (unw_context_t * )& state ;
553
+
513
554
if (running ) {
514
555
#ifdef LLVMLIBUNWIND
515
556
/*
0 commit comments