Skip to content

Commit 0c40a8f

Browse files
aarzilliderekparker
authored andcommitted
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.
1 parent be62813 commit 0c40a8f

File tree

10 files changed

+84
-21
lines changed

10 files changed

+84
-21
lines changed

pkg/dwarf/reader/reader.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,49 @@ func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) {
319319

320320
return nil, nil
321321
}
322+
323+
// Entry represents a debug_info entry.
324+
// When calling Val, if the entry does not have the specified attribute, the
325+
// entry specified by DW_AT_abstract_origin will be searched recursively.
326+
type Entry interface {
327+
Val(dwarf.Attr) interface{}
328+
}
329+
330+
type compositeEntry []*dwarf.Entry
331+
332+
func (ce compositeEntry) Val(attr dwarf.Attr) interface{} {
333+
for _, e := range ce {
334+
if r := e.Val(attr); r != nil {
335+
return r
336+
}
337+
}
338+
return nil
339+
}
340+
341+
// LoadAbstractOrigin loads the entry corresponding to the
342+
// DW_AT_abstract_origin of entry and returns a combination of entry and its
343+
// abstract origin.
344+
func LoadAbstractOrigin(entry *dwarf.Entry, aordr *dwarf.Reader) (Entry, dwarf.Offset) {
345+
ao, ok := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
346+
if !ok {
347+
return entry, entry.Offset
348+
}
349+
350+
r := []*dwarf.Entry{entry}
351+
352+
for {
353+
aordr.Seek(ao)
354+
e, _ := aordr.Next()
355+
if e == nil {
356+
break
357+
}
358+
r = append(r, e)
359+
360+
ao, ok = e.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
361+
if !ok {
362+
break
363+
}
364+
}
365+
366+
return compositeEntry(r), entry.Offset
367+
}

pkg/proc/bininfo.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ type BinaryInfo struct {
5959

6060
loadErrMu sync.Mutex
6161
loadErr error
62+
63+
dwarfReader *dwarf.Reader
6264
}
6365

