forked from go-delve/delve
/
reader.go
executable file
·446 lines (377 loc) · 10.8 KB
/
reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
package reader
import (
"debug/dwarf"
"errors"
"fmt"
"github.com/derekparker/delve/pkg/dwarf/op"
)
type Reader struct {
*dwarf.Reader
depth int
}
// New returns a reader for the specified dwarf data.
func New(data *dwarf.Data) *Reader {
return &Reader{data.Reader(), 0}
}
// Seek moves the reader to an arbitrary offset.
func (reader *Reader) Seek(off dwarf.Offset) {
reader.depth = 0
reader.Reader.Seek(off)
}
// SeekToEntry moves the reader to an arbitrary entry.
func (reader *Reader) SeekToEntry(entry *dwarf.Entry) error {
reader.Seek(entry.Offset)
// Consume the current entry so .Next works as intended
_, err := reader.Next()
return err
}
// SeekToFunctionEntry moves the reader to the function that includes the
// specified program counter.
func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) {
reader.Seek(0)
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
if entry.Tag != dwarf.TagSubprogram {
continue
}
lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64)
if !ok {
continue
}
highpc, ok := entry.Val(dwarf.AttrHighpc).(uint64)
if !ok {
continue
}
if lowpc <= pc && highpc > pc {
return entry, nil
}
}
return nil, fmt.Errorf("unable to find function context")
}
// Returns the address for the named entry.
func (reader *Reader) AddrFor(name string) (uint64, error) {
entry, err := reader.FindEntryNamed(name, false)
if err != nil {
return 0, err
}
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
if !ok {
return 0, fmt.Errorf("type assertion failed")
}
addr, _, err := op.ExecuteStackProgram(op.DwarfRegisters{}, instructions)
if err != nil {
return 0, err
}
return uint64(addr), nil
}
// Returns the address for the named struct member. Expects the reader to be at the parent entry
// or one of the parents children, thus does not seek to parent by itself.
func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (uint64, error) {
for {
entry, err := reader.NextMemberVariable()
if err != nil {
return 0, err
}
if entry == nil {
return 0, fmt.Errorf("nil entry for member named %s", member)
}
name, ok := entry.Val(dwarf.AttrName).(string)
if !ok || name != member {
continue
}
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
if !ok {
continue
}
addr, _, err := op.ExecuteStackProgram(op.DwarfRegisters{}, append(initialInstructions, instructions...))
return uint64(addr), err
}
}
var TypeNotFoundErr = errors.New("no type entry found, use 'types' for a list of valid types")
// SeekToType moves the reader to the type specified by the entry,
// optionally resolving typedefs and pointer types. If the reader is set
// to a struct type the NextMemberVariable call can be used to walk all member data.
func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resolvePointerTypes bool) (*dwarf.Entry, error) {
offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
if !ok {
return nil, fmt.Errorf("entry does not have a type attribute")
}
// Seek to the first type offset
reader.Seek(offset)
// Walk the types to the base
for typeEntry, err := reader.Next(); typeEntry != nil; typeEntry, err = reader.Next() {
if err != nil {
return nil, err
}
if typeEntry.Tag == dwarf.TagTypedef && !resolveTypedefs {
return typeEntry, nil
}
if typeEntry.Tag == dwarf.TagPointerType && !resolvePointerTypes {
return typeEntry, nil
}
offset, ok = typeEntry.Val(dwarf.AttrType).(dwarf.Offset)
if !ok {
return typeEntry, nil
}
reader.Seek(offset)
}
return nil, TypeNotFoundErr
}
func (reader *Reader) NextType() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
switch entry.Tag {
case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
return entry, nil
}
}
return nil, nil
}
// SeekToTypeNamed moves the reader to the type specified by the name.
// If the reader is set to a struct type the NextMemberVariable call
// can be used to walk all member data.
func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
// Walk the types to the base
for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() {
if err != nil {
return nil, err
}
n, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
continue
}
if n == name {
return entry, nil
}
}
return nil, TypeNotFoundErr
}
// Finds the entry for 'name'.
func (reader *Reader) FindEntryNamed(name string, member bool) (*dwarf.Entry, error) {
depth := 1
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
if entry.Children {
depth++
}
if entry.Tag == 0 {
depth--
if depth <= 0 {
return nil, fmt.Errorf("could not find symbol value for %s", name)
}
}
if member {
if entry.Tag != dwarf.TagMember {
continue
}
} else {
if entry.Tag != dwarf.TagVariable && entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagStructType {
continue
}
}
n, ok := entry.Val(dwarf.AttrName).(string)
if !ok || n != name {
continue
}
return entry, nil
}
return nil, fmt.Errorf("could not find symbol value for %s", name)
}
func (reader *Reader) InstructionsForEntryNamed(name string, member bool) ([]byte, error) {
entry, err := reader.FindEntryNamed(name, member)
if err != nil {
return nil, err
}
var attr dwarf.Attr
if member {
attr = dwarf.AttrDataMemberLoc
} else {
attr = dwarf.AttrLocation
}
instr, ok := entry.Val(attr).([]byte)
if !ok {
return nil, errors.New("invalid typecast for Dwarf instructions")
}
return instr, nil
}
func (reader *Reader) InstructionsForEntry(entry *dwarf.Entry) ([]byte, error) {
if entry.Tag == dwarf.TagMember {
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
if !ok {
return nil, fmt.Errorf("member data has no data member location attribute")
}
// clone slice to prevent stomping on the dwarf data
return append([]byte{}, instructions...), nil
}
// non-member
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
if !ok {
return nil, fmt.Errorf("entry has no location attribute")
}
// clone slice to prevent stomping on the dwarf data
return append([]byte{}, instructions...), nil
}
// NextMemberVariable moves the reader to the next debug entry that describes a member variable and returns the entry.
func (reader *Reader) NextMemberVariable() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
// All member variables will be at the same depth
reader.SkipChildren()
// End of the current depth
if entry.Tag == 0 {
break
}
if entry.Tag == dwarf.TagMember {
return entry, nil
}
}
// No more items
return nil, nil
}
// NextPackageVariable moves the reader to the next debug entry that describes a package variable.
// Any TagVariable entry that is not inside a sub prgram entry and is marked external is considered a package variable.
func (reader *Reader) NextPackageVariable() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
if entry.Tag == dwarf.TagVariable {
ext, ok := entry.Val(dwarf.AttrExternal).(bool)
if ok && ext {
return entry, nil
}
}
// Ignore everything inside sub programs
if entry.Tag == dwarf.TagSubprogram {
reader.SkipChildren()
}
}
// No more items
return nil, nil
}
func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
if entry.Tag == dwarf.TagCompileUnit {
return entry, nil
}
}
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
}
// InlineStackReader provides a way to read the stack of inlined calls at a
// specified PC address.
type InlineStackReader struct {
dwarf *dwarf.Data
reader *dwarf.Reader
entry *dwarf.Entry
depth int
pc uint64
err error
}
// InlineStack returns an InlineStackReader for the specified function and
// PC address.
// If pc is 0 then all inlined calls will be returned.
func InlineStack(dwarf *dwarf.Data, fnoff dwarf.Offset, pc uint64) *InlineStackReader {
reader := dwarf.Reader()
reader.Seek(fnoff)
return &InlineStackReader{dwarf: dwarf, reader: reader, entry: nil, depth: 0, pc: pc}
}
// Next reads next inlined call in the stack, returns false if there aren't any.
func (irdr *InlineStackReader) Next() bool {
if irdr.err != nil {
return false
}
for {
irdr.entry, irdr.err = irdr.reader.Next()
if irdr.entry == nil || irdr.err != nil {
return false
}
switch irdr.entry.Tag {
case 0:
irdr.depth--
if irdr.depth == 0 {
return false
}
case dwarf.TagLexDwarfBlock, dwarf.TagSubprogram, dwarf.TagInlinedSubroutine:
var recur bool
if irdr.pc != 0 {
recur, irdr.err = entryRangesContains(irdr.dwarf, irdr.entry, irdr.pc)
} else {
recur = true
}
if recur {
irdr.depth++
if irdr.entry.Tag == dwarf.TagInlinedSubroutine {
return true
}
} else {
if irdr.depth == 0 {
return false
}
irdr.reader.SkipChildren()
}
default:
irdr.reader.SkipChildren()
}
}
}
// Entry returns the DIE for the current inlined call.
func (irdr *InlineStackReader) Entry() *dwarf.Entry {
return irdr.entry
}
// Err returns an error, if any was encountered.
func (irdr *InlineStackReader) Err() error {
return irdr.err
}
// SkipChildren skips all children of the current inlined call.
func (irdr *InlineStackReader) SkipChildren() {
irdr.reader.SkipChildren()
}