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
47using google_breakpad::test_assembler::Endianness;
48using google_breakpad::test_assembler::Label;
49using google_breakpad::test_assembler::Section;
50using google_breakpad::test_assembler::kBigEndian;
51using google_breakpad::test_assembler::kLittleEndian;
52
53using dwarf2reader::ByteReader;
54using dwarf2reader::CompilationUnit;
55using dwarf2reader::Dwarf2Handler;
56using dwarf2reader::DwarfAttribute;
57using dwarf2reader::DwarfForm;
58using dwarf2reader::DwarfHasChild;
59using dwarf2reader::DwarfTag;
60using dwarf2reader::ENDIANNESS_BIG;
61using dwarf2reader::ENDIANNESS_LITTLE;
62using dwarf2reader::SectionMap;
63
64using std::vector;
65using testing::InSequence;
66using testing::Pointee;
67using testing::Return;
68using testing::Sequence;
69using testing::Test;
70using testing::TestWithParam;
71using testing::_;
72
73class 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
107struct DIEFixture {
108
109  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.
129  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
149struct DwarfHeaderParams {
150  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
160class DwarfHeader: public DIEFixture,
161                   public TestWithParam<DwarfHeaderParams> { };
162
163TEST_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
203INSTANTIATE_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
230struct 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.
235  void StartSingleAttributeDIE(const DwarfHeaderParams &params,
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.
255  void ExpectBeginCompilationUnit(const DwarfHeaderParams &params,
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
268  void ExpectEndCompilationUnit() {
269    EXPECT_CALL(handler, EndDIE(_))
270        .InSequence(s)
271        .WillOnce(Return());
272  }
273
274  void ParseCompilationUnit(const DwarfHeaderParams &params, 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
285struct DwarfForms: public DwarfFormsFixture,
286                   public TestWithParam<DwarfHeaderParams> { };
287
288TEST_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
313TEST_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
331TEST_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
352TEST_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
371TEST_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
396TEST_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
415TEST_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.
438TEST_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
459INSTANTIATE_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