1
2
3
4
5 package dwtest
6
7 import (
8 "debug/dwarf"
9 "errors"
10 "fmt"
11 "os"
12 )
13
14
15
16
17
18
19
20
21 type Examiner struct {
22 dies []*dwarf.Entry
23 idxByOffset map[dwarf.Offset]int
24 kids map[int][]int
25 parent map[int]int
26 byname map[string][]int
27 }
28
29
30 func (ex *Examiner) Populate(rdr *dwarf.Reader) error {
31 ex.idxByOffset = make(map[dwarf.Offset]int)
32 ex.kids = make(map[int][]int)
33 ex.parent = make(map[int]int)
34 ex.byname = make(map[string][]int)
35 var nesting []int
36 for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
37 if err != nil {
38 return err
39 }
40 if entry.Tag == 0 {
41
42 if len(nesting) == 0 {
43 return errors.New("nesting stack underflow")
44 }
45 nesting = nesting[:len(nesting)-1]
46 continue
47 }
48 idx := len(ex.dies)
49 ex.dies = append(ex.dies, entry)
50 if _, found := ex.idxByOffset[entry.Offset]; found {
51 return errors.New("DIE clash on offset")
52 }
53 ex.idxByOffset[entry.Offset] = idx
54 if name, ok := entry.Val(dwarf.AttrName).(string); ok {
55 ex.byname[name] = append(ex.byname[name], idx)
56 }
57 if len(nesting) > 0 {
58 parent := nesting[len(nesting)-1]
59 ex.kids[parent] = append(ex.kids[parent], idx)
60 ex.parent[idx] = parent
61 }
62 if entry.Children {
63 nesting = append(nesting, idx)
64 }
65 }
66 if len(nesting) > 0 {
67 return errors.New("unterminated child sequence")
68 }
69 return nil
70 }
71
72 func (ex *Examiner) DIEs() []*dwarf.Entry {
73 return ex.dies
74 }
75
76 func indent(ilevel int) {
77 for i := 0; i < ilevel; i++ {
78 fmt.Printf(" ")
79 }
80 }
81
82
83 func (ex *Examiner) DumpEntry(idx int, dumpKids bool, ilevel int) {
84 if idx >= len(ex.dies) {
85 fmt.Fprintf(os.Stderr, "DumpEntry: bad DIE %d: index out of range\n", idx)
86 return
87 }
88 entry := ex.dies[idx]
89 indent(ilevel)
90 fmt.Printf("0x%x: %v\n", idx, entry.Tag)
91 for _, f := range entry.Field {
92 indent(ilevel)
93 fmt.Printf("at=%v val=%v\n", f.Attr, f.Val)
94 }
95 if dumpKids {
96 ksl := ex.kids[idx]
97 for _, k := range ksl {
98 ex.DumpEntry(k, true, ilevel+2)
99 }
100 }
101 }
102
103
104 func (ex *Examiner) EntryFromOffset(off dwarf.Offset) *dwarf.Entry {
105 if idx, found := ex.idxByOffset[off]; found && idx != -1 {
106 return ex.entryFromIdx(idx)
107 }
108 return nil
109 }
110
111
112 func (ex *Examiner) IdxFromOffset(off dwarf.Offset) int {
113 if idx, found := ex.idxByOffset[off]; found {
114 return idx
115 }
116 return -1
117 }
118
119
120 func (ex *Examiner) entryFromIdx(idx int) *dwarf.Entry {
121 if idx >= len(ex.dies) || idx < 0 {
122 return nil
123 }
124 return ex.dies[idx]
125 }
126
127
128 func (ex *Examiner) Children(idx int) []*dwarf.Entry {
129 sl := ex.kids[idx]
130 ret := make([]*dwarf.Entry, len(sl))
131 for i, k := range sl {
132 ret[i] = ex.entryFromIdx(k)
133 }
134 return ret
135 }
136
137
138 func (ex *Examiner) Parent(idx int) *dwarf.Entry {
139 p, found := ex.parent[idx]
140 if !found {
141 return nil
142 }
143 return ex.entryFromIdx(p)
144 }
145
146
147
148
149 func (ex *Examiner) ParentCU(idx int) *dwarf.Entry {
150 for {
151 parentDie := ex.Parent(idx)
152 if parentDie == nil {
153 return nil
154 }
155 if parentDie.Tag == dwarf.TagCompileUnit {
156 return parentDie
157 }
158 idx = ex.IdxFromOffset(parentDie.Offset)
159 }
160 }
161
162
163
164
165
166
167 func (ex *Examiner) FileRef(dw *dwarf.Data, dieIdx int, fileRef int64) (string, error) {
168
169
170 cuDie := ex.ParentCU(dieIdx)
171 if cuDie == nil {
172 return "", fmt.Errorf("no parent CU DIE for DIE with idx %d?", dieIdx)
173 }
174
175 lr, lrerr := dw.LineReader(cuDie)
176 if lrerr != nil {
177 return "", fmt.Errorf("d.LineReader: %v", lrerr)
178 }
179 files := lr.Files()
180 if fileRef < 0 || int(fileRef) > len(files)-1 {
181 return "", fmt.Errorf("Examiner.FileRef: malformed file reference %d", fileRef)
182 }
183 return files[fileRef].Name, nil
184 }
185
186
187
188
189
190 func (ex *Examiner) Named(name string) []*dwarf.Entry {
191 sl := ex.byname[name]
192 ret := make([]*dwarf.Entry, len(sl))
193 for i, k := range sl {
194 ret[i] = ex.entryFromIdx(k)
195 }
196 return ret
197 }
198
View as plain text