1
0
mirror of https://github.com/golang/go synced 2024-11-23 05:50:05 -07:00

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 <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Keith Randall 2020-02-28 12:59:38 -08:00
parent a2bff7c296
commit 63f1bc5992
4 changed files with 67 additions and 0 deletions

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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