mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +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
	 dr2chase
					dr2chase