mirror of
https://github.com/go-delve/delve.git
synced 2025-10-29 17:56:45 +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:
committed by
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