@@ -370,6 +370,149 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
370
370
}
371
371
}
372
372
373
+ // crashing is the number of m's we have waited for when implementing
374
+ // GOTRACEBACK=crash when a signal is received.
375
+ var crashing int32
376
+
377
+ // testSigtrap is used by the runtime tests. If non-nil, it is called
378
+ // on SIGTRAP. If it returns true, the normal behavior on SIGTRAP is
379
+ // suppressed.
380
+ var testSigtrap func (info * siginfo , ctxt * sigctxt , gp * g ) bool
381
+
382
+ // sighandler is invoked when a signal occurs. The global g will be
383
+ // set to a gsignal goroutine and we will be running on the alternate
384
+ // signal stack. The parameter g will be the value of the global g
385
+ // when the signal occurred. The sig, info, and ctxt parameters are
386
+ // from the system signal handler: they are the parameters passed when
387
+ // the SA is passed to the sigaction system call.
388
+ //
389
+ // The garbage collector may have stopped the world, so write barriers
390
+ // are not allowed.
391
+ //
392
+ //go:nowritebarrierrec
393
+ func sighandler (sig uint32 , info * siginfo , ctxt unsafe.Pointer , gp * g ) {
394
+ _g_ := getg ()
395
+ c := & sigctxt {info , ctxt }
396
+
397
+ if sig == _SIGPROF {
398
+ sigprof (c .sigpc (), c .sigsp (), c .siglr (), gp , _g_ .m )
399
+ return
400
+ }
401
+
402
+ if sig == _SIGTRAP && testSigtrap != nil && testSigtrap (info , (* sigctxt )(noescape (unsafe .Pointer (c ))), gp ) {
403
+ return
404
+ }
405
+
406
+ flags := int32 (_SigThrow )
407
+ if sig < uint32 (len (sigtable )) {
408
+ flags = sigtable [sig ].flags
409
+ }
410
+ if flags & _SigPanic != 0 && gp .throwsplit {
411
+ // We can't safely sigpanic because it may grow the
412
+ // stack. Abort in the signal handler instead.
413
+ flags = (flags &^ _SigPanic ) | _SigThrow
414
+ }
415
+ if isAbortPC (c .sigpc ()) {
416
+ // On many architectures, the abort function just
417
+ // causes a memory fault. Don't turn that into a panic.
418
+ flags = _SigThrow
419
+ }
420
+ if c .sigcode () != _SI_USER && flags & _SigPanic != 0 {
421
+ // The signal is going to cause a panic.
422
+ // Arrange the stack so that it looks like the point
423
+ // where the signal occurred made a call to the
424
+ // function sigpanic. Then set the PC to sigpanic.
425
+
426
+ // Have to pass arguments out of band since
427
+ // augmenting the stack frame would break
428
+ // the unwinding code.
429
+ gp .sig = sig
430
+ gp .sigcode0 = uintptr (c .sigcode ())
431
+ gp .sigcode1 = uintptr (c .fault ())
432
+ gp .sigpc = c .sigpc ()
433
+
434
+ c .preparePanic (sig , gp )
435
+ return
436
+ }
437
+
438
+ if c .sigcode () == _SI_USER || flags & _SigNotify != 0 {
439
+ if sigsend (sig ) {
440
+ return
441
+ }
442
+ }
443
+
444
+ if c .sigcode () == _SI_USER && signal_ignored (sig ) {
445
+ return
446
+ }
447
+
448
+ if flags & _SigKill != 0 {
449
+ dieFromSignal (sig )
450
+ }
451
+
452
+ if flags & _SigThrow == 0 {
453
+ return
454
+ }
455
+
456
+ _g_ .m .throwing = 1
457
+ _g_ .m .caughtsig .set (gp )
458
+
459
+ if crashing == 0 {
460
+ startpanic_m ()
461
+ }
462
+
463
+ if sig < uint32 (len (sigtable )) {
464
+ print (sigtable [sig ].name , "\n " )
465
+ } else {
466
+ print ("Signal " , sig , "\n " )
467
+ }
468
+
469
+ print ("PC=" , hex (c .sigpc ()), " m=" , _g_ .m .id , " sigcode=" , c .sigcode (), "\n " )
470
+ if _g_ .m .lockedg != 0 && _g_ .m .ncgo > 0 && gp == _g_ .m .g0 {
471
+ print ("signal arrived during cgo execution\n " )
472
+ gp = _g_ .m .lockedg .ptr ()
473
+ }
474
+ print ("\n " )
475
+
476
+ level , _ , docrash := gotraceback ()
477
+ if level > 0 {
478
+ goroutineheader (gp )
479
+ tracebacktrap (c .sigpc (), c .sigsp (), c .siglr (), gp )
480
+ if crashing > 0 && gp != _g_ .m .curg && _g_ .m .curg != nil && readgstatus (_g_ .m .curg )&^_Gscan == _Grunning {
481
+ // tracebackothers on original m skipped this one; trace it now.
482
+ goroutineheader (_g_ .m .curg )
483
+ traceback (^ uintptr (0 ), ^ uintptr (0 ), 0 , _g_ .m .curg )
484
+ } else if crashing == 0 {
485
+ tracebackothers (gp )
486
+ print ("\n " )
487
+ }
488
+ dumpregs (c )
489
+ }
490
+
491
+ if docrash {
492
+ crashing ++
493
+ if crashing < mcount ()- int32 (extraMCount ) {
494
+ // There are other m's that need to dump their stacks.
495
+ // Relay SIGQUIT to the next m by sending it to the current process.
496
+ // All m's that have already received SIGQUIT have signal masks blocking
497
+ // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
498
+ // When the last m receives the SIGQUIT, it will fall through to the call to
499
+ // crash below. Just in case the relaying gets botched, each m involved in
500
+ // the relay sleeps for 5 seconds and then does the crash/exit itself.
501
+ // In expected operation, the last m has received the SIGQUIT and run
502
+ // crash/exit and the process is gone, all long before any of the
503
+ // 5-second sleeps have finished.
504
+ print ("\n -----\n \n " )
505
+ raiseproc (_SIGQUIT )
506
+ usleep (5 * 1000 * 1000 )
507
+ }
508
+ crash ()
509
+ }
510
+
511
+ printDebugLog ()
512
+
513
+ exit (2 )
514
+ }
515
+
373
516
// sigpanic turns a synchronous signal into a run-time panic.
374
517
// If the signal handler sees a synchronous panic, it arranges the
375
518
// stack to look like the function where the signal occurred called
0 commit comments