提交 0c40a8f5 编写于 作者: A Alessandro Arzilli 提交者: Derek Parker

dwarf/reader,proc: support DW_AT_abstract_origin (#1111)

debug_info entries can use DW_AT_abstract_origin to inherit the
attributes of another entry, supporting this attribute is necessary to
support DW_TAG_inlined_subroutine.

Go, starting with 1.10, emits DW_TAG_inlined_subroutine entries when
inlining is enabled.
上级 be628132
......@@ -319,3 +319,49 @@ func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) {
return nil, nil
}
// Entry represents a debug_info entry.
// When calling Val, if the entry does not have the specified attribute, the
// entry specified by DW_AT_abstract_origin will be searched recursively.
type Entry interface {
Val(dwarf.Attr) interface{}
}
type compositeEntry []*dwarf.Entry
func (ce compositeEntry) Val(attr dwarf.Attr) interface{} {
for _, e := range ce {
if r := e.Val(attr); r != nil {
return r
}
}
return nil
}
// LoadAbstractOrigin loads the entry corresponding to the
// DW_AT_abstract_origin of entry and returns a combination of entry and its
// abstract origin.
func LoadAbstractOrigin(entry *dwarf.Entry, aordr *dwarf.Reader) (Entry, dwarf.Offset) {
ao, ok := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
if !ok {
return entry, entry.Offset
}
r := []*dwarf.Entry{entry}
for {
aordr.Seek(ao)
e, _ := aordr.Next()
if e == nil {
break
}
r = append(r, e)
ao, ok = e.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
if !ok {
break
}
}
return compositeEntry(r), entry.Offset
}
......@@ -59,6 +59,8 @@ type BinaryInfo struct {
loadErrMu sync.Mutex
loadErr error
dwarfReader *dwarf.Reader
}
var UnsupportedLinuxArchErr = errors.New("unsupported architecture - only linux/amd64 is supported")
......@@ -342,7 +344,7 @@ func (bi *BinaryInfo) loclistInit(data []byte) {
// This will either be an int64 address or a slice of Pieces for locations
// that don't correspond to a single memory address (registers, composite
// locations).
func (bi *BinaryInfo) Location(entry *dwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, string, error) {
func (bi *BinaryInfo) Location(entry reader.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, string, error) {
a := entry.Val(attr)
if a == nil {
return 0, nil, "", fmt.Errorf("no location attribute %s", attr)
......@@ -425,6 +427,8 @@ func (bi *BinaryInfo) LoadBinaryInfoElf(path string, wg *sync.WaitGroup) error {
return err
}
bi.dwarfReader = bi.dwarf.Reader()
debugLineBytes, err := getDebugLineInfoElf(elfFile)
if err != nil {
return err
......@@ -535,6 +539,8 @@ func (bi *BinaryInfo) LoadBinaryInfoPE(path string, wg *sync.WaitGroup) error {
return err
}
bi.dwarfReader = bi.dwarf.Reader()
debugLineBytes, err := getDebugLineInfoPE(peFile)
if err != nil {
return err
......@@ -701,6 +707,8 @@ func (bi *BinaryInfo) LoadBinaryInfoMacho(path string, wg *sync.WaitGroup) error
return err
}
bi.dwarfReader = bi.dwarf.Reader()
debugLineBytes, err := getDebugLineInfoMacho(exe)
if err != nil {
return err
......
......@@ -197,7 +197,7 @@ func TestCore(t *testing.T) {
if mainFrame == nil {
t.Fatalf("Couldn't find main in stack %v", panickingStack)
}
msg, err := proc.FrameToScope(p, *mainFrame).EvalVariable("msg", proc.LoadConfig{MaxStringLen: 64})
msg, err := proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, *mainFrame).EvalVariable("msg", proc.LoadConfig{MaxStringLen: 64})
if err != nil {
t.Fatalf("Couldn't EvalVariable(msg, ...): %v", err)
}
......
......@@ -3,8 +3,6 @@ package proc
import (
"go/constant"
"unsafe"
"github.com/derekparker/delve/pkg/dwarf/op"
)
// delve counterpart to runtime.moduledata
......@@ -15,7 +13,7 @@ type moduleData struct {
func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) (err error) {
bi.loadModuleDataOnce.Do(func() {
scope := &EvalScope{0, op.DwarfRegisters{}, mem, nil, bi, 0}
scope := globalScope(bi, mem)
var md *Variable
md, err = scope.findGlobal("runtime.firstmoduledata")
if err != nil {
......@@ -121,7 +119,7 @@ func resolveNameOff(bi *BinaryInfo, typeAddr uintptr, off uintptr, mem MemoryRea
}
func reflectOffsMapAccess(bi *BinaryInfo, off uintptr, mem MemoryReadWriter) (*Variable, error) {
scope := &EvalScope{0, op.DwarfRegisters{}, mem, nil, bi, 0}
scope := globalScope(bi, mem)
reflectOffs, err := scope.findGlobal("runtime.reflectOffs")
if err != nil {
return nil, err
......
......@@ -482,10 +482,15 @@ func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) {
return nil, fmt.Errorf("Frame %d does not exist in goroutine %d", frame, gid)
}
return &EvalScope{locs[frame].Current.PC, locs[frame].Regs, thread, g.variable, dbp.BinInfo(), locs[frame].FrameOffset()}, nil
return FrameToScope(dbp.BinInfo(), thread, g, locs[frame]), nil
}
// FrameToScope returns a new EvalScope for this frame
func FrameToScope(p Process, frame Stackframe) *EvalScope {
return &EvalScope{frame.Current.PC, frame.Regs, p.CurrentThread(), nil, p.BinInfo(), frame.FrameOffset()}
func FrameToScope(bi *BinaryInfo, thread MemoryReadWriter, g *G, frame Stackframe) *EvalScope {
var gvar *Variable
if g != nil {
gvar = g.variable
}
s := &EvalScope{PC: frame.Call.PC, Regs: frame.Regs, Mem: thread, Gvar: gvar, BinInfo: bi, frameOffset: frame.FrameOffset()}
return s
}
......@@ -1119,7 +1119,7 @@ func evalVariableOrError(p proc.Process, symbol string) (*proc.Variable, error)
var frame proc.Stackframe
frame, err = findFirstNonRuntimeFrame(p)
if err == nil {
scope = proc.FrameToScope(p, frame)
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
}
} else {
scope, err = proc.GoroutineScope(p.CurrentThread())
......@@ -2931,7 +2931,7 @@ func TestIssue871(t *testing.T) {
var frame proc.Stackframe
frame, err = findFirstNonRuntimeFrame(p)
if err == nil {
scope = proc.FrameToScope(p, frame)
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
}
} else {
scope, err = proc.GoroutineScope(p.CurrentThread())
......@@ -3345,7 +3345,7 @@ func TestIssue1034(t *testing.T) {
assertNoError(proc.Continue(p), t, "Continue()")
frames, err := p.SelectedGoroutine().Stacktrace(10)
assertNoError(err, t, "Stacktrace")
scope := proc.FrameToScope(p, frames[2])
scope := proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frames[2])
args, _ := scope.FunctionArguments(normalLoadConfig)
assertNoError(err, t, "FunctionArguments()")
if len(args) > 0 {
......
......@@ -398,7 +398,7 @@ func ThreadScope(thread Thread) (*EvalScope, error) {
if len(locations) < 1 {
return nil, errors.New("could not decode first frame")
}
return &EvalScope{locations[0].Current.PC, locations[0].Regs, thread, nil, thread.BinInfo(), 0}, nil
return FrameToScope(thread.BinInfo(), thread, nil, locations[0]), nil
}
// GoroutineScope returns an EvalScope for the goroutine running on this thread.
......@@ -414,7 +414,7 @@ func GoroutineScope(thread Thread) (*EvalScope, error) {
if err != nil {
return nil, err
}
return &EvalScope{locations[0].Current.PC, locations[0].Regs, thread, g.variable, thread.BinInfo(), locations[0].FrameOffset()}, nil
return FrameToScope(thread.BinInfo(), thread, g, locations[0]), nil
}
func onRuntimeBreakpoint(thread Thread) bool {
......
......@@ -174,6 +174,10 @@ func (err *IsNilErr) Error() string {
return fmt.Sprintf("%s is nil", err.name)
}
func globalScope(bi *BinaryInfo, mem MemoryReadWriter) *EvalScope {
return &EvalScope{PC: 0, Regs: op.DwarfRegisters{}, Mem: mem, Gvar: nil, BinInfo: bi, frameOffset: 0}
}
func (scope *EvalScope) newVariable(name string, addr uintptr, dwarfType godwarf.Type, mem MemoryReadWriter) *Variable {
return newVariable(name, addr, dwarfType, scope.BinInfo, mem)
}
......@@ -749,15 +753,17 @@ func (v *Variable) structMember(memberName string) (*Variable, error) {
// Extracts the name and type of a variable from a dwarf entry
// then executes the instructions given in the DW_AT_location attribute to grab the variable's address
func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable, error) {
if entry == nil {
func (scope *EvalScope) extractVarInfoFromEntry(varEntry *dwarf.Entry) (*Variable, error) {
if varEntry == nil {
return nil, fmt.Errorf("invalid entry")
}
if entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagVariable {
return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", entry.Tag.String())
if varEntry.Tag != dwarf.TagFormalParameter && varEntry.Tag != dwarf.TagVariable {
return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", varEntry.Tag.String())
}
entry, _ := reader.LoadAbstractOrigin(varEntry, scope.BinInfo.dwarfReader)
n, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
return nil, fmt.Errorf("type assertion failed")
......
......@@ -868,7 +868,7 @@ func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadCo
}
if cfg != nil && rawlocs[i].Current.Fn != nil {
var err error
scope := proc.FrameToScope(d.target, rawlocs[i])
scope := proc.FrameToScope(d.target.BinInfo(), d.target.CurrentThread(), nil, rawlocs[i])
locals, err := scope.LocalVariables(*cfg)
if err != nil {
return nil, err
......
......@@ -78,7 +78,7 @@ func evalVariable(p proc.Process, symbol string, cfg proc.LoadConfig) (*proc.Var
var frame proc.Stackframe
frame, err = findFirstNonRuntimeFrame(p)
if err == nil {
scope = proc.FrameToScope(p, frame)
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
}
} else {
scope, err = proc.GoroutineScope(p.CurrentThread())
......@@ -405,7 +405,7 @@ func TestLocalVariables(t *testing.T) {
var frame proc.Stackframe
frame, err = findFirstNonRuntimeFrame(p)
if err == nil {
scope = proc.FrameToScope(p, frame)
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
}
} else {
scope, err = proc.GoroutineScope(p.CurrentThread())
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册