mirror of
https://github.com/go-delve/delve.git
synced 2025-10-29 01:27:16 +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
|
FixFrameUnwindContext(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext
|
||||||
RegSize(uint64) int
|
RegSize(uint64) int
|
||||||
RegistersToDwarfRegisters(uint64, Registers) op.DwarfRegisters
|
RegistersToDwarfRegisters(uint64, Registers) op.DwarfRegisters
|
||||||
GoroutineToDwarfRegisters(*G) op.DwarfRegisters
|
AddrAndStackRegsToDwarfRegisters(uint64, uint64, uint64, uint64) op.DwarfRegisters
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMD64 represents the AMD64 CPU architecture.
|
// 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
|
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
|
||||||
// goroutine in the format used by the DWARF expression interpreter.
|
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
||||||
func (a *AMD64) GoroutineToDwarfRegisters(g *G) op.DwarfRegisters {
|
func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp uint64) op.DwarfRegisters {
|
||||||
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
|
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
|
||||||
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(g.PC)
|
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
||||||
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(g.SP)
|
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
||||||
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(g.BP)
|
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
|
||||||
|
|
||||||
so := g.variable.bi.PCToImage(g.PC)
|
return op.DwarfRegisters{
|
||||||
|
StaticBase: staticBase,
|
||||||
return op.DwarfRegisters{StaticBase: so.StaticBase, Regs: dregs, ByteOrder: binary.LittleEndian, PCRegNum: amd64DwarfIPRegNum, SPRegNum: amd64DwarfSPRegNum, BPRegNum: amd64DwarfBPRegNum}
|
Regs: dregs,
|
||||||
|
ByteOrder: binary.LittleEndian,
|
||||||
|
PCRegNum: amd64DwarfIPRegNum,
|
||||||
|
SPRegNum: amd64DwarfSPRegNum,
|
||||||
|
BPRegNum: amd64DwarfBPRegNum,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,9 +119,16 @@ func (g *G) stackIterator() (*stackIterator, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
so := g.variable.bi.PCToImage(regs.PC())
|
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.
|
// Stacktrace returns the stack trace for a goroutine.
|
||||||
|
|||||||
@ -213,6 +213,60 @@ type G struct {
|
|||||||
Unreadable error // could not read the 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 {
|
type Ancestor struct {
|
||||||
ID int64 // Goroutine ID
|
ID int64 // Goroutine ID
|
||||||
Unreadable error
|
Unreadable error
|
||||||
@ -601,20 +655,6 @@ func (v *Variable) fieldVariable(name string) *Variable {
|
|||||||
return nil
|
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
|
// From $GOROOT/src/runtime/traceback.go:597
|
||||||
// isExportedRuntime reports whether name is an exported runtime function.
|
// isExportedRuntime reports whether name is an exported runtime function.
|
||||||
// It is only for runtime functions, so ASCII A-Z is fine.
|
// 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'
|
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")
|
var errTracebackAncestorsDisabled = errors.New("tracebackancestors is disabled")
|
||||||
|
|
||||||
// Ancestors returns the list of ancestors for g.
|
// Ancestors returns the list of ancestors for g.
|
||||||
|
|||||||
Reference in New Issue
Block a user