@@ -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
}
@@ -164,19 +166,31 @@ typedef arm_exception_state64_t host_exception_state_t;
164
166
static void jl_call_in_state (jl_ptls_t ptls2 , host_thread_state_t * state ,
165
167
void (* fptr )(void ))
166
168
{
167
- uint64_t rsp = (uint64_t )ptls2 -> signal_stack + sig_stack_size ;
169
+ #ifdef _CPU_X86_64_
170
+ uintptr_t rsp = state -> __rsp ;
171
+ #elif defined(_CPU_AARCH64_ )
172
+ uintptr_t rsp = state -> __sp ;
173
+ #else
174
+ #error "julia: throw-in-context not supported on this platform"
175
+ #endif
176
+ if (ptls2 -> signal_stack == NULL || is_addr_on_sigstack (ptls2 , (void * )rsp )) {
177
+ rsp = (rsp - 256 ) & ~(uintptr_t )15 ; // redzone and re-alignment
178
+ }
179
+ else {
180
+ rsp = (uintptr_t )ptls2 -> signal_stack + sig_stack_size ;
181
+ }
168
182
assert (rsp % 16 == 0 );
169
183
170
- // push (null) $RIP onto the stack
171
- rsp -= sizeof (void * );
172
- * (void * * )rsp = NULL ;
173
-
174
184
#ifdef _CPU_X86_64_
185
+ rsp -= sizeof (void * );
175
186
state -> __rsp = rsp ; // set stack pointer
176
187
state -> __rip = (uint64_t )fptr ; // "call" the function
177
- #else
188
+ #elif defined( _CPU_AARCH64_ )
178
189
state -> __sp = rsp ;
179
190
state -> __pc = (uint64_t )fptr ;
191
+ state -> __lr = 0 ;
192
+ #else
193
+ #error "julia: throw-in-context not supported on this platform"
180
194
#endif
181
195
}
182
196
@@ -194,11 +208,22 @@ static void jl_throw_in_thread(int tid, mach_port_t thread, jl_value_t *exceptio
194
208
ptls2 -> sig_exception = exception ;
195
209
}
196
210
jl_call_in_state (ptls2 , & state , & jl_sig_throw );
197
- ret = thread_set_state (thread , THREAD_STATE ,
198
- (thread_state_t )& state , count );
211
+ ret = thread_set_state (thread , THREAD_STATE , (thread_state_t )& state , count );
199
212
HANDLE_MACH_ERROR ("thread_set_state" , ret );
200
213
}
201
214
215
+ static void segv_handler (int sig , siginfo_t * info , void * context )
216
+ {
217
+ jl_ptls_t ptls = jl_get_ptls_states ();
218
+ assert (sig == SIGSEGV || sig == SIGBUS );
219
+ if (ptls -> safe_restore ) { // restarting jl_ or jl_unwind_stepn
220
+ jl_call_in_state (ptls , (host_thread_state_t * )jl_to_bt_context (context ), & jl_sig_throw );
221
+ }
222
+ else {
223
+ sigdie_handler (sig , info , context );
224
+ }
225
+ }
226
+
202
227
//exc_server uses dlsym to find symbol
203
228
JL_DLLEXPORT
204
229
kern_return_t catch_exception_raise (mach_port_t exception_port ,
@@ -208,18 +233,16 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,
208
233
exception_data_t code ,
209
234
mach_msg_type_number_t code_count )
210
235
{
211
- unsigned int count = THREAD_STATE_COUNT ;
212
236
unsigned int exc_count = HOST_EXCEPTION_STATE_COUNT ;
213
237
host_exception_state_t exc_state ;
214
- host_thread_state_t state ;
215
- #ifdef LIBOSXUNWIND
238
+ #ifdef LLVMLIBUNWIND
216
239
if (thread == mach_profiler_thread ) {
217
240
return profiler_segv_handler (exception_port , thread , task , exception , code , code_count );
218
241
}
219
242
#endif
220
243
int16_t tid ;
221
244
jl_ptls_t ptls2 = NULL ;
222
- for (tid = 0 ;tid < jl_n_threads ;tid ++ ) {
245
+ for (tid = 0 ; tid < jl_n_threads ; tid ++ ) {
223
246
jl_ptls_t _ptls2 = jl_all_tls_states [tid ];
224
247
if (pthread_mach_thread_np (_ptls2 -> system_id ) == thread ) {
225
248
ptls2 = _ptls2 ;
@@ -288,11 +311,8 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,
288
311
return KERN_SUCCESS ;
289
312
}
290
313
else {
291
- kern_return_t ret = thread_get_state (thread , THREAD_STATE , (thread_state_t )& state , & count );
292
- HANDLE_MACH_ERROR ("thread_get_state" , ret );
293
- jl_critical_error (SIGSEGV , (unw_context_t * )& state ,
294
- ptls2 -> bt_data , & ptls2 -> bt_size );
295
- return KERN_INVALID_ARGUMENT ;
314
+ jl_exit_thread0 (128 + SIGSEGV , NULL , 0 );
315
+ return KERN_SUCCESS ;
296
316
}
297
317
}
298
318
@@ -307,24 +327,27 @@ static void attach_exception_port(thread_port_t thread, int segv_only)
307
327
HANDLE_MACH_ERROR ("thread_set_exception_ports" , ret );
308
328
}
309
329
310
- static void jl_thread_suspend_and_get_state (int tid , unw_context_t * * ctx )
330
+ static void jl_thread_suspend_and_get_state2 (int tid , host_thread_state_t * ctx )
311
331
{
312
332
jl_ptls_t ptls2 = jl_all_tls_states [tid ];
313
- mach_port_t tid_port = pthread_mach_thread_np (ptls2 -> system_id );
333
+ mach_port_t thread = pthread_mach_thread_np (ptls2 -> system_id );
314
334
315
- kern_return_t ret = thread_suspend (tid_port );
335
+ kern_return_t ret = thread_suspend (thread );
316
336
HANDLE_MACH_ERROR ("thread_suspend" , ret );
317
337
318
338
// Do the actual sampling
319
339
unsigned int count = THREAD_STATE_COUNT ;
320
- static unw_context_t state ;
321
- memset (& state , 0 , sizeof (unw_context_t ));
340
+ memset (ctx , 0 , sizeof (* ctx ));
322
341
323
342
// Get the state of the suspended thread
324
- ret = thread_get_state (tid_port , THREAD_STATE , (thread_state_t )& state , & count );
343
+ ret = thread_get_state (thread , THREAD_STATE , (thread_state_t )ctx , & count );
344
+ }
325
345
326
- // Initialize the unwind context with the suspend thread's state
327
- * ctx = & state ;
346
+ static void jl_thread_suspend_and_get_state (int tid , unw_context_t * * ctx )
347
+ {
348
+ static host_thread_state_t state ;
349
+ jl_thread_suspend_and_get_state2 (tid , & state );
350
+ * ctx = (unw_context_t * )& state ;
328
351
}
329
352
330
353
static void jl_thread_resume (int tid , int sig )
@@ -366,29 +389,46 @@ static void jl_try_deliver_sigint(void)
366
389
HANDLE_MACH_ERROR ("thread_resume" , ret );
367
390
}
368
391
369
- static void jl_exit_thread0 (int exitstate )
392
+ static void JL_NORETURN jl_exit_thread0_cb (int exitstate )
393
+ {
394
+ CFI_NORETURN
395
+ jl_critical_error (exitstate - 128 , NULL );
396
+ jl_exit (exitstate );
397
+ }
398
+
399
+ static void jl_exit_thread0 (int exitstate , jl_bt_element_t * bt_data , size_t bt_size )
370
400
{
371
401
jl_ptls_t ptls2 = jl_all_tls_states [0 ];
372
402
mach_port_t thread = pthread_mach_thread_np (ptls2 -> system_id );
373
- kern_return_t ret = thread_suspend (thread );
374
- HANDLE_MACH_ERROR ("thread_suspend" , ret );
403
+
404
+ host_thread_state_t state ;
405
+ jl_thread_suspend_and_get_state2 (0 , & state );
406
+ unw_context_t * uc = (unw_context_t * )& state ;
375
407
376
408
// This aborts `sleep` and other syscalls.
377
- ret = thread_abort (thread );
409
+ kern_return_t ret = thread_abort (thread );
378
410
HANDLE_MACH_ERROR ("thread_abort" , ret );
379
411
380
- unsigned int count = THREAD_STATE_COUNT ;
381
- host_thread_state_t state ;
382
- ret = thread_get_state (thread , THREAD_STATE ,
383
- (thread_state_t )& state , & count );
412
+ if (bt_data == NULL ) {
413
+ // Must avoid extended backtrace frames here unless we're sure bt_data
414
+ // is properly rooted.
415
+ ptls2 -> bt_size = rec_backtrace_ctx (ptls2 -> bt_data , JL_MAX_BT_SIZE , uc , NULL );
416
+ }
417
+ else {
418
+ ptls2 -> bt_size = bt_size ; // <= JL_MAX_BT_SIZE
419
+ memcpy (ptls2 -> bt_data , bt_data , ptls2 -> bt_size * sizeof (bt_data [0 ]));
420
+ }
384
421
385
422
void (* exit_func )(int ) = & _exit ;
386
423
if (thread0_exit_count <= 1 ) {
387
- exit_func = & jl_exit ;
424
+ exit_func = & jl_exit_thread0_cb ;
388
425
}
389
426
else if (thread0_exit_count == 2 ) {
390
427
exit_func = & exit ;
391
428
}
429
+ else {
430
+ exit_func = & _exit ;
431
+ }
392
432
393
433
#ifdef _CPU_X86_64_
394
434
// First integer argument. Not portable but good enough =)
@@ -399,8 +439,8 @@ static void jl_exit_thread0(int exitstate)
399
439
#error Fill in first integer argument here
400
440
#endif
401
441
jl_call_in_state (ptls2 , & state , (void (* )(void ))exit_func );
402
- ret = thread_set_state ( thread , THREAD_STATE ,
403
- (thread_state_t )& state , count );
442
+ unsigned int count = THREAD_STATE_COUNT ;
443
+ ret = thread_set_state ( thread , THREAD_STATE , (thread_state_t )& state , count );
404
444
HANDLE_MACH_ERROR ("thread_set_state" , ret );
405
445
406
446
ret = thread_resume (thread );
@@ -498,8 +538,10 @@ void *mach_profile_listener(void *arg)
498
538
break ;
499
539
}
500
540
501
- unw_context_t * uc ;
502
- jl_thread_suspend_and_get_state (i , & uc );
541
+ host_thread_state_t state ;
542
+ jl_thread_suspend_and_get_state2 (i , & state );
543
+ unw_context_t * uc = (unw_context_t * )& state ;
544
+
503
545
if (running ) {
504
546
#ifdef LIBOSXUNWIND
505
547
/*
0 commit comments