6466
var UnsupportedLinuxArchErr = errors.New("unsupported architecture - only linux/amd64 is supported")
@@ -342,7 +344,7 @@ func (bi *BinaryInfo) loclistInit(data []byte) {
342344
// This will either be an int64 address or a slice of Pieces for locations
343345
// that don't correspond to a single memory address (registers, composite
344346
// locations).
345-
func (bi *BinaryInfo) Location(entry *dwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, string, error) {
347+
func (bi *BinaryInfo) Location(entry reader.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, string, error) {
346348
a := entry.Val(attr)
347349
if a == nil {
348350
return 0, nil, "", fmt.Errorf("no location attribute %s", attr)
@@ -425,6 +427,8 @@ func (bi *BinaryInfo) LoadBinaryInfoElf(path string, wg *sync.WaitGroup) error {
425427
return err
426428
}
427429

430+
bi.dwarfReader = bi.dwarf.Reader()
431+
428432
debugLineBytes, err := getDebugLineInfoElf(elfFile)
429433
if err != nil {
430434
return err
@@ -535,6 +539,8 @@ func (bi *BinaryInfo) LoadBinaryInfoPE(path string, wg *sync.WaitGroup) error {
535539
return err
536540
}
537541

542+
bi.dwarfReader = bi.dwarf.Reader()
543+
538544
debugLineBytes, err := getDebugLineInfoPE(peFile)
539545
if err != nil {
540546
return err
@@ -701,6 +707,8 @@ func (bi *BinaryInfo) LoadBinaryInfoMacho(path string, wg *sync.WaitGroup) error
701707
return err
702708
}
703709

710+
bi.dwarfReader = bi.dwarf.Reader()
711+
704712
debugLineBytes, err := getDebugLineInfoMacho(exe)
705713
if err != nil {
706714
return err

pkg/proc/core/core_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ func TestCore(t *testing.T) {
197197
if mainFrame == nil {
198198
t.Fatalf("Couldn't find main in stack %v", panickingStack)
199199
}
200-
msg, err := proc.FrameToScope(p, *mainFrame).EvalVariable("msg", proc.LoadConfig{MaxStringLen: 64})
200+
msg, err := proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, *mainFrame).EvalVariable("msg", proc.LoadConfig{MaxStringLen: 64})
201201
if err != nil {
202202
t.Fatalf("Couldn't EvalVariable(msg, ...): %v", err)
203203
}

pkg/proc/moduledata.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package proc
33
import (
44
"go/constant"
55
"unsafe"
6-
7-
"github.com/derekparker/delve/pkg/dwarf/op"
86
)
97

108
// delve counterpart to runtime.moduledata
@@ -15,7 +13,7 @@ type moduleData struct {
1513

1614
func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) (err error) {
1715
bi.loadModuleDataOnce.Do(func() {
18-
scope := &EvalScope{0, op.DwarfRegisters{}, mem, nil, bi, 0}
16+
scope := globalScope(bi, mem)
1917
var md *Variable
2018
md, err = scope.findGlobal("runtime.firstmoduledata")
2119
if err != nil {
@@ -121,7 +119,7 @@ func resolveNameOff(bi *BinaryInfo, typeAddr uintptr, off uintptr, mem MemoryRea
121119
}
122120

123121
func reflectOffsMapAccess(bi *BinaryInfo, off uintptr, mem MemoryReadWriter) (*Variable, error) {
124-
scope := &EvalScope{0, op.DwarfRegisters{}, mem, nil, bi, 0}
122+
scope := globalScope(bi, mem)
125123
reflectOffs, err := scope.findGlobal("runtime.reflectOffs")
126124
if err != nil {
127125
return nil, err

pkg/proc/proc.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,15 @@ func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) {
482482
return nil, fmt.Errorf("Frame %d does not exist in goroutine %d", frame, gid)
483483
}
484484

485-
return &EvalScope{locs[frame].Current.PC, locs[frame].Regs, thread, g.variable, dbp.BinInfo(), locs[frame].FrameOffset()}, nil
485+
return FrameToScope(dbp.BinInfo(), thread, g, locs[frame]), nil
486486
}
487487

488488
// FrameToScope returns a new EvalScope for this frame
489-
func FrameToScope(p Process, frame Stackframe) *EvalScope {
490-
return &EvalScope{frame.Current.PC, frame.Regs, p.CurrentThread(), nil, p.BinInfo(), frame.FrameOffset()}
489+
func FrameToScope(bi *BinaryInfo, thread MemoryReadWriter, g *G, frame Stackframe) *EvalScope {
490+
var gvar *Variable
491+
if g != nil {
492+
gvar = g.variable
493+
}
494+
s := &EvalScope{PC: frame.Call.PC, Regs: frame.Regs, Mem: thread, Gvar: gvar, BinInfo: bi, frameOffset: frame.FrameOffset()}
495+
return s
491496
}

pkg/proc/proc_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,7 @@ func evalVariableOrError(p proc.Process, symbol string) (*proc.Variable, error)
11191119
var frame proc.Stackframe
11201120
frame, err = findFirstNonRuntimeFrame(p)
11211121
if err == nil {
1122-
scope = proc.FrameToScope(p, frame)
1122+
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
11231123
}
11241124
} else {
11251125
scope, err = proc.GoroutineScope(p.CurrentThread())
@@ -2931,7 +2931,7 @@ func TestIssue871(t *testing.T) {
29312931
var frame proc.Stackframe
29322932
frame, err = findFirstNonRuntimeFrame(p)
29332933
if err == nil {
2934-
scope = proc.FrameToScope(p, frame)
2934+
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
29352935
}
29362936
} else {
29372937
scope, err = proc.GoroutineScope(p.CurrentThread())
@@ -3345,7 +3345,7 @@ func TestIssue1034(t *testing.T) {
33453345
assertNoError(proc.Continue(p), t, "Continue()")
33463346
frames, err := p.SelectedGoroutine().Stacktrace(10)
33473347
assertNoError(err, t, "Stacktrace")
3348-
scope := proc.FrameToScope(p, frames[2])
3348+
scope := proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frames[2])
33493349
args, _ := scope.FunctionArguments(normalLoadConfig)
33503350
assertNoError(err, t, "FunctionArguments()")
33513351
if len(args) > 0 {

pkg/proc/threads.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ func ThreadScope(thread Thread) (*EvalScope, error) {
398398
if len(locations) < 1 {
399399
return nil, errors.New("could not decode first frame")
400400
}
401-
return &EvalScope{locations[0].Current.PC, locations[0].Regs, thread, nil, thread.BinInfo(), 0}, nil
401+
return FrameToScope(thread.BinInfo(), thread, nil, locations[0]), nil
402402
}
403403

404404
// GoroutineScope returns an EvalScope for the goroutine running on this thread.
@@ -414,7 +414,7 @@ func GoroutineScope(thread Thread) (*EvalScope, error) {
414414
if err != nil {
415415
return nil, err
416416
}
417-
return &EvalScope{locations[0].Current.PC, locations[0].Regs, thread, g.variable, thread.BinInfo(), locations[0].FrameOffset()}, nil
417+
return FrameToScope(thread.BinInfo(), thread, g, locations[0]), nil
418418
}
419419

420420
func onRuntimeBreakpoint(thread Thread) bool {

pkg/proc/variables.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@ func (err *IsNilErr) Error() string {
174174
return fmt.Sprintf("%s is nil", err.name)
175175
}
176176

177+
func globalScope(bi *BinaryInfo, mem MemoryReadWriter) *EvalScope {
178+
return &EvalScope{PC: 0, Regs: op.DwarfRegisters{}, Mem: mem, Gvar: nil, BinInfo: bi, frameOffset: 0}
179+
}
180+
177181
func (scope *EvalScope) newVariable(name string, addr uintptr, dwarfType godwarf.Type, mem MemoryReadWriter) *Variable {
178182
return newVariable(name, addr, dwarfType, scope.BinInfo, mem)
179183
}
@@ -749,15 +753,17 @@ func (v *Variable) structMember(memberName string) (*Variable, error) {
749753

750754
// Extracts the name and type of a variable from a dwarf entry
751755
// then executes the instructions given in the DW_AT_location attribute to grab the variable's address
752-
func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable, error) {
753-
if entry == nil {
756+
func (scope *EvalScope) extractVarInfoFromEntry(varEntry *dwarf.Entry) (*Variable, error) {
757+
if varEntry == nil {
754758
return nil, fmt.Errorf("invalid entry")
755759
}
756760

757-
if entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagVariable {
758-
return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", entry.Tag.String())
761+
if varEntry.Tag != dwarf.TagFormalParameter && varEntry.Tag != dwarf.TagVariable {
762+
return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", varEntry.Tag.String())
759763
}
760764

765+
entry, _ := reader.LoadAbstractOrigin(varEntry, scope.BinInfo.dwarfReader)
766+
761767
n, ok := entry.Val(dwarf.AttrName).(string)
762768
if !ok {
763769
return nil, fmt.Errorf("type assertion failed")

service/debugger/debugger.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadCo
868868
}
869869
if cfg != nil && rawlocs[i].Current.Fn != nil {
870870
var err error
871-
scope := proc.FrameToScope(d.target, rawlocs[i])
871+
scope := proc.FrameToScope(d.target.BinInfo(), d.target.CurrentThread(), nil, rawlocs[i])
872872
locals, err := scope.LocalVariables(*cfg)
873873
if err != nil {
874874
return nil, err

service/test/variables_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func evalVariable(p proc.Process, symbol string, cfg proc.LoadConfig) (*proc.Var
7878
var frame proc.Stackframe
7979
frame, err = findFirstNonRuntimeFrame(p)
8080
if err == nil {
81-
scope = proc.FrameToScope(p, frame)
81+
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
8282
}
8383
} else {
8484
scope, err = proc.GoroutineScope(p.CurrentThread())
@@ -405,7 +405,7 @@ func TestLocalVariables(t *testing.T) {
405405
var frame proc.Stackframe
406406
frame, err = findFirstNonRuntimeFrame(p)
407407
if err == nil {
408-
scope = proc.FrameToScope(p, frame)
408+
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
409409
}
410410
} else {
411411
scope, err = proc.GoroutineScope(p.CurrentThread())

0 commit comments

Comments
 (0)