mirror of
https://github.com/golang/go
synced 2024-11-27 01:31:21 -07:00
c06a354bcc
In issue11656.go, it tests that if the runtime can get a reasonable traceback when it faults at a non-function PC. It does it by jumping to an address that contains an illegal or trap instruction. When it traps, the SIGTRAP crashes the runtime. This CL changes it to use an instruction that triggers SIGSEGV. This is due to two reasons: - currently, the handling of bad PC is done by preparePanic, which is only used for a panicking signal (SIGSEGV, SIGBUS, SIGFPE), not a fatal signal (e.g. SIGTRAP). - the test uses defer+recover to get a traceback, which only works for panicking signals, not fatal signals. Ideally, we should handle all kinds of faults (SIGSEGV, SIGBUS, SIGILL, SIGTRAP, etc.) with a nice traceback. I'll leave this for the future. This CL also adds RISCV64 support. Fixes #43283. Change-Id: I5e0fbf8530cc89d16e05c3257d282bc1d4d03405 Reviewed-on: https://go-review.googlesource.com/c/go/+/279423 Trust: Cherry Zhang <cherryyz@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org>
90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
// run
|
|
|
|
// Copyright 2015 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.
|
|
|
|
// windows doesn't work, because Windows exception handling
|
|
// delivers signals based on the current PC, and that current PC
|
|
// doesn't go into the Go runtime.
|
|
// +build !windows
|
|
|
|
// wasm does not work, because the linear memory is not executable.
|
|
// +build !wasm
|
|
|
|
// This test doesn't work on gccgo/GoLLVM, because they will not find
|
|
// any unwind information for the artificial function, and will not be
|
|
// able to unwind past that point.
|
|
// +build !gccgo
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"runtime"
|
|
"runtime/debug"
|
|
"unsafe"
|
|
)
|
|
|
|
func main() {
|
|
debug.SetPanicOnFault(true)
|
|
defer func() {
|
|
if err := recover(); err == nil {
|
|
panic("not panicking")
|
|
}
|
|
pc, _, _, _ := runtime.Caller(10)
|
|
f := runtime.FuncForPC(pc)
|
|
if f == nil || f.Name() != "main.f" {
|
|
if f == nil {
|
|
println("no func for ", unsafe.Pointer(pc))
|
|
} else {
|
|
println("found func:", f.Name())
|
|
}
|
|
panic("cannot find main.f on stack")
|
|
}
|
|
}()
|
|
f(20)
|
|
}
|
|
|
|
func f(n int) {
|
|
if n > 0 {
|
|
f(n - 1)
|
|
}
|
|
var f struct {
|
|
x uintptr
|
|
}
|
|
|
|
// We want to force a seg fault, to get a crash at a PC value != 0.
|
|
// Not all systems make the data section non-executable.
|
|
ill := make([]byte, 64)
|
|
switch runtime.GOARCH {
|
|
case "386", "amd64":
|
|
ill = append(ill, 0x89, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00) // MOVL AX, 0
|
|
case "arm":
|
|
binary.LittleEndian.PutUint32(ill, 0xe3a00000) // MOVW $0, R0
|
|
binary.LittleEndian.PutUint32(ill, 0xe5800000) // MOVW R0, (R0)
|
|
case "arm64":
|
|
binary.LittleEndian.PutUint32(ill, 0xf90003ff) // MOVD ZR, (ZR)
|
|
case "ppc64":
|
|
binary.BigEndian.PutUint32(ill, 0xf8000000) // MOVD R0, (R0)
|
|
case "ppc64le":
|
|
binary.LittleEndian.PutUint32(ill, 0xf8000000) // MOVD R0, (R0)
|
|
case "mips", "mips64":
|
|
binary.BigEndian.PutUint32(ill, 0xfc000000) // MOVV R0, (R0)
|
|
case "mipsle", "mips64le":
|
|
binary.LittleEndian.PutUint32(ill, 0xfc000000) // MOVV R0, (R0)
|
|
case "s390x":
|
|
ill = append(ill, 0xa7, 0x09, 0x00, 0x00) // MOVD $0, R0
|
|
ill = append(ill, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x24) // MOVD R0, (R0)
|
|
case "riscv64":
|
|
binary.LittleEndian.PutUint32(ill, 0x00003023) // MOV X0, (X0)
|
|
default:
|
|
// Just leave it as 0 and hope for the best.
|
|
}
|
|
|
|
f.x = uintptr(unsafe.Pointer(&ill[0]))
|
|
p := &f
|
|
fn := *(*func())(unsafe.Pointer(&p))
|
|
fn()
|
|
}
|