Source file
src/debug/dwarf/entry_test.go
1
2
3
4
5 package dwarf_test
6
7 import (
8 . "debug/dwarf"
9 "encoding/binary"
10 "path/filepath"
11 "reflect"
12 "testing"
13 )
14
15 func TestSplit(t *testing.T) {
16
17
18
19
20 d := elfData(t, "testdata/split.elf")
21 r := d.Reader()
22 e, err := r.Next()
23 if err != nil {
24 t.Fatal(err)
25 }
26 if e.Tag != TagCompileUnit {
27 t.Fatalf("bad tag: have %s, want %s", e.Tag, TagCompileUnit)
28 }
29
30
31 const AttrGNUAddrBase Attr = 0x2133
32 f := e.AttrField(AttrGNUAddrBase)
33 if _, ok := f.Val.(int64); !ok {
34 t.Fatalf("bad attribute value type: have %T, want int64", f.Val)
35 }
36 if f.Class != ClassUnknown {
37 t.Fatalf("bad class: have %s, want %s", f.Class, ClassUnknown)
38 }
39 }
40
41
42
43 type wantRange struct {
44 pc uint64
45 ranges [][2]uint64
46 }
47
48 func TestReaderSeek(t *testing.T) {
49 want := []wantRange{
50 {0x40059d, [][2]uint64{{0x40059d, 0x400601}}},
51 {0x400600, [][2]uint64{{0x40059d, 0x400601}}},
52 {0x400601, [][2]uint64{{0x400601, 0x400611}}},
53 {0x4005f0, [][2]uint64{{0x40059d, 0x400601}}},
54 {0x10, nil},
55 {0x400611, nil},
56 }
57 testRanges(t, "testdata/line-gcc.elf", want)
58
59 want = []wantRange{
60 {0x401122, [][2]uint64{{0x401122, 0x401166}}},
61 {0x401165, [][2]uint64{{0x401122, 0x401166}}},
62 {0x401166, [][2]uint64{{0x401166, 0x401179}}},
63 }
64 testRanges(t, "testdata/line-gcc-dwarf5.elf", want)
65
66 want = []wantRange{
67 {0x401130, [][2]uint64{{0x401130, 0x40117e}}},
68 {0x40117d, [][2]uint64{{0x401130, 0x40117e}}},
69 {0x40117e, nil},
70 }
71 testRanges(t, "testdata/line-clang-dwarf5.elf", want)
72 }
73
74 func TestRangesSection(t *testing.T) {
75 want := []wantRange{
76 {0x400500, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
77 {0x400400, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
78 {0x400548, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
79 {0x400407, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
80 {0x400408, nil},
81 {0x400449, nil},
82 {0x4003ff, nil},
83 }
84 testRanges(t, "testdata/ranges.elf", want)
85 }
86
87 func TestRangesRnglistx(t *testing.T) {
88 want := []wantRange{
89 {0x401000, [][2]uint64{{0x401020, 0x40102c}, {0x401000, 0x40101d}}},
90 {0x40101c, [][2]uint64{{0x401020, 0x40102c}, {0x401000, 0x40101d}}},
91 {0x40101d, nil},
92 {0x40101f, nil},
93 {0x401020, [][2]uint64{{0x401020, 0x40102c}, {0x401000, 0x40101d}}},
94 {0x40102b, [][2]uint64{{0x401020, 0x40102c}, {0x401000, 0x40101d}}},
95 {0x40102c, nil},
96 }
97 testRanges(t, "testdata/rnglistx.elf", want)
98 }
99
100 func testRanges(t *testing.T, name string, want []wantRange) {
101 d := elfData(t, name)
102 r := d.Reader()
103 for _, w := range want {
104 entry, err := r.SeekPC(w.pc)
105 if err != nil {
106 if w.ranges != nil {
107 t.Errorf("%s: missing Entry for %#x", name, w.pc)
108 }
109 if err != ErrUnknownPC {
110 t.Errorf("%s: expected ErrUnknownPC for %#x, got %v", name, w.pc, err)
111 }
112 continue
113 }
114
115 ranges, err := d.Ranges(entry)
116 if err != nil {
117 t.Errorf("%s: %v", name, err)
118 continue
119 }
120 if !reflect.DeepEqual(ranges, w.ranges) {
121 t.Errorf("%s: for %#x got %x, expected %x", name, w.pc, ranges, w.ranges)
122 }
123 }
124 }
125
126 func TestReaderRanges(t *testing.T) {
127 type subprograms []struct {
128 name string
129 ranges [][2]uint64
130 }
131 tests := []struct {
132 filename string
133 subprograms subprograms
134 }{
135 {
136 "testdata/line-gcc.elf",
137 subprograms{
138 {"f1", [][2]uint64{{0x40059d, 0x4005e7}}},
139 {"main", [][2]uint64{{0x4005e7, 0x400601}}},
140 {"f2", [][2]uint64{{0x400601, 0x400611}}},
141 },
142 },
143 {
144 "testdata/line-gcc-dwarf5.elf",
145 subprograms{
146 {"main", [][2]uint64{{0x401147, 0x401166}}},
147 {"f1", [][2]uint64{{0x401122, 0x401147}}},
148 {"f2", [][2]uint64{{0x401166, 0x401179}}},
149 },
150 },
151 {
152 "testdata/line-clang-dwarf5.elf",
153 subprograms{
154 {"main", [][2]uint64{{0x401130, 0x401144}}},
155 {"f1", [][2]uint64{{0x401150, 0x40117e}}},
156 {"f2", [][2]uint64{{0x401180, 0x401197}}},
157 },
158 },
159 }
160
161 for _, test := range tests {
162 d := elfData(t, test.filename)
163 subprograms := test.subprograms
164
165 r := d.Reader()
166 i := 0
167 for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
168 if entry.Tag != TagSubprogram {
169 continue
170 }
171
172 if i > len(subprograms) {
173 t.Fatalf("%s: too many subprograms (expected at most %d)", test.filename, i)
174 }
175
176 if got := entry.Val(AttrName).(string); got != subprograms[i].name {
177 t.Errorf("%s: subprogram %d name is %s, expected %s", test.filename, i, got, subprograms[i].name)
178 }
179 ranges, err := d.Ranges(entry)
180 if err != nil {
181 t.Errorf("%s: subprogram %d: %v", test.filename, i, err)
182 continue
183 }
184 if !reflect.DeepEqual(ranges, subprograms[i].ranges) {
185 t.Errorf("%s: subprogram %d ranges are %x, expected %x", test.filename, i, ranges, subprograms[i].ranges)
186 }
187 i++
188 }
189
190 if i < len(subprograms) {
191 t.Errorf("%s: saw only %d subprograms, expected %d", test.filename, i, len(subprograms))
192 }
193 }
194 }
195
196 func Test64Bit(t *testing.T) {
197
198
199
200 tests := []struct {
201 name string
202 info []byte
203 addrSize int
204 byteOrder binary.ByteOrder
205 }{
206 {
207 "32-bit little",
208 []byte{0x30, 0, 0, 0,
209 4, 0,
210 0, 0, 0, 0,
211 8,
212 0,
213 0, 0, 0, 0, 0, 0, 0, 0,
214 0, 0, 0, 0, 0, 0, 0, 0,
215 0, 0, 0, 0, 0, 0, 0, 0,
216 0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0, 0, 0,
218 },
219 8, binary.LittleEndian,
220 },
221 {
222 "64-bit little",
223 []byte{0xff, 0xff, 0xff, 0xff,
224 0x30, 0, 0, 0, 0, 0, 0, 0,
225 4, 0,
226 0, 0, 0, 0, 0, 0, 0, 0,
227 8,
228 0, 0, 0, 0, 0,
229 0, 0, 0, 0, 0, 0, 0, 0,
230 0, 0, 0, 0, 0, 0, 0, 0,
231 0, 0, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0,
233 },
234 8, binary.LittleEndian,
235 },
236 {
237 "64-bit big",
238 []byte{0xff, 0xff, 0xff, 0xff,
239 0, 0, 0, 0, 0, 0, 0, 0x30,
240 0, 4,
241 0, 0, 0, 0, 0, 0, 0, 0,
242 8,
243 0, 0, 0, 0, 0,
244 0, 0, 0, 0, 0, 0, 0, 0,
245 0, 0, 0, 0, 0, 0, 0, 0,
246 0, 0, 0, 0, 0, 0, 0, 0,
247 0, 0, 0, 0, 0, 0, 0, 0,
248 },
249 8, binary.BigEndian,
250 },
251 }
252
253 for _, test := range tests {
254 data, err := New(nil, nil, nil, test.info, nil, nil, nil, nil)
255 if err != nil {
256 t.Errorf("%s: %v", test.name, err)
257 }
258
259 r := data.Reader()
260 if r.AddressSize() != test.addrSize {
261 t.Errorf("%s: got address size %d, want %d", test.name, r.AddressSize(), test.addrSize)
262 }
263 if r.ByteOrder() != test.byteOrder {
264 t.Errorf("%s: got byte order %s, want %s", test.name, r.ByteOrder(), test.byteOrder)
265 }
266 }
267 }
268
269 func TestUnitIteration(t *testing.T) {
270
271
272
273 files, err := filepath.Glob(filepath.Join("testdata", "*.elf"))
274 if err != nil {
275 t.Fatal(err)
276 }
277 for _, file := range files {
278 t.Run(file, func(t *testing.T) {
279 d := elfData(t, file)
280 var units [2][]any
281 for method := range units {
282 for r := d.Reader(); ; {
283 ent, err := r.Next()
284 if err != nil {
285 t.Fatal(err)
286 }
287 if ent == nil {
288 break
289 }
290 if ent.Tag == TagCompileUnit {
291 units[method] = append(units[method], ent.Val(AttrName))
292 }
293 if method == 0 {
294 if ent.Tag != TagCompileUnit {
295 t.Fatalf("found unexpected tag %v on top level", ent.Tag)
296 }
297 r.SkipChildren()
298 }
299 }
300 }
301 t.Logf("skipping CUs: %v", units[0])
302 t.Logf("not-skipping CUs: %v", units[1])
303 if !reflect.DeepEqual(units[0], units[1]) {
304 t.Fatal("set of CUs differ")
305 }
306 })
307 }
308 }
309
View as plain text