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
2019-08-07 20:44:37 -07:00
committed by Alessandro Arzilli
parent 2de4930ad1
commit 583d335ffe
3 changed files with 78 additions and 66 deletions

View File

@ -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,
}
}

View File

@ -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.

View File

@ -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.