mirror of
https://github.com/go-delve/delve.git
synced 2025-11-01 03:42:59 +08:00
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:
@ -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")
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user