From 63f1bc59922d454f288ad3d193bc60d7c980dbb0 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 28 Feb 2020 12:59:38 -0800 Subject: [PATCH] runtime: print instruction bytes when reporting a SIGILL Print the bytes of the instruction that generated a SIGILL. This should help us respond to bug reports without having to go back-and-forth with the reporter to get the instruction involved. Might also help with SIGILL problems that are difficult to reproduce. Update #37513 Change-Id: I33059b1dbfc97bce16142a843f32a88a6547e280 Reviewed-on: https://go-review.googlesource.com/c/go/+/221431 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/signal_unix.go | 24 +++++++++++++++++ test/fixedbugs/issue37513.dir/main.go | 27 ++++++++++++++++++++ test/fixedbugs/issue37513.dir/sigill_amd64.s | 7 +++++ test/fixedbugs/issue37513.go | 9 +++++++ 4 files changed, 67 insertions(+) create mode 100644 test/fixedbugs/issue37513.dir/main.go create mode 100644 test/fixedbugs/issue37513.dir/sigill_amd64.s create mode 100644 test/fixedbugs/issue37513.go diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index d2e66938051..32b192c9777 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -607,6 +607,30 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { print("signal arrived during cgo execution\n") gp = _g_.m.lockedg.ptr() } + if sig == _SIGILL { + // 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") level, _, docrash := gotraceback() diff --git a/test/fixedbugs/issue37513.dir/main.go b/test/fixedbugs/issue37513.dir/main.go new file mode 100644 index 00000000000..75106521b6b --- /dev/null +++ b/test/fixedbugs/issue37513.dir/main.go @@ -0,0 +1,27 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "os" + "os/exec" +) + +func main() { + if len(os.Args) > 1 { + // Generate a SIGILL. + sigill() + return + } + // Run ourselves with an extra argument. That process should SIGILL. + out, _ := exec.Command(os.Args[0], "foo").CombinedOutput() + want := "instruction bytes: 0xf 0xb 0xc3" + if !bytes.Contains(out, []byte(want)) { + fmt.Printf("got:\n%s\nwant:\n%s\n", string(out), want) + } +} +func sigill() diff --git a/test/fixedbugs/issue37513.dir/sigill_amd64.s b/test/fixedbugs/issue37513.dir/sigill_amd64.s new file mode 100644 index 00000000000..43260c21aed --- /dev/null +++ b/test/fixedbugs/issue37513.dir/sigill_amd64.s @@ -0,0 +1,7 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +TEXT ·sigill(SB),0,$0-0 + UD2 // generates a SIGILL + RET diff --git a/test/fixedbugs/issue37513.go b/test/fixedbugs/issue37513.go new file mode 100644 index 00000000000..e05b2d861f5 --- /dev/null +++ b/test/fixedbugs/issue37513.go @@ -0,0 +1,9 @@ +// buildrundir + +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux,amd64 darwin,amd64 linux,386 + +package ignored