From 70b2da98ca097598326d5d01406b287bcd5eb6ee Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 29 Sep 2014 21:21:36 -0700 Subject: [PATCH] runtime: initialize traceback variables earlier Our traceback code needs to know the PC of several special functions, including goexit, mcall, etc. Make sure that these PCs are initialized before any traceback occurs. Fixes #8766 LGTM=rsc R=golang-codereviews, rsc, khr, bradfitz CC=golang-codereviews https://golang.org/cl/145570043 --- src/runtime/proc.c | 1 + src/runtime/runtime.h | 1 + src/runtime/traceback.go | 39 +++++++++++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 1f0a79098b..e84dc1d048 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -131,6 +131,7 @@ runtime·schedinit(void) runtime·sched.maxmcount = 10000; + runtime·tracebackinit(); runtime·symtabinit(); runtime·stackinit(); runtime·mallocinit(); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 3a6d3e3262..aa300d7bb8 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -841,6 +841,7 @@ void runtime·mpreinit(M*); void runtime·minit(void); void runtime·unminit(void); void runtime·signalstack(byte*, int32); +void runtime·tracebackinit(void); void runtime·symtabinit(void); Func* runtime·findfunc(uintptr); int32 runtime·funcline(Func*, uintptr, String*); diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index a93c42186b..24dc3eea95 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -31,20 +31,36 @@ import "unsafe" const usesLR = GOARCH != "amd64" && GOARCH != "amd64p32" && GOARCH != "386" var ( - deferprocPC = funcPC(deferproc) - goexitPC = funcPC(goexit) - jmpdeferPC = funcPC(jmpdefer) - mcallPC = funcPC(mcall) - morestackPC = funcPC(morestack) - mstartPC = funcPC(mstart) - newprocPC = funcPC(newproc) - newstackPC = funcPC(newstack) - rt0_goPC = funcPC(rt0_go) - sigpanicPC = funcPC(sigpanic) + // initialized in tracebackinit + deferprocPC uintptr + goexitPC uintptr + jmpdeferPC uintptr + mcallPC uintptr + morestackPC uintptr + mstartPC uintptr + newprocPC uintptr + rt0_goPC uintptr + sigpanicPC uintptr externalthreadhandlerp uintptr // initialized elsewhere ) +func tracebackinit() { + // Go variable initialization happens late during runtime startup. + // Instead of initializing the variables above in the declarations, + // schedinit calls this function so that the variables are + // initialized and available earlier in the startup sequence. + deferprocPC = funcPC(deferproc) + goexitPC = funcPC(goexit) + jmpdeferPC = funcPC(jmpdefer) + mcallPC = funcPC(mcall) + morestackPC = funcPC(morestack) + mstartPC = funcPC(mstart) + newprocPC = funcPC(newproc) + rt0_goPC = funcPC(rt0_go) + sigpanicPC = funcPC(sigpanic) +} + // Traceback over the deferred function calls. // Report them like calls that have been invoked but not started executing yet. func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer) { @@ -81,6 +97,9 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns // collector (callback != nil). A little clunky to merge these, but avoids // duplicating the code and all its subtlety. func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, printall bool) int { + if goexitPC == 0 { + gothrow("gentraceback before goexitPC initialization") + } g := getg() gotraceback := gotraceback(nil) if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp. -- 2.50.0