• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdint.h>
35 #include <stdlib.h>
36 
37 #include <iostream>
38 #include <string>
39 #include <vector>
40 
41 #include "breakpad_googletest_includes.h"
42 #include "common/dwarf/bytereader-inl.h"
43 #include "common/dwarf/dwarf2reader_test_common.h"
44 #include "common/dwarf/dwarf2reader.h"
45 #include "common/using_std_string.h"
46 #include "google_breakpad/common/breakpad_types.h"
47 
48 using google_breakpad::test_assembler::Endianness;
49 using google_breakpad::test_assembler::Label;
50 using google_breakpad::test_assembler::Section;
51 using google_breakpad::test_assembler::kBigEndian;
52 using google_breakpad::test_assembler::kLittleEndian;
53 
54 using dwarf2reader::ByteReader;
55 using dwarf2reader::CompilationUnit;
56 using dwarf2reader::Dwarf2Handler;
57 using dwarf2reader::DwarfAttribute;
58 using dwarf2reader::DwarfForm;
59 using dwarf2reader::DwarfHasChild;
60 using dwarf2reader::DwarfTag;
61 using dwarf2reader::ENDIANNESS_BIG;
62 using dwarf2reader::ENDIANNESS_LITTLE;
63 using dwarf2reader::SectionMap;
64 
65 using std::vector;
66 using testing::InSequence;
67 using testing::Pointee;
68 using testing::Return;
69 using testing::Sequence;
70 using testing::Test;
71 using testing::TestWithParam;
72 using testing::_;
73 
74 class MockDwarf2Handler: public Dwarf2Handler {
75  public:
76   MOCK_METHOD5(StartCompilationUnit, bool(uint64_t offset, uint8_t address_size,
77                                           uint8_t offset_size,
78                                           uint64_t cu_length,
79                                           uint8_t dwarf_version));
80   MOCK_METHOD2(StartDIE, bool(uint64_t offset, enum DwarfTag tag));
81   MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64_t offset,
82                                               DwarfAttribute attr,
83                                               enum DwarfForm form,
84                                               uint64_t data));
85   MOCK_METHOD4(ProcessAttributeSigned, void(uint64_t offset,
86                                             enum DwarfAttribute attr,
87                                             enum DwarfForm form,
88                                             int64_t data));
89   MOCK_METHOD4(ProcessAttributeReference, void(uint64_t offset,
90                                                enum DwarfAttribute attr,
91                                                enum DwarfForm form,
92                                                uint64_t data));
93   MOCK_METHOD5(ProcessAttributeBuffer, void(uint64_t offset,
94                                             enum DwarfAttribute attr,
95                                             enum DwarfForm form,
96                                             const uint8_t *data,
97                                             uint64_t len));
98   MOCK_METHOD4(ProcessAttributeString, void(uint64_t offset,
99                                             enum DwarfAttribute attr,
100                                             enum DwarfForm form,
101                                             const string& data));
102   MOCK_METHOD4(ProcessAttributeSignature, void(uint64_t offset,
103                                                DwarfAttribute attr,
104                                                enum DwarfForm form,
105                                                uint64_t signature));
106   MOCK_METHOD1(EndDIE, void(uint64_t offset));
107 };
108 
109 struct DIEFixture {
110 
DIEFixtureDIEFixture111   DIEFixture() {
112     // Fix the initial offset of the .debug_info and .debug_abbrev sections.
113     info.start() = 0;
114     abbrevs.start() = 0;
115 
116     // Default expectations for the data handler.
117     EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0);
118     EXPECT_CALL(handler, StartDIE(_, _)).Times(0);
119     EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0);
120     EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0);
121     EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0);
122     EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0);
123     EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0);
124     EXPECT_CALL(handler, EndDIE(_)).Times(0);
125   }
126 
127   // Return a reference to a section map whose .debug_info section refers
128   // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This
129   // function returns a reference to the same SectionMap each time; new
130   // calls wipe out maps established by earlier calls.
MakeSectionMapDIEFixture131   const SectionMap &MakeSectionMap() {
132     // Copy the sections' contents into strings that will live as long as
133     // the map itself.
134     assert(info.GetContents(&info_contents));
135     assert(abbrevs.GetContents(&abbrevs_contents));
136     section_map.clear();
137     section_map[".debug_info"].first
138       = reinterpret_cast<const uint8_t *>(info_contents.data());
139     section_map[".debug_info"].second = info_contents.size();
140     section_map[".debug_abbrev"].first
141       = reinterpret_cast<const uint8_t *>(abbrevs_contents.data());
142     section_map[".debug_abbrev"].second = abbrevs_contents.size();
143     return section_map;
144   }
145 
146   TestCompilationUnit info;
147   TestAbbrevTable abbrevs;
148   MockDwarf2Handler handler;
149   string abbrevs_contents, info_contents;
150   SectionMap section_map;
151 };
152 
153 struct DwarfHeaderParams {
DwarfHeaderParamsDwarfHeaderParams154   DwarfHeaderParams(Endianness endianness, size_t format_size,
155                    int version, size_t address_size)
156       : endianness(endianness), format_size(format_size),
157         version(version), address_size(address_size) { }
158   Endianness endianness;
159   size_t format_size;                   // 4-byte or 8-byte DWARF offsets
160   int version;
161   size_t address_size;
162 };
163 
164 class DwarfHeader: public DIEFixture,
165                    public TestWithParam<DwarfHeaderParams> { };
166 
TEST_P(DwarfHeader,Header)167 TEST_P(DwarfHeader, Header) {
168   Label abbrev_table = abbrevs.Here();
169   abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit,
170                  dwarf2reader::DW_children_yes)
171       .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string)
172       .EndAbbrev()
173       .EndTable();
174 
175   info.set_format_size(GetParam().format_size);
176   info.set_endianness(GetParam().endianness);
177 
178   info.Header(GetParam().version, abbrev_table, GetParam().address_size)
179       .ULEB128(1)                     // DW_TAG_compile_unit, with children
180       .AppendCString("sam")           // DW_AT_name, DW_FORM_string
181       .D8(0);                         // end of children
182   info.Finish();
183 
184   {
185     InSequence s;
186     EXPECT_CALL(handler,
187                 StartCompilationUnit(0, GetParam().address_size,
188                                      GetParam().format_size, _,
189                                      GetParam().version))
190         .WillOnce(Return(true));
191     EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit))
192         .WillOnce(Return(true));
193     EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name,
194                                                 dwarf2reader::DW_FORM_string,
195                                                 "sam"))
196         .WillOnce(Return());
197     EXPECT_CALL(handler, EndDIE(_))
198         .WillOnce(Return());
199   }
200 
201   ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
202                          ENDIANNESS_LITTLE : ENDIANNESS_BIG);
203   CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler);
204   EXPECT_EQ(parser.Start(), info_contents.size());
205 }
206 
207 INSTANTIATE_TEST_CASE_P(
208     HeaderVariants, DwarfHeader,
209     ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
210                       DwarfHeaderParams(kLittleEndian, 4, 2, 8),
211                       DwarfHeaderParams(kLittleEndian, 4, 3, 4),
212                       DwarfHeaderParams(kLittleEndian, 4, 3, 8),
213                       DwarfHeaderParams(kLittleEndian, 4, 4, 4),
214                       DwarfHeaderParams(kLittleEndian, 4, 4, 8),
215                       DwarfHeaderParams(kLittleEndian, 8, 2, 4),
216                       DwarfHeaderParams(kLittleEndian, 8, 2, 8),
217                       DwarfHeaderParams(kLittleEndian, 8, 3, 4),
218                       DwarfHeaderParams(kLittleEndian, 8, 3, 8),
219                       DwarfHeaderParams(kLittleEndian, 8, 4, 4),
220                       DwarfHeaderParams(kLittleEndian, 8, 4, 8),
221                       DwarfHeaderParams(kBigEndian,    4, 2, 4),
222                       DwarfHeaderParams(kBigEndian,    4, 2, 8),
223                       DwarfHeaderParams(kBigEndian,    4, 3, 4),
224                       DwarfHeaderParams(kBigEndian,    4, 3, 8),
225                       DwarfHeaderParams(kBigEndian,    4, 4, 4),
226                       DwarfHeaderParams(kBigEndian,    4, 4, 8),
227                       DwarfHeaderParams(kBigEndian,    8, 2, 4),
228                       DwarfHeaderParams(kBigEndian,    8, 2, 8),
229                       DwarfHeaderParams(kBigEndian,    8, 3, 4),
230                       DwarfHeaderParams(kBigEndian,    8, 3, 8),
231                       DwarfHeaderParams(kBigEndian,    8, 4, 4),
232                       DwarfHeaderParams(kBigEndian,    8, 4, 8)));
233 
234 struct DwarfFormsFixture: public DIEFixture {
235   // Start a compilation unit, as directed by |params|, containing one
236   // childless DIE of the given tag, with one attribute of the given name
237   // and form. The 'info' fixture member is left just after the abbrev
238   // code, waiting for the attribute value to be appended.
StartSingleAttributeDIEDwarfFormsFixture239   void StartSingleAttributeDIE(const DwarfHeaderParams &params,
240                                DwarfTag tag, DwarfAttribute name,
241                                DwarfForm form) {
242     // Create the abbreviation table.
243     Label abbrev_table = abbrevs.Here();
244     abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no)
245         .Attribute(name, form)
246         .EndAbbrev()
247         .EndTable();
248 
249     // Create the compilation unit, up to the attribute value.
250     info.set_format_size(params.format_size);
251     info.set_endianness(params.endianness);
252     info.Header(params.version, abbrev_table, params.address_size)
253         .ULEB128(1);                    // abbrev code
254   }
255 
256   // Set up handler to expect a compilation unit matching |params|,
257   // containing one childless DIE of the given tag, in the sequence s. Stop
258   // just before the expectations.
ExpectBeginCompilationUnitDwarfFormsFixture259   void ExpectBeginCompilationUnit(const DwarfHeaderParams &params,
260                                   DwarfTag tag, uint64_t offset=0) {
261     EXPECT_CALL(handler,
262                 StartCompilationUnit(offset, params.address_size,
263                                      params.format_size, _,
264                                      params.version))
265         .InSequence(s)
266         .WillOnce(Return(true));
267     EXPECT_CALL(handler, StartDIE(_, tag))
268         .InSequence(s)
269         .WillOnce(Return(true));
270   }
271 
ExpectEndCompilationUnitDwarfFormsFixture272   void ExpectEndCompilationUnit() {
273     EXPECT_CALL(handler, EndDIE(_))
274         .InSequence(s)
275         .WillOnce(Return());
276   }
277 
ParseCompilationUnitDwarfFormsFixture278   void ParseCompilationUnit(const DwarfHeaderParams &params,
279                             uint64_t offset=0) {
280     ByteReader byte_reader(params.endianness == kLittleEndian ?
281                            ENDIANNESS_LITTLE : ENDIANNESS_BIG);
282     CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler);
283     EXPECT_EQ(offset + parser.Start(), info_contents.size());
284   }
285 
286   // The sequence to which the fixture's methods append expectations.
287   Sequence s;
288 };
289 
290 struct DwarfForms: public DwarfFormsFixture,
291                    public TestWithParam<DwarfHeaderParams> { };
292 
TEST_P(DwarfForms,addr)293 TEST_P(DwarfForms, addr) {
294   StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit,
295                           dwarf2reader::DW_AT_low_pc,
296                           dwarf2reader::DW_FORM_addr);
297   uint64_t value;
298   if (GetParam().address_size == 4) {
299     value = 0xc8e9ffcc;
300     info.D32(value);
301   } else {
302     value = 0xe942517fc2768564ULL;
303     info.D64(value);
304   }
305   info.Finish();
306 
307   ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit);
308   EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc,
309                                                 dwarf2reader::DW_FORM_addr,
310                                                 value))
311       .InSequence(s)
312       .WillOnce(Return());
313   ExpectEndCompilationUnit();
314 
315   ParseCompilationUnit(GetParam());
316 }
317 
TEST_P(DwarfForms,block2_empty)318 TEST_P(DwarfForms, block2_empty) {
319   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
320                           (DwarfAttribute) 0xe52c4463,
321                           dwarf2reader::DW_FORM_block2);
322   info.D16(0);
323   info.Finish();
324 
325   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
326   EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
327                                               dwarf2reader::DW_FORM_block2,
328                                               _, 0))
329       .InSequence(s)
330       .WillOnce(Return());
331   ExpectEndCompilationUnit();
332 
333   ParseCompilationUnit(GetParam());
334 }
335 
TEST_P(DwarfForms,block2)336 TEST_P(DwarfForms, block2) {
337   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
338                           (DwarfAttribute) 0xe52c4463,
339                           dwarf2reader::DW_FORM_block2);
340   unsigned char data[258];
341   memset(data, '*', sizeof(data));
342   info.D16(sizeof(data))
343       .Append(data, sizeof(data));
344   info.Finish();
345 
346   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
347   EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
348                                               dwarf2reader::DW_FORM_block2,
349                                               Pointee('*'), 258))
350       .InSequence(s)
351       .WillOnce(Return());
352   ExpectEndCompilationUnit();
353 
354   ParseCompilationUnit(GetParam());
355 }
356 
TEST_P(DwarfForms,flag_present)357 TEST_P(DwarfForms, flag_present) {
358   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
359                           (DwarfAttribute) 0x359d1972,
360                           dwarf2reader::DW_FORM_flag_present);
361   // DW_FORM_flag_present occupies no space in the DIE.
362   info.Finish();
363 
364   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
365   EXPECT_CALL(handler,
366               ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
367                                        dwarf2reader::DW_FORM_flag_present,
368                                        1))
369       .InSequence(s)
370       .WillOnce(Return());
371   ExpectEndCompilationUnit();
372 
373   ParseCompilationUnit(GetParam());
374 }
375 
TEST_P(DwarfForms,sec_offset)376 TEST_P(DwarfForms, sec_offset) {
377   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
378                           (DwarfAttribute) 0xa060bfd1,
379                           dwarf2reader::DW_FORM_sec_offset);
380   uint64_t value;
381   if (GetParam().format_size == 4) {
382     value = 0xacc9c388;
383     info.D32(value);
384   } else {
385     value = 0xcffe5696ffe3ed0aULL;
386     info.D64(value);
387   }
388   info.Finish();
389 
390   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
391   EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
392                                                 dwarf2reader::DW_FORM_sec_offset,
393                                                 value))
394       .InSequence(s)
395       .WillOnce(Return());
396   ExpectEndCompilationUnit();
397 
398   ParseCompilationUnit(GetParam());
399 }
400 
TEST_P(DwarfForms,exprloc)401 TEST_P(DwarfForms, exprloc) {
402   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
403                           (DwarfAttribute) 0xba3ae5cb,
404                           dwarf2reader::DW_FORM_exprloc);
405   info.ULEB128(29)
406       .Append(29, 173);
407   info.Finish();
408 
409   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
410   EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
411                                               dwarf2reader::DW_FORM_exprloc,
412                                               Pointee(173), 29))
413       .InSequence(s)
414       .WillOnce(Return());
415   ExpectEndCompilationUnit();
416 
417   ParseCompilationUnit(GetParam());
418 }
419 
TEST_P(DwarfForms,ref_sig8)420 TEST_P(DwarfForms, ref_sig8) {
421   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
422                           (DwarfAttribute) 0xd708d908,
423                           dwarf2reader::DW_FORM_ref_sig8);
424   info.D64(0xf72fa0cb6ddcf9d6ULL);
425   info.Finish();
426 
427   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
428   EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
429                                                  dwarf2reader::DW_FORM_ref_sig8,
430                                                  0xf72fa0cb6ddcf9d6ULL))
431       .InSequence(s)
432       .WillOnce(Return());
433   ExpectEndCompilationUnit();
434 
435   ParseCompilationUnit(GetParam());
436 }
437 
438 // A value passed to ProcessAttributeSignature is just an absolute number,
439 // not an offset within the compilation unit as most of the other
440 // DW_FORM_ref forms are. Check that the reader doesn't try to apply any
441 // offset to the signature, by reading it from a compilation unit that does
442 // not start at the beginning of the section.
TEST_P(DwarfForms,ref_sig8_not_first)443 TEST_P(DwarfForms, ref_sig8_not_first) {
444   info.Append(98, '*');
445   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
446                           (DwarfAttribute) 0xd708d908,
447                           dwarf2reader::DW_FORM_ref_sig8);
448   info.D64(0xf72fa0cb6ddcf9d6ULL);
449   info.Finish();
450 
451   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
452   EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
453                                                  dwarf2reader::DW_FORM_ref_sig8,
454                                                  0xf72fa0cb6ddcf9d6ULL))
455       .InSequence(s)
456       .WillOnce(Return());
457   ExpectEndCompilationUnit();
458 
459   ParseCompilationUnit(GetParam(), 98);
460 }
461 
462 // Tests for the other attribute forms could go here.
463 
464 INSTANTIATE_TEST_CASE_P(
465     HeaderVariants, DwarfForms,
466     ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
467                       DwarfHeaderParams(kLittleEndian, 4, 2, 8),
468                       DwarfHeaderParams(kLittleEndian, 4, 3, 4),
469                       DwarfHeaderParams(kLittleEndian, 4, 3, 8),
470                       DwarfHeaderParams(kLittleEndian, 4, 4, 4),
471                       DwarfHeaderParams(kLittleEndian, 4, 4, 8),
472                       DwarfHeaderParams(kLittleEndian, 8, 2, 4),
473                       DwarfHeaderParams(kLittleEndian, 8, 2, 8),
474                       DwarfHeaderParams(kLittleEndian, 8, 3, 4),
475                       DwarfHeaderParams(kLittleEndian, 8, 3, 8),
476                       DwarfHeaderParams(kLittleEndian, 8, 4, 4),
477                       DwarfHeaderParams(kLittleEndian, 8, 4, 8),
478                       DwarfHeaderParams(kBigEndian,    4, 2, 4),
479                       DwarfHeaderParams(kBigEndian,    4, 2, 8),
480                       DwarfHeaderParams(kBigEndian,    4, 3, 4),
481                       DwarfHeaderParams(kBigEndian,    4, 3, 8),
482                       DwarfHeaderParams(kBigEndian,    4, 4, 4),
483                       DwarfHeaderParams(kBigEndian,    4, 4, 8),
484                       DwarfHeaderParams(kBigEndian,    8, 2, 4),
485                       DwarfHeaderParams(kBigEndian,    8, 2, 8),
486                       DwarfHeaderParams(kBigEndian,    8, 3, 4),
487                       DwarfHeaderParams(kBigEndian,    8, 3, 8),
488                       DwarfHeaderParams(kBigEndian,    8, 4, 4),
489                       DwarfHeaderParams(kBigEndian,    8, 4, 8)));
490