runtime: fix traceback from goexit1

We used to not call traceback from goexit1.
But now tracer does it and crashes on amd64p32:

runtime: unexpected return pc for runtime.getg called from 0x108a4240
goroutine 18 [runnable, locked to thread]:
runtime.traceGoEnd()
    src/runtime/trace.go:758 fp=0x10818fe0 sp=0x10818fdc
runtime.goexit1()
    src/runtime/proc1.go:1540 +0x20 fp=0x10818fe8 sp=0x10818fe0
runtime.getg(0x0)
    src/runtime/asm_386.s:2414 fp=0x10818fec sp=0x10818fe8
created by runtime/pprof_test.TestTraceStress
    src/runtime/pprof/trace_test.go:123 +0x500

Return PC from goexit1 points right after goexit (+0x6).
It happens to work most of the time somehow.

This change fixes traceback from goexit1 by adding an additional NOP to goexit.

Fixes #9931

Change-Id: Ied25240a181b0a2d7bc98127b3ed9068e9a1a13e
Reviewed-on: https://go-review.googlesource.com/5460
Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
Dmitry Vyukov 2015-02-20 20:07:02 +03:00 committed by Russ Cox
parent 2dbee8919c
commit 894024f478
6 changed files with 10 additions and 2 deletions

View file

@ -2422,6 +2422,8 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
TEXT runtime·goexit(SB),NOSPLIT,$0-0 TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return CALL runtime·goexit1(SB) // does not return
// traceback from goexit1 must hit code range of goexit
BYTE $0x90 // NOP
TEXT runtime·getg(SB),NOSPLIT,$0-4 TEXT runtime·getg(SB),NOSPLIT,$0-4
get_tls(CX) get_tls(CX)

View file

@ -2457,6 +2457,8 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
TEXT runtime·goexit(SB),NOSPLIT,$0-0 TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return CALL runtime·goexit1(SB) // does not return
// traceback from goexit1 must hit code range of goexit
BYTE $0x90 // NOP
TEXT runtime·getg(SB),NOSPLIT,$0-8 TEXT runtime·getg(SB),NOSPLIT,$0-8
get_tls(CX) get_tls(CX)

View file

@ -1085,6 +1085,8 @@ TEXT runtime·return0(SB), NOSPLIT, $0
TEXT runtime·goexit(SB),NOSPLIT,$0-0 TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return CALL runtime·goexit1(SB) // does not return
// traceback from goexit1 must hit code range of goexit
BYTE $0x90 // NOP
TEXT runtime·getg(SB),NOSPLIT,$0-4 TEXT runtime·getg(SB),NOSPLIT,$0-4
get_tls(CX) get_tls(CX)

View file

@ -1338,6 +1338,8 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$8
TEXT runtime·goexit(SB),NOSPLIT,$-4-0 TEXT runtime·goexit(SB),NOSPLIT,$-4-0
MOVW R0, R0 // NOP MOVW R0, R0 // NOP
BL runtime·goexit1(SB) // does not return BL runtime·goexit1(SB) // does not return
// traceback from goexit1 must hit code range of goexit
MOVW R0, R0 // NOP
TEXT runtime·getg(SB),NOSPLIT,$-4-4 TEXT runtime·getg(SB),NOSPLIT,$-4-4
MOVW g, ret+0(FP) MOVW g, ret+0(FP)

View file

@ -1241,6 +1241,8 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$-8
TEXT runtime·goexit(SB),NOSPLIT,$-8-0 TEXT runtime·goexit(SB),NOSPLIT,$-8-0
MOVD R0, R0 // NOP MOVD R0, R0 // NOP
BL runtime·goexit1(SB) // does not return BL runtime·goexit1(SB) // does not return
// traceback from goexit1 must hit code range of goexit
MOVD R0, R0 // NOP
TEXT runtime·getg(SB),NOSPLIT,$-8-8 TEXT runtime·getg(SB),NOSPLIT,$-8-8
MOVD g, ret+0(FP) MOVD g, ret+0(FP)

View file

@ -1553,8 +1553,6 @@ func gopreempt_m(gp *g) {
} }
// Finishes execution of the current goroutine. // Finishes execution of the current goroutine.
// Must be NOSPLIT because it is called from Go. (TODO - probably not anymore)
//go:nosplit
func goexit1() { func goexit1() {
if raceenabled { if raceenabled {
racegoend() racegoend()