pkg/proc: tolerate absence of stack barriers in Go 1.9 (#762)

Stack barriers were removed in Go 1.9, and thus code that
expected various stack-barrier-related symbols to exist
does not find them.  Check for their absence and do not
crash when they are missing.  Disable stack-barrier-handling
test for 1.9 and beyond.

Fixes #754.
This commit is contained in:
dr2chase
2017-03-13 13:53:16 -04:00
committed by Derek Parker
parent 97e3fc261c
commit bd48358de3
3 changed files with 19 additions and 6 deletions

View File

@ -2489,14 +2489,16 @@ func TestStacktraceWithBarriers(t *testing.T) {
// The original return address is saved into the stkbar slice inside the G // The original return address is saved into the stkbar slice inside the G
// struct. // struct.
// In Go 1.9 stack barriers have been removed and this test must be disabled.
if ver, _ := ParseVersionString(runtime.Version()); ver.Major < 0 || ver.AfterOrEqual(GoVersion{1, 9, -1, 0, 0}) {
return
}
// In Go 1.8 stack barriers are not inserted by default, this enables them. // In Go 1.8 stack barriers are not inserted by default, this enables them.
godebugOld := os.Getenv("GODEBUG") godebugOld := os.Getenv("GODEBUG")
defer os.Setenv("GODEBUG", godebugOld) defer os.Setenv("GODEBUG", godebugOld)
os.Setenv("GODEBUG", "gcrescanstacks=1") os.Setenv("GODEBUG", "gcrescanstacks=1")
// TODO(aarzilli): in Go 1.9 stack barriers will be removed completely, therefore
// this test will have to be disabled
withTestProcess("binarytrees", t, func(p *Process, fixture protest.Fixture) { withTestProcess("binarytrees", t, func(p *Process, fixture protest.Fixture) {
// We want to get a user goroutine with a stack barrier, to get that we execute the program until runtime.gcInstallStackBarrier is executed AND the goroutine it was executed onto contains a call to main.bottomUpTree // We want to get a user goroutine with a stack barrier, to get that we execute the program until runtime.gcInstallStackBarrier is executed AND the goroutine it was executed onto contains a call to main.bottomUpTree
_, err := setFunctionBreakpoint(p, "runtime.gcInstallStackBarrier") _, err := setFunctionBreakpoint(p, "runtime.gcInstallStackBarrier")

View File

@ -130,8 +130,10 @@ type savedLR struct {
} }
func newStackIterator(dbp *Process, pc, sp, bp uint64, stkbar []savedLR, stkbarPos int) *stackIterator { func newStackIterator(dbp *Process, pc, sp, bp uint64, stkbar []savedLR, stkbarPos int) *stackIterator {
stackBarrierPC := dbp.goSymTable.LookupFunc(runtimeStackBarrier).Entry stackBarrierFunc := dbp.goSymTable.LookupFunc(runtimeStackBarrier) // stack barriers were removed in Go 1.9
if stkbar != nil { var stackBarrierPC uint64
if stackBarrierFunc != nil && stkbar != nil {
stackBarrierPC = stackBarrierFunc.Entry
fn := dbp.goSymTable.PCToFunc(pc) fn := dbp.goSymTable.PCToFunc(pc)
if fn != nil && fn.Name == runtimeStackBarrier { if fn != nil && fn.Name == runtimeStackBarrier {
// We caught the goroutine as it's executing the stack barrier, we must // We caught the goroutine as it's executing the stack barrier, we must

View File

@ -396,8 +396,14 @@ func (gvar *Variable) parseG() (*G, error) {
id, _ := constant.Int64Val(gvar.fieldVariable("goid").Value) id, _ := constant.Int64Val(gvar.fieldVariable("goid").Value)
gopc, _ := constant.Int64Val(gvar.fieldVariable("gopc").Value) gopc, _ := constant.Int64Val(gvar.fieldVariable("gopc").Value)
waitReason := constant.StringVal(gvar.fieldVariable("waitreason").Value) waitReason := constant.StringVal(gvar.fieldVariable("waitreason").Value)
stkbarVar, _ := gvar.structMember("stkbar") stkbarVar, _ := gvar.structMember("stkbar")
stkbarPos, _ := constant.Int64Val(gvar.fieldVariable("stkbarPos").Value) stkbarVarPosFld := gvar.fieldVariable("stkbarPos")
var stkbarPos int64
if stkbarVarPosFld != nil { // stack barriers were removed in Go 1.9
stkbarPos, _ = constant.Int64Val(stkbarVarPosFld.Value)
}
status, _ := constant.Int64Val(gvar.fieldVariable("atomicstatus").Value) status, _ := constant.Int64Val(gvar.fieldVariable("atomicstatus").Value)
f, l, fn := gvar.dbp.goSymTable.PCToLine(uint64(pc)) f, l, fn := gvar.dbp.goSymTable.PCToLine(uint64(pc))
g := &G{ g := &G{
@ -498,6 +504,9 @@ func (g *G) Go() Location {
// Returns the list of saved return addresses used by stack barriers // Returns the list of saved return addresses used by stack barriers
func (g *G) stkbar() ([]savedLR, error) { func (g *G) stkbar() ([]savedLR, error) {
if g.stkbarVar == nil { // stack barriers were removed in Go 1.9
return nil, nil
}
g.stkbarVar.loadValue(LoadConfig{false, 1, 0, int(g.stkbarVar.Len), 3}) g.stkbarVar.loadValue(LoadConfig{false, 1, 0, int(g.stkbarVar.Len), 3})
if g.stkbarVar.Unreadable != nil { if g.stkbarVar.Unreadable != nil {
return nil, fmt.Errorf("unreadable stkbar: %v\n", g.stkbarVar.Unreadable) return nil, fmt.Errorf("unreadable stkbar: %v\n", g.stkbarVar.Unreadable)