mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	pkg/proc: Untangle Arch from G struct
More untangling. Arch doesn't actually need to know anything about a Goroutine.
This commit is contained in:
		 Derek Parker
					Derek Parker
				
			
				
					committed by
					
						 Alessandro Arzilli
						Alessandro Arzilli
					
				
			
			
				
	
			
			
			 Alessandro Arzilli
						Alessandro Arzilli
					
				
			
						parent
						
							2de4930ad1
						
					
				
				
					commit
					583d335ffe
				
			| @ -18,7 +18,7 @@ type Arch interface { | ||||
| 	FixFrameUnwindContext(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext | ||||
| 	RegSize(uint64) int | ||||
| 	RegistersToDwarfRegisters(uint64, Registers) op.DwarfRegisters | ||||
| 	GoroutineToDwarfRegisters(*G) op.DwarfRegisters | ||||
| 	AddrAndStackRegsToDwarfRegisters(uint64, uint64, uint64, uint64) op.DwarfRegisters | ||||
| } | ||||
|  | ||||
| // AMD64 represents the AMD64 CPU architecture. | ||||
| @ -293,15 +293,20 @@ func (a *AMD64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op. | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GoroutineToDwarfRegisters extract the saved DWARF registers from a parked | ||||
| // goroutine in the format used by the DWARF expression interpreter. | ||||
| func (a *AMD64) GoroutineToDwarfRegisters(g *G) op.DwarfRegisters { | ||||
| // AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in | ||||
| // PC, SP, and BP registers in the format used by the DWARF expression interpreter. | ||||
| func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp uint64) op.DwarfRegisters { | ||||
| 	dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1) | ||||
| 	dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(g.PC) | ||||
| 	dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(g.SP) | ||||
| 	dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(g.BP) | ||||
| 	dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc) | ||||
| 	dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp) | ||||
| 	dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp) | ||||
|  | ||||
| 	so := g.variable.bi.PCToImage(g.PC) | ||||
|  | ||||
| 	return op.DwarfRegisters{StaticBase: so.StaticBase, Regs: dregs, ByteOrder: binary.LittleEndian, PCRegNum: amd64DwarfIPRegNum, SPRegNum: amd64DwarfSPRegNum, BPRegNum: amd64DwarfBPRegNum} | ||||
| 	return op.DwarfRegisters{ | ||||
| 		StaticBase: staticBase, | ||||
| 		Regs:       dregs, | ||||
| 		ByteOrder:  binary.LittleEndian, | ||||
| 		PCRegNum:   amd64DwarfIPRegNum, | ||||
| 		SPRegNum:   amd64DwarfSPRegNum, | ||||
| 		BPRegNum:   amd64DwarfBPRegNum, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -119,9 +119,16 @@ func (g *G) stackIterator() (*stackIterator, error) { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		so := g.variable.bi.PCToImage(regs.PC()) | ||||
| 		return newStackIterator(g.variable.bi, g.Thread, g.variable.bi.Arch.RegistersToDwarfRegisters(so.StaticBase, regs), g.stackhi, stkbar, g.stkbarPos, g), nil | ||||
| 		return newStackIterator( | ||||
| 			g.variable.bi, g.Thread, | ||||
| 			g.variable.bi.Arch.RegistersToDwarfRegisters(so.StaticBase, regs), | ||||
| 			g.stackhi, stkbar, g.stkbarPos, g), nil | ||||
| 	} | ||||
| 	return newStackIterator(g.variable.bi, g.variable.mem, g.variable.bi.Arch.GoroutineToDwarfRegisters(g), g.stackhi, stkbar, g.stkbarPos, g), nil | ||||
| 	so := g.variable.bi.PCToImage(g.PC) | ||||
| 	return newStackIterator( | ||||
| 		g.variable.bi, g.variable.mem, | ||||
| 		g.variable.bi.Arch.AddrAndStackRegsToDwarfRegisters(so.StaticBase, g.PC, g.SP, g.BP), | ||||
| 		g.stackhi, stkbar, g.stkbarPos, g), nil | ||||
| } | ||||
|  | ||||
| // Stacktrace returns the stack trace for a goroutine. | ||||
|  | ||||
| @ -213,6 +213,60 @@ type G struct { | ||||
| 	Unreadable error // could not read the G struct | ||||
| } | ||||
|  | ||||
| // Defer returns the top-most defer of the goroutine. | ||||
| func (g *G) Defer() *Defer { | ||||
| 	if g.variable.Unreadable != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	dvar := g.variable.fieldVariable("_defer").maybeDereference() | ||||
| 	if dvar.Addr == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	d := &Defer{variable: dvar} | ||||
| 	d.load() | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| // UserCurrent returns the location the users code is at, | ||||
| // or was at before entering a runtime function. | ||||
| func (g *G) UserCurrent() Location { | ||||
| 	it, err := g.stackIterator() | ||||
| 	if err != nil { | ||||
| 		return g.CurrentLoc | ||||
| 	} | ||||
| 	for it.Next() { | ||||
| 		frame := it.Frame() | ||||
| 		if frame.Call.Fn != nil { | ||||
| 			name := frame.Call.Fn.Name | ||||
| 			if strings.Contains(name, ".") && (!strings.HasPrefix(name, "runtime.") || isExportedRuntime(name)) { | ||||
| 				return frame.Call | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return g.CurrentLoc | ||||
| } | ||||
|  | ||||
| // Go returns the location of the 'go' statement | ||||
| // that spawned this goroutine. | ||||
| func (g *G) Go() Location { | ||||
| 	pc := g.GoPC | ||||
| 	if fn := g.variable.bi.PCToFunc(pc); fn != nil { | ||||
| 		// Backup to CALL instruction. | ||||
| 		// Mimics runtime/traceback.go:677. | ||||
| 		if g.GoPC > fn.Entry { | ||||
| 			pc-- | ||||
| 		} | ||||
| 	} | ||||
| 	f, l, fn := g.variable.bi.PCToLine(pc) | ||||
| 	return Location{PC: g.GoPC, File: f, Line: l, Fn: fn} | ||||
| } | ||||
|  | ||||
| // StartLoc returns the starting location of the goroutine. | ||||
| func (g *G) StartLoc() Location { | ||||
| 	f, l, fn := g.variable.bi.PCToLine(g.StartPC) | ||||
| 	return Location{PC: g.StartPC, File: f, Line: l, Fn: fn} | ||||
| } | ||||
|  | ||||
| type Ancestor struct { | ||||
| 	ID         int64 // Goroutine ID | ||||
| 	Unreadable error | ||||
| @ -601,20 +655,6 @@ func (v *Variable) fieldVariable(name string) *Variable { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Defer returns the top-most defer of the goroutine. | ||||
| func (g *G) Defer() *Defer { | ||||
| 	if g.variable.Unreadable != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	dvar := g.variable.fieldVariable("_defer").maybeDereference() | ||||
| 	if dvar.Addr == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	d := &Defer{variable: dvar} | ||||
| 	d.load() | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| // From $GOROOT/src/runtime/traceback.go:597 | ||||
| // isExportedRuntime reports whether name is an exported runtime function. | ||||
| // It is only for runtime functions, so ASCII A-Z is fine. | ||||
| @ -623,46 +663,6 @@ func isExportedRuntime(name string) bool { | ||||
| 	return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' | ||||
| } | ||||
|  | ||||
| // UserCurrent returns the location the users code is at, | ||||
| // or was at before entering a runtime function. | ||||
| func (g *G) UserCurrent() Location { | ||||
| 	it, err := g.stackIterator() | ||||
| 	if err != nil { | ||||
| 		return g.CurrentLoc | ||||
| 	} | ||||
| 	for it.Next() { | ||||
| 		frame := it.Frame() | ||||
| 		if frame.Call.Fn != nil { | ||||
| 			name := frame.Call.Fn.Name | ||||
| 			if strings.Contains(name, ".") && (!strings.HasPrefix(name, "runtime.") || isExportedRuntime(name)) { | ||||
| 				return frame.Call | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return g.CurrentLoc | ||||
| } | ||||
|  | ||||
| // Go returns the location of the 'go' statement | ||||
| // that spawned this goroutine. | ||||
| func (g *G) Go() Location { | ||||
| 	pc := g.GoPC | ||||
| 	if fn := g.variable.bi.PCToFunc(pc); fn != nil { | ||||
| 		// Backup to CALL instruction. | ||||
| 		// Mimics runtime/traceback.go:677. | ||||
| 		if g.GoPC > fn.Entry { | ||||
| 			pc-- | ||||
| 		} | ||||
| 	} | ||||
| 	f, l, fn := g.variable.bi.PCToLine(pc) | ||||
| 	return Location{PC: g.GoPC, File: f, Line: l, Fn: fn} | ||||
| } | ||||
|  | ||||
| // StartLoc returns the starting location of the goroutine. | ||||
| func (g *G) StartLoc() Location { | ||||
| 	f, l, fn := g.variable.bi.PCToLine(g.StartPC) | ||||
| 	return Location{PC: g.StartPC, File: f, Line: l, Fn: fn} | ||||
| } | ||||
|  | ||||
| var errTracebackAncestorsDisabled = errors.New("tracebackancestors is disabled") | ||||
|  | ||||
| // Ancestors returns the list of ancestors for g. | ||||
|  | ||||
		Reference in New Issue
	
	Block a user