]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add debugger hook for fatal signals
authorAlessandro Arzilli <alessandro.arzilli@gmail.com>
Wed, 17 May 2023 13:33:07 +0000 (15:33 +0200)
committerGopher Robot <gobot@golang.org>
Mon, 5 Jun 2023 17:00:46 +0000 (17:00 +0000)
On Go <= 1.20 signals that caused the program to exit would eventually
call runtime.fatal. After the changes made in go.dev/cl/462437 but it
would still be nice if debuggers (eg. Delve) had a function they could
hook to intercept fatal signals.

Change-Id: Icf2b65187f95d52e60825c84f386806a75b38f6e
Reviewed-on: https://go-review.googlesource.com/c/go/+/495736
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Auto-Submit: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/runtime/signal_unix.go

index 6ebfbbc5be7eb50293bfb6dd3162ae8fb79c7b28..97ef68579713733286c81492d27e7454cc9bbf38 100644 (file)
@@ -734,44 +734,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
                startpanic_m()
        }
 
-       if sig < uint32(len(sigtable)) {
-               print(sigtable[sig].name, "\n")
-       } else {
-               print("Signal ", sig, "\n")
-       }
-
-       print("PC=", hex(c.sigpc()), " m=", mp.id, " sigcode=", c.sigcode(), "\n")
-       if mp.incgo && gp == mp.g0 && mp.curg != nil {
-               print("signal arrived during cgo execution\n")
-               // Switch to curg so that we get a traceback of the Go code
-               // leading up to the cgocall, which switched from curg to g0.
-               gp = mp.curg
-       }
-       if sig == _SIGILL || sig == _SIGFPE {
-               // It would be nice to know how long the instruction is.
-               // Unfortunately, that's complicated to do in general (mostly for x86
-               // and s930x, but other archs have non-standard instruction lengths also).
-               // Opt to print 16 bytes, which covers most instructions.
-               const maxN = 16
-               n := uintptr(maxN)
-               // We have to be careful, though. If we're near the end of
-               // a page and the following page isn't mapped, we could
-               // segfault. So make sure we don't straddle a page (even though
-               // that could lead to printing an incomplete instruction).
-               // We're assuming here we can read at least the page containing the PC.
-               // I suppose it is possible that the page is mapped executable but not readable?
-               pc := c.sigpc()
-               if n > physPageSize-pc%physPageSize {
-                       n = physPageSize - pc%physPageSize
-               }
-               print("instruction bytes:")
-               b := (*[maxN]byte)(unsafe.Pointer(pc))
-               for i := uintptr(0); i < n; i++ {
-                       print(" ", hex(b[i]))
-               }
-               println()
-       }
-       print("\n")
+       gp = fatalsignal(sig, c, gp, mp)
 
        level, _, docrash := gotraceback()
        if level > 0 {
@@ -813,6 +776,48 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
        exit(2)
 }
 
+func fatalsignal(sig uint32, c *sigctxt, gp *g, mp *m) *g {
+       if sig < uint32(len(sigtable)) {
+               print(sigtable[sig].name, "\n")
+       } else {
+               print("Signal ", sig, "\n")
+       }
+
+       print("PC=", hex(c.sigpc()), " m=", mp.id, " sigcode=", c.sigcode(), "\n")
+       if mp.incgo && gp == mp.g0 && mp.curg != nil {
+               print("signal arrived during cgo execution\n")
+               // Switch to curg so that we get a traceback of the Go code
+               // leading up to the cgocall, which switched from curg to g0.
+               gp = mp.curg
+       }
+       if sig == _SIGILL || sig == _SIGFPE {
+               // It would be nice to know how long the instruction is.
+               // Unfortunately, that's complicated to do in general (mostly for x86
+               // and s930x, but other archs have non-standard instruction lengths also).
+               // Opt to print 16 bytes, which covers most instructions.
+               const maxN = 16
+               n := uintptr(maxN)
+               // We have to be careful, though. If we're near the end of
+               // a page and the following page isn't mapped, we could
+               // segfault. So make sure we don't straddle a page (even though
+               // that could lead to printing an incomplete instruction).
+               // We're assuming here we can read at least the page containing the PC.
+               // I suppose it is possible that the page is mapped executable but not readable?
+               pc := c.sigpc()
+               if n > physPageSize-pc%physPageSize {
+                       n = physPageSize - pc%physPageSize
+               }
+               print("instruction bytes:")
+               b := (*[maxN]byte)(unsafe.Pointer(pc))
+               for i := uintptr(0); i < n; i++ {
+                       print(" ", hex(b[i]))
+               }
+               println()
+       }
+       print("\n")
+       return gp
+}
+
 // sigpanic turns a synchronous signal into a run-time panic.
 // If the signal handler sees a synchronous panic, it arranges the
 // stack to look like the function where the signal occurred called