1 // Copyright (c) 2012, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
31
32 // dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit
33
34 #include <stdlib.h>
35
36 #include <iostream>
37 #include <string>
38 #include <vector>
39
40 #include "breakpad_googletest_includes.h"
41 #include "common/dwarf/bytereader-inl.h"
42 #include "common/dwarf/dwarf2reader_test_common.h"
43 #include "common/dwarf/dwarf2reader.h"
44 #include "common/using_std_string.h"
45 #include "google_breakpad/common/breakpad_types.h"
46
47 using google_breakpad::test_assembler::Endianness;
48 using google_breakpad::test_assembler::Label;
49 using google_breakpad::test_assembler::Section;
50 using google_breakpad::test_assembler::kBigEndian;
51 using google_breakpad::test_assembler::kLittleEndian;
52
53 using dwarf2reader::ByteReader;
54 using dwarf2reader::CompilationUnit;
55 using dwarf2reader::Dwarf2Handler;
56 using dwarf2reader::DwarfAttribute;
57 using dwarf2reader::DwarfForm;
58 using dwarf2reader::DwarfHasChild;
59 using dwarf2reader::DwarfTag;
60 using dwarf2reader::ENDIANNESS_BIG;
61 using dwarf2reader::ENDIANNESS_LITTLE;
62 using dwarf2reader::SectionMap;
63
64 using std::vector;
65 using testing::InSequence;
66 using testing::Pointee;
67 using testing::Return;
68 using testing::Sequence;
69 using testing::Test;
70 using testing::TestWithParam;
71 using testing::_;
72
73 class MockDwarf2Handler: public Dwarf2Handler {
74 public:
75 MOCK_METHOD5(StartCompilationUnit, bool(uint64 offset, uint8 address_size,
76 uint8 offset_size, uint64 cu_length,
77 uint8 dwarf_version));
78 MOCK_METHOD2(StartDIE, bool(uint64 offset, enum DwarfTag tag));
79 MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset,
80 DwarfAttribute attr,
81 enum DwarfForm form,
82 uint64 data));
83 MOCK_METHOD4(ProcessAttributeSigned, void(uint64 offset,
84 enum DwarfAttribute attr,
85 enum DwarfForm form,
86 int64 data));
87 MOCK_METHOD4(ProcessAttributeReference, void(uint64 offset,
88 enum DwarfAttribute attr,
89 enum DwarfForm form,
90 uint64 data));
91 MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset,
92 enum DwarfAttribute attr,
93 enum DwarfForm form,
94 const char* data,
95 uint64 len));
96 MOCK_METHOD4(ProcessAttributeString, void(uint64 offset,
97 enum DwarfAttribute attr,
98 enum DwarfForm form,
99 const string& data));
100 MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset,
101 DwarfAttribute attr,
102 enum DwarfForm form,
103 uint64 signature));
104 MOCK_METHOD1(EndDIE, void(uint64 offset));
105 };
106
107 struct DIEFixture {
108
DIEFixtureDIEFixture109 DIEFixture() {
110 // Fix the initial offset of the .debug_info and .debug_abbrev sections.
111 info.start() = 0;
112 abbrevs.start() = 0;
113
114 // Default expectations for the data handler.
115 EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0);
116 EXPECT_CALL(handler, StartDIE(_, _)).Times(0);
117 EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0);
118 EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0);
119 EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0);
120 EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0);
121 EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0);
122 EXPECT_CALL(handler, EndDIE(_)).Times(0);
123 }
124
125 // Return a reference to a section map whose .debug_info section refers
126 // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This
127 // function returns a reference to the same SectionMap each time; new
128 // calls wipe out maps established by earlier calls.
MakeSectionMapDIEFixture129 const SectionMap &MakeSectionMap() {
130 // Copy the sections' contents into strings that will live as long as
131 // the map itself.
132 assert(info.GetContents(&info_contents));
133 assert(abbrevs.GetContents(&abbrevs_contents));
134 section_map.clear();
135 section_map[".debug_info"].first = info_contents.data();
136 section_map[".debug_info"].second = info_contents.size();
137 section_map[".debug_abbrev"].first = abbrevs_contents.data();
138 section_map[".debug_abbrev"].second = abbrevs_contents.size();
139 return section_map;
140 }
141
142 TestCompilationUnit info;
143 TestAbbrevTable abbrevs;
144 MockDwarf2Handler handler;
145 string abbrevs_contents, info_contents;
146 SectionMap section_map;
147 };
148
149 struct DwarfHeaderParams {
DwarfHeaderParamsDwarfHeaderParams150 DwarfHeaderParams(Endianness endianness, size_t format_size,
151 int version, size_t address_size)
152 : endianness(endianness), format_size(format_size),
153 version(version), address_size(address_size) { }
154 Endianness endianness;
155 size_t format_size; // 4-byte or 8-byte DWARF offsets
156 int version;
157 size_t address_size;
158 };
159
160 class DwarfHeader: public DIEFixture,
161 public TestWithParam<DwarfHeaderParams> { };
162
TEST_P(DwarfHeader,Header)163 TEST_P(DwarfHeader, Header) {
164 Label abbrev_table = abbrevs.Here();
165 abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit,
166 dwarf2reader::DW_children_yes)
167 .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string)
168 .EndAbbrev()
169 .EndTable();
170
171 info.set_format_size(GetParam().format_size);
172 info.set_endianness(GetParam().endianness);
173
174 info.Header(GetParam().version, abbrev_table, GetParam().address_size)
175 .ULEB128(1) // DW_TAG_compile_unit, with children
176 .AppendCString("sam") // DW_AT_name, DW_FORM_string
177 .D8(0); // end of children
178 info.Finish();
179
180 {
181 InSequence s;
182 EXPECT_CALL(handler,
183 StartCompilationUnit(0, GetParam().address_size,
184 GetParam().format_size, _,
185 GetParam().version))
186 .WillOnce(Return(true));
187 EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit))
188 .WillOnce(Return(true));
189 EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name,
190 dwarf2reader::DW_FORM_string,
191 "sam"))
192 .WillOnce(Return());
193 EXPECT_CALL(handler, EndDIE(_))
194 .WillOnce(Return());
195 }
196
197 ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
198 ENDIANNESS_LITTLE : ENDIANNESS_BIG);
199 CompilationUnit parser(MakeSectionMap(), 0, &byte_reader, &handler);
200 EXPECT_EQ(parser.Start(), info_contents.size());
201 }
202
203 INSTANTIATE_TEST_CASE_P(
204 HeaderVariants, DwarfHeader,
205 ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
206 DwarfHeaderParams(kLittleEndian, 4, 2, 8),
207 DwarfHeaderParams(kLittleEndian, 4, 3, 4),
208 DwarfHeaderParams(kLittleEndian, 4, 3, 8),
209 DwarfHeaderParams(kLittleEndian, 4, 4, 4),
210 DwarfHeaderParams(kLittleEndian, 4, 4, 8),
211 DwarfHeaderParams(kLittleEndian, 8, 2, 4),
212 DwarfHeaderParams(kLittleEndian, 8, 2, 8),
213 DwarfHeaderParams(kLittleEndian, 8, 3, 4),
214 DwarfHeaderParams(kLittleEndian, 8, 3, 8),
215 DwarfHeaderParams(kLittleEndian, 8, 4, 4),
216 DwarfHeaderParams(kLittleEndian, 8, 4, 8),
217 DwarfHeaderParams(kBigEndian, 4, 2, 4),
218 DwarfHeaderParams(kBigEndian, 4, 2, 8),
219 DwarfHeaderParams(kBigEndian, 4, 3, 4),
220 DwarfHeaderParams(kBigEndian, 4, 3, 8),
221 DwarfHeaderParams(kBigEndian, 4, 4, 4),
222 DwarfHeaderParams(kBigEndian, 4, 4, 8),
223 DwarfHeaderParams(kBigEndian, 8, 2, 4),
224 DwarfHeaderParams(kBigEndian, 8, 2, 8),
225 DwarfHeaderParams(kBigEndian, 8, 3, 4),
226 DwarfHeaderParams(kBigEndian, 8, 3, 8),
227 DwarfHeaderParams(kBigEndian, 8, 4, 4),
228 DwarfHeaderParams(kBigEndian, 8, 4, 8)));
229
230 struct DwarfFormsFixture: public DIEFixture {
231 // Start a compilation unit, as directed by |params|, containing one
232 // childless DIE of the given tag, with one attribute of the given name
233 // and form. The 'info' fixture member is left just after the abbrev
234 // code, waiting for the attribute value to be appended.
StartSingleAttributeDIEDwarfFormsFixture235 void StartSingleAttributeDIE(const DwarfHeaderParams ¶ms,
236 DwarfTag tag, DwarfAttribute name,
237 DwarfForm form) {
238 // Create the abbreviation table.
239 Label abbrev_table = abbrevs.Here();
240 abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no)
241 .Attribute(name, form)
242 .EndAbbrev()
243 .EndTable();
244
245 // Create the compilation unit, up to the attribute value.
246 info.set_format_size(params.format_size);
247 info.set_endianness(params.endianness);
248 info.Header(params.version, abbrev_table, params.address_size)
249 .ULEB128(1); // abbrev code
250 }
251
252 // Set up handler to expect a compilation unit matching |params|,
253 // containing one childless DIE of the given tag, in the sequence s. Stop
254 // just before the expectations.
ExpectBeginCompilationUnitDwarfFormsFixture255 void ExpectBeginCompilationUnit(const DwarfHeaderParams ¶ms,
256 DwarfTag tag, uint64 offset=0) {
257 EXPECT_CALL(handler,
258 StartCompilationUnit(offset, params.address_size,
259 params.format_size, _,
260 params.version))
261 .InSequence(s)
262 .WillOnce(Return(true));
263 EXPECT_CALL(handler, StartDIE(_, tag))
264 .InSequence(s)
265 .WillOnce(Return(true));
266 }
267
ExpectEndCompilationUnitDwarfFormsFixture268 void ExpectEndCompilationUnit() {
269 EXPECT_CALL(handler, EndDIE(_))
270 .InSequence(s)
271 .WillOnce(Return());
272 }
273
ParseCompilationUnitDwarfFormsFixture274 void ParseCompilationUnit(const DwarfHeaderParams ¶ms, uint64 offset=0) {
275 ByteReader byte_reader(params.endianness == kLittleEndian ?
276 ENDIANNESS_LITTLE : ENDIANNESS_BIG);
277 CompilationUnit parser(MakeSectionMap(), offset, &byte_reader, &handler);
278 EXPECT_EQ(offset + parser.Start(), info_contents.size());
279 }
280
281 // The sequence to which the fixture's methods append expectations.
282 Sequence s;
283 };
284
285 struct DwarfForms: public DwarfFormsFixture,
286 public TestWithParam<DwarfHeaderParams> { };
287
TEST_P(DwarfForms,addr)288 TEST_P(DwarfForms, addr) {
289 StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit,
290 dwarf2reader::DW_AT_low_pc,
291 dwarf2reader::DW_FORM_addr);
292 uint64_t value;
293 if (GetParam().address_size == 4) {
294 value = 0xc8e9ffcc;
295 info.D32(value);
296 } else {
297 value = 0xe942517fc2768564ULL;
298 info.D64(value);
299 }
300 info.Finish();
301
302 ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit);
303 EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc,
304 dwarf2reader::DW_FORM_addr,
305 value))
306 .InSequence(s)
307 .WillOnce(Return());
308 ExpectEndCompilationUnit();
309
310 ParseCompilationUnit(GetParam());
311 }
312
TEST_P(DwarfForms,block2_empty)313 TEST_P(DwarfForms, block2_empty) {
314 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
315 (DwarfAttribute) 0xe52c4463,
316 dwarf2reader::DW_FORM_block2);
317 info.D16(0);
318 info.Finish();
319
320 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
321 EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
322 dwarf2reader::DW_FORM_block2,
323 _, 0))
324 .InSequence(s)
325 .WillOnce(Return());
326 ExpectEndCompilationUnit();
327
328 ParseCompilationUnit(GetParam());
329 }
330
TEST_P(DwarfForms,block2)331 TEST_P(DwarfForms, block2) {
332 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
333 (DwarfAttribute) 0xe52c4463,
334 dwarf2reader::DW_FORM_block2);
335 unsigned char data[258];
336 memset(data, '*', sizeof(data));
337 info.D16(sizeof(data))
338 .Append(data, sizeof(data));
339 info.Finish();
340
341 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
342 EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
343 dwarf2reader::DW_FORM_block2,
344 Pointee('*'), 258))
345 .InSequence(s)
346 .WillOnce(Return());
347 ExpectEndCompilationUnit();
348
349 ParseCompilationUnit(GetParam());
350 }
351
TEST_P(DwarfForms,flag_present)352 TEST_P(DwarfForms, flag_present) {
353 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
354 (DwarfAttribute) 0x359d1972,
355 dwarf2reader::DW_FORM_flag_present);
356 // DW_FORM_flag_present occupies no space in the DIE.
357 info.Finish();
358
359 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
360 EXPECT_CALL(handler,
361 ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
362 dwarf2reader::DW_FORM_flag_present,
363 1))
364 .InSequence(s)
365 .WillOnce(Return());
366 ExpectEndCompilationUnit();
367
368 ParseCompilationUnit(GetParam());
369 }
370
TEST_P(DwarfForms,sec_offset)371 TEST_P(DwarfForms, sec_offset) {
372 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
373 (DwarfAttribute) 0xa060bfd1,
374 dwarf2reader::DW_FORM_sec_offset);
375 uint64_t value;
376 if (GetParam().format_size == 4) {
377 value = 0xacc9c388;
378 info.D32(value);
379 } else {
380 value = 0xcffe5696ffe3ed0aULL;
381 info.D64(value);
382 }
383 info.Finish();
384
385 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
386 EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
387 dwarf2reader::DW_FORM_sec_offset,
388 value))
389 .InSequence(s)
390 .WillOnce(Return());
391 ExpectEndCompilationUnit();
392
393 ParseCompilationUnit(GetParam());
394 }
395
TEST_P(DwarfForms,exprloc)396 TEST_P(DwarfForms, exprloc) {
397 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
398 (DwarfAttribute) 0xba3ae5cb,
399 dwarf2reader::DW_FORM_exprloc);
400 info.ULEB128(29)
401 .Append(29, 173);
402 info.Finish();
403
404 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
405 EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
406 dwarf2reader::DW_FORM_exprloc,
407 Pointee(173), 29))
408 .InSequence(s)
409 .WillOnce(Return());
410 ExpectEndCompilationUnit();
411
412 ParseCompilationUnit(GetParam());
413 }
414
TEST_P(DwarfForms,ref_sig8)415 TEST_P(DwarfForms, ref_sig8) {
416 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
417 (DwarfAttribute) 0xd708d908,
418 dwarf2reader::DW_FORM_ref_sig8);
419 info.D64(0xf72fa0cb6ddcf9d6ULL);
420 info.Finish();
421
422 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
423 EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
424 dwarf2reader::DW_FORM_ref_sig8,
425 0xf72fa0cb6ddcf9d6ULL))
426 .InSequence(s)
427 .WillOnce(Return());
428 ExpectEndCompilationUnit();
429
430 ParseCompilationUnit(GetParam());
431 }
432
433 // A value passed to ProcessAttributeSignature is just an absolute number,
434 // not an offset within the compilation unit as most of the other
435 // DW_FORM_ref forms are. Check that the reader doesn't try to apply any
436 // offset to the signature, by reading it from a compilation unit that does
437 // not start at the beginning of the section.
TEST_P(DwarfForms,ref_sig8_not_first)438 TEST_P(DwarfForms, ref_sig8_not_first) {
439 info.Append(98, '*');
440 StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
441 (DwarfAttribute) 0xd708d908,
442 dwarf2reader::DW_FORM_ref_sig8);
443 info.D64(0xf72fa0cb6ddcf9d6ULL);
444 info.Finish();
445
446 ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
447 EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
448 dwarf2reader::DW_FORM_ref_sig8,
449 0xf72fa0cb6ddcf9d6ULL))
450 .InSequence(s)
451 .WillOnce(Return());
452 ExpectEndCompilationUnit();
453
454 ParseCompilationUnit(GetParam(), 98);
455 }
456
457 // Tests for the other attribute forms could go here.
458
459 INSTANTIATE_TEST_CASE_P(
460 HeaderVariants, DwarfForms,
461 ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
462 DwarfHeaderParams(kLittleEndian, 4, 2, 8),
463 DwarfHeaderParams(kLittleEndian, 4, 3, 4),
464 DwarfHeaderParams(kLittleEndian, 4, 3, 8),
465 DwarfHeaderParams(kLittleEndian, 4, 4, 4),
466 DwarfHeaderParams(kLittleEndian, 4, 4, 8),
467 DwarfHeaderParams(kLittleEndian, 8, 2, 4),
468 DwarfHeaderParams(kLittleEndian, 8, 2, 8),
469 DwarfHeaderParams(kLittleEndian, 8, 3, 4),
470 DwarfHeaderParams(kLittleEndian, 8, 3, 8),
471 DwarfHeaderParams(kLittleEndian, 8, 4, 4),
472 DwarfHeaderParams(kLittleEndian, 8, 4, 8),
473 DwarfHeaderParams(kBigEndian, 4, 2, 4),
474 DwarfHeaderParams(kBigEndian, 4, 2, 8),
475 DwarfHeaderParams(kBigEndian, 4, 3, 4),
476 DwarfHeaderParams(kBigEndian, 4, 3, 8),
477 DwarfHeaderParams(kBigEndian, 4, 4, 4),
478 DwarfHeaderParams(kBigEndian, 4, 4, 8),
479 DwarfHeaderParams(kBigEndian, 8, 2, 4),
480 DwarfHeaderParams(kBigEndian, 8, 2, 8),
481 DwarfHeaderParams(kBigEndian, 8, 3, 4),
482 DwarfHeaderParams(kBigEndian, 8, 3, 8),
483 DwarfHeaderParams(kBigEndian, 8, 4, 4),
484 DwarfHeaderParams(kBigEndian, 8, 4, 8)));
485