1// Copyright (c) 2010 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// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule.
33
34#include <string>
35#include <utility>
36#include <vector>
37
38#include "breakpad_googletest_includes.h"
39#include "common/dwarf_cu_to_module.h"
40#include "common/using_std_string.h"
41
42using std::make_pair;
43using std::vector;
44
45using dwarf2reader::DIEHandler;
46using dwarf2reader::DwarfTag;
47using dwarf2reader::DwarfAttribute;
48using dwarf2reader::DwarfForm;
49using dwarf2reader::DwarfInline;
50using dwarf2reader::RootDIEHandler;
51using google_breakpad::DwarfCUToModule;
52using google_breakpad::Module;
53
54using ::testing::_;
55using ::testing::AtMost;
56using ::testing::Invoke;
57using ::testing::Return;
58using ::testing::Test;
59using ::testing::TestWithParam;
60using ::testing::Values;
61using ::testing::ValuesIn;
62
63// Mock classes.
64
65class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler {
66 public:
67  MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir));
68  MOCK_METHOD4(ReadProgram, void(const char* program, uint64 length,
69                                 Module *module, vector<Module::Line> *lines));
70};
71
72class MockWarningReporter: public DwarfCUToModule::WarningReporter {
73 public:
74  MockWarningReporter(const string &filename, uint64 cu_offset)
75      : DwarfCUToModule::WarningReporter(filename, cu_offset) { }
76  MOCK_METHOD1(SetCUName, void(const string &name));
77  MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target));
78  MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target));
79  MOCK_METHOD1(MissingSection, void(const string &section_name));
80  MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset));
81  MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
82  MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
83  MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
84  MOCK_METHOD2(DemangleError, void(const string &input, int error));
85  MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target));
86};
87
88// A fixture class including all the objects needed to handle a
89// compilation unit, and their entourage. It includes member functions
90// for doing common kinds of setup and tests.
91class CUFixtureBase {
92 public:
93  // If we have:
94  //
95  //   vector<Module::Line> lines;
96  //   AppendLinesFunctor appender(lines);
97  //
98  // then doing:
99  //
100  //   appender(line_program, length, module, line_vector);
101  //
102  // will append lines to the end of line_vector.  We can use this with
103  // MockLineToModuleHandler like this:
104  //
105  //   MockLineToModuleHandler l2m;
106  //   EXPECT_CALL(l2m, ReadProgram(_,_,_,_))
107  //       .WillOnce(DoAll(Invoke(appender), Return()));
108  //
109  // in which case calling l2m with some line vector will append lines.
110  class AppendLinesFunctor {
111   public:
112    explicit AppendLinesFunctor(
113        const vector<Module::Line> *lines) : lines_(lines) { }
114    void operator()(const char *program, uint64 length,
115                    Module *module, vector<Module::Line> *lines) {
116      lines->insert(lines->end(), lines_->begin(), lines_->end());
117    }
118   private:
119    const vector<Module::Line> *lines_;
120  };
121
122  CUFixtureBase()
123      : module_("module-name", "module-os", "module-arch", "module-id"),
124        file_context_("dwarf-filename", &module_, true),
125        language_(dwarf2reader::DW_LANG_none),
126        language_signed_(false),
127        appender_(&lines_),
128        reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL),
129        root_handler_(&file_context_, &line_reader_, &reporter_),
130        functions_filled_(false) {
131    // By default, expect no warnings to be reported, and expect the
132    // compilation unit's name to be provided. The test can override
133    // these expectations.
134    EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1);
135    EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0);
136    EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0);
137    EXPECT_CALL(reporter_, MissingSection(_)).Times(0);
138    EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0);
139    EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0);
140    EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0);
141    EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0);
142    EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(0);
143
144    // By default, expect the line program reader not to be invoked. We
145    // may override this in StartCU.
146    EXPECT_CALL(line_reader_, StartCompilationUnit(_)).Times(0);
147    EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_)).Times(0);
148
149    // The handler will consult this section map to decide what to
150    // pass to our line reader.
151    file_context_.AddSectionToSectionMap(".debug_line",
152                                         dummy_line_program_,
153                                         dummy_line_size_);
154  }
155
156  // Add a line with the given address, size, filename, and line
157  // number to the end of the statement list the handler will receive
158  // when it invokes its LineToModuleHandler. Call this before calling
159  // StartCU.
160  void PushLine(Module::Address address, Module::Address size,
161                const string &filename, int line_number);
162
163  // Use LANGUAGE for the compilation unit. More precisely, arrange
164  // for StartCU to pass the compilation unit's root DIE a
165  // DW_AT_language attribute whose value is LANGUAGE.
166  void SetLanguage(dwarf2reader::DwarfLanguage language) {
167    language_ = language;
168  }
169
170  // If SIGNED true, have StartCU report DW_AT_language as a signed
171  // attribute; if false, have it report it as unsigned.
172  void SetLanguageSigned(bool is_signed) { language_signed_ = is_signed; }
173
174  // Call the handler this.root_handler_'s StartCompilationUnit and
175  // StartRootDIE member functions, passing it appropriate attributes as
176  // determined by prior calls to PushLine and SetLanguage. Leave
177  // this.root_handler_ ready to hear about children: call
178  // this.root_handler_.EndAttributes, but not this.root_handler_.Finish.
179  void StartCU();
180
181  // Have HANDLER process some strange attribute/form/value triples.
182  void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler);
183
184  // Start a child DIE of PARENT with the given tag and name. Leave
185  // the handler ready to hear about children: call EndAttributes, but
186  // not Finish.
187  DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag,
188                            const string &name);
189
190  // Start a child DIE of PARENT with the given tag and a
191  // DW_AT_specification attribute whose value is SPECIFICATION. Leave
192  // the handler ready to hear about children: call EndAttributes, but
193  // not Finish. If NAME is non-zero, use it as the DW_AT_name
194  // attribute.
195  DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag,
196                                uint64 specification, const char *name = NULL);
197
198  // Define a function as a child of PARENT with the given name, address, and
199  // size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute
200  // will be written as an address; otherwise it will be written as the
201  // function's size. Call EndAttributes and Finish; one cannot define
202  // children of the defined function's DIE.
203  void DefineFunction(DIEHandler *parent, const string &name,
204                      Module::Address address, Module::Address size,
205                      const char* mangled_name,
206                      DwarfForm high_pc_form = dwarf2reader::DW_FORM_addr);
207
208  // Create a declaration DIE as a child of PARENT with the given
209  // offset, tag and name. If NAME is the empty string, don't provide
210  // a DW_AT_name attribute. Call EndAttributes and Finish.
211  void DeclarationDIE(DIEHandler *parent, uint64 offset,
212                      DwarfTag tag, const string &name,
213                      const string &mangled_name);
214
215  // Create a definition DIE as a child of PARENT with the given tag
216  // that refers to the declaration DIE at offset SPECIFICATION as its
217  // specification. If NAME is non-empty, pass it as the DW_AT_name
218  // attribute. If SIZE is non-zero, record ADDRESS and SIZE as
219  // low_pc/high_pc attributes.
220  void DefinitionDIE(DIEHandler *parent, DwarfTag tag,
221                     uint64 specification, const string &name,
222                     Module::Address address = 0, Module::Address size = 0);
223
224  // Create an inline DW_TAG_subprogram DIE as a child of PARENT.  If
225  // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at
226  // offset SPECIFICATION as its specification.  If Name is non-empty, pass it
227  // as the DW_AT_name attribute.
228  void AbstractInstanceDIE(DIEHandler *parent, uint64 offset,
229                           DwarfInline type, uint64 specification,
230                           const string &name,
231                           DwarfForm form = dwarf2reader::DW_FORM_data1);
232
233  // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to
234  // ORIGIN in its DW_AT_abstract_origin attribute.  If NAME is the empty
235  // string, don't provide a DW_AT_name attribute.
236  void DefineInlineInstanceDIE(DIEHandler *parent, const string &name,
237                               uint64 origin, Module::Address address,
238                               Module::Address size);
239
240  // The following Test* functions should be called after calling
241  // this.root_handler_.Finish. After that point, no further calls
242  // should be made on the handler.
243
244  // Test that the number of functions defined in the module this.module_ is
245  // equal to EXPECTED.
246  void TestFunctionCount(size_t expected);
247
248  // Test that the I'th function (ordered by address) in the module
249  // this.module_ has the given name, address, and size, and that its
250  // parameter size is zero.
251  void TestFunction(int i, const string &name,
252                    Module::Address address, Module::Address size);
253
254  // Test that the number of source lines owned by the I'th function
255  // in the module this.module_ is equal to EXPECTED.
256  void TestLineCount(int i, size_t expected);
257
258  // Test that the J'th line (ordered by address) of the I'th function
259  // (again, by address) has the given address, size, filename, and
260  // line number.
261  void TestLine(int i, int j, Module::Address address, Module::Address size,
262                const string &filename, int number);
263
264  // Actual objects under test.
265  Module module_;
266  DwarfCUToModule::FileContext file_context_;
267
268  // If this is not DW_LANG_none, we'll pass it as a DW_AT_language
269  // attribute to the compilation unit. This defaults to DW_LANG_none.
270  dwarf2reader::DwarfLanguage language_;
271
272  // If this is true, report DW_AT_language as a signed value; if false,
273  // report it as an unsigned value.
274  bool language_signed_;
275
276  // If this is not empty, we'll give the CU a DW_AT_comp_dir attribute that
277  // indicates the path that this compilation unit was compiled in.
278  string compilation_dir_;
279
280  // If this is not empty, we'll give the CU a DW_AT_stmt_list
281  // attribute that, when passed to line_reader_, adds these lines to the
282  // provided lines array.
283  vector<Module::Line> lines_;
284
285  // Mock line program reader.
286  MockLineToModuleHandler line_reader_;
287  AppendLinesFunctor appender_;
288  static const char dummy_line_program_[];
289  static const size_t dummy_line_size_;
290
291  MockWarningReporter reporter_;
292  DwarfCUToModule root_handler_;
293
294 private:
295  // Fill functions_, if we haven't already.
296  void FillFunctions();
297
298  // If functions_filled_ is true, this is a table of functions we've
299  // extracted from module_, sorted by address.
300  vector<Module::Function *> functions_;
301  // True if we have filled the above vector with this.module_'s function list.
302  bool functions_filled_;
303};
304
305const char CUFixtureBase::dummy_line_program_[] = "lots of fun data";
306const size_t CUFixtureBase::dummy_line_size_ =
307    sizeof(CUFixtureBase::dummy_line_program_);
308
309void CUFixtureBase::PushLine(Module::Address address, Module::Address size,
310                             const string &filename, int line_number) {
311  Module::Line l;
312  l.address = address;
313  l.size = size;
314  l.file = module_.FindFile(filename);
315  l.number = line_number;
316  lines_.push_back(l);
317}
318
319void CUFixtureBase::StartCU() {
320  if (!compilation_dir_.empty())
321    EXPECT_CALL(line_reader_,
322                StartCompilationUnit(compilation_dir_)).Times(1);
323
324  // If we have lines, make the line reader expect to be invoked at
325  // most once. (Hey, if the handler can pass its tests without
326  // bothering to read the line number data, that's great.)
327  // Have it add the lines passed to PushLine. Otherwise, leave the
328  // initial expectation (no calls) in force.
329  if (!lines_.empty())
330    EXPECT_CALL(line_reader_,
331                ReadProgram(&dummy_line_program_[0], dummy_line_size_,
332                            &module_, _))
333        .Times(AtMost(1))
334        .WillOnce(DoAll(Invoke(appender_), Return()));
335
336  ASSERT_TRUE(root_handler_
337              .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44,
338                                    0x4241b4f33720dd5cULL, 3));
339  {
340    ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL,
341                                           dwarf2reader::DW_TAG_compile_unit));
342  }
343  root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name,
344                                       dwarf2reader::DW_FORM_strp,
345                                       "compilation-unit-name");
346  if (!compilation_dir_.empty())
347    root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_comp_dir,
348                                         dwarf2reader::DW_FORM_strp,
349                                         compilation_dir_);
350  if (!lines_.empty())
351    root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list,
352                                           dwarf2reader::DW_FORM_ref4,
353                                           0);
354  if (language_ != dwarf2reader::DW_LANG_none) {
355    if (language_signed_)
356      root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language,
357                                           dwarf2reader::DW_FORM_sdata,
358                                           language_);
359    else
360      root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language,
361                                             dwarf2reader::DW_FORM_udata,
362                                             language_);
363  }
364  ASSERT_TRUE(root_handler_.EndAttributes());
365}
366
367void CUFixtureBase::ProcessStrangeAttributes(
368    dwarf2reader::DIEHandler *handler) {
369  handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead,
370                                    (DwarfForm) 0x4106e4db,
371                                    0xa592571997facda1ULL);
372  handler->ProcessAttributeSigned((DwarfAttribute) 0x85380095,
373                                  (DwarfForm) 0x0f16fe87,
374                                  0x12602a4e3bf1f446LL);
375  handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f,
376                                     (DwarfForm) 0x829e038a,
377                                     0x50fddef44734fdecULL);
378  static const char buffer[10] = "frobynode";
379  handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51,
380                                  (DwarfForm) 0x2f43b041,
381                                  buffer, sizeof(buffer));
382  handler->ProcessAttributeString((DwarfAttribute) 0x2f43b041,
383                                  (DwarfForm) 0x895ffa23,
384                                  "strange string");
385}
386
387DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent,
388                                         DwarfTag tag,
389                                         const string &name) {
390  dwarf2reader::DIEHandler *handler
391    = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag);
392  if (!handler)
393    return NULL;
394  handler->ProcessAttributeString(dwarf2reader::DW_AT_name,
395                                  dwarf2reader::DW_FORM_strp,
396                                  name);
397  ProcessStrangeAttributes(handler);
398  if (!handler->EndAttributes()) {
399    handler->Finish();
400    delete handler;
401    return NULL;
402  }
403
404  return handler;
405}
406
407DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent,
408                                             DwarfTag tag,
409                                             uint64 specification,
410                                             const char *name) {
411  dwarf2reader::DIEHandler *handler
412    = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag);
413  if (!handler)
414    return NULL;
415  if (name)
416    handler->ProcessAttributeString(dwarf2reader::DW_AT_name,
417                                    dwarf2reader::DW_FORM_strp,
418                                    name);
419  handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
420                                     dwarf2reader::DW_FORM_ref4,
421                                     specification);
422  if (!handler->EndAttributes()) {
423    handler->Finish();
424    delete handler;
425    return NULL;
426  }
427
428  return handler;
429}
430
431void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent,
432                                   const string &name, Module::Address address,
433                                   Module::Address size,
434                                   const char* mangled_name,
435                                   DwarfForm high_pc_form) {
436  dwarf2reader::DIEHandler *func
437      = parent->FindChildHandler(0xe34797c7e68590a8LL,
438                                 dwarf2reader::DW_TAG_subprogram);
439  ASSERT_TRUE(func != NULL);
440  func->ProcessAttributeString(dwarf2reader::DW_AT_name,
441                               dwarf2reader::DW_FORM_strp,
442                               name);
443  func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
444                                 dwarf2reader::DW_FORM_addr,
445                                 address);
446
447  Module::Address high_pc = size;
448  if (high_pc_form == dwarf2reader::DW_FORM_addr) {
449    high_pc += address;
450  }
451  func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
452                                 high_pc_form,
453                                 high_pc);
454
455  if (mangled_name)
456    func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name,
457                                 dwarf2reader::DW_FORM_strp,
458                                 mangled_name);
459
460  ProcessStrangeAttributes(func);
461  EXPECT_TRUE(func->EndAttributes());
462  func->Finish();
463  delete func;
464}
465
466void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset,
467                                   DwarfTag tag,
468                                   const string &name,
469                                   const string &mangled_name) {
470  dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag);
471  ASSERT_TRUE(die != NULL);
472  if (!name.empty())
473    die->ProcessAttributeString(dwarf2reader::DW_AT_name,
474                                dwarf2reader::DW_FORM_strp,
475                                name);
476  if (!mangled_name.empty())
477    die->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name,
478                                dwarf2reader::DW_FORM_strp,
479                                mangled_name);
480
481  die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration,
482                                dwarf2reader::DW_FORM_flag,
483                                1);
484  EXPECT_TRUE(die->EndAttributes());
485  die->Finish();
486  delete die;
487}
488
489void CUFixtureBase::DefinitionDIE(DIEHandler *parent,
490                                  DwarfTag tag,
491                                  uint64 specification,
492                                  const string &name,
493                                  Module::Address address,
494                                  Module::Address size) {
495  dwarf2reader::DIEHandler *die
496    = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag);
497  ASSERT_TRUE(die != NULL);
498  die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
499                                 dwarf2reader::DW_FORM_ref4,
500                                 specification);
501  if (!name.empty())
502    die->ProcessAttributeString(dwarf2reader::DW_AT_name,
503                                dwarf2reader::DW_FORM_strp,
504                                name);
505  if (size) {
506    die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
507                                  dwarf2reader::DW_FORM_addr,
508                                  address);
509    die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
510                                  dwarf2reader::DW_FORM_addr,
511                                  address + size);
512  }
513  EXPECT_TRUE(die->EndAttributes());
514  die->Finish();
515  delete die;
516}
517
518void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent,
519                                        uint64 offset,
520                                        DwarfInline type,
521                                        uint64 specification,
522                                        const string &name,
523                                        DwarfForm form) {
524  dwarf2reader::DIEHandler *die
525    = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram);
526  ASSERT_TRUE(die != NULL);
527  if (specification != 0ULL)
528    die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
529                                   dwarf2reader::DW_FORM_ref4,
530                                   specification);
531  if (form == dwarf2reader::DW_FORM_sdata) {
532    die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type);
533  } else {
534    die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type);
535  }
536  if (!name.empty())
537    die->ProcessAttributeString(dwarf2reader::DW_AT_name,
538                                dwarf2reader::DW_FORM_strp,
539                                name);
540
541  EXPECT_TRUE(die->EndAttributes());
542  die->Finish();
543  delete die;
544}
545
546void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent,
547                                            const string &name,
548                                            uint64 origin,
549                                            Module::Address address,
550                                            Module::Address size) {
551  dwarf2reader::DIEHandler *func
552      = parent->FindChildHandler(0x11c70f94c6e87ccdLL,
553                                 dwarf2reader::DW_TAG_subprogram);
554  ASSERT_TRUE(func != NULL);
555  if (!name.empty()) {
556    func->ProcessAttributeString(dwarf2reader::DW_AT_name,
557                                 dwarf2reader::DW_FORM_strp,
558                                 name);
559  }
560  func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
561                                 dwarf2reader::DW_FORM_addr,
562                                 address);
563  func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
564                                 dwarf2reader::DW_FORM_addr,
565                                 address + size);
566  func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin,
567                                 dwarf2reader::DW_FORM_ref4,
568                                 origin);
569  ProcessStrangeAttributes(func);
570  EXPECT_TRUE(func->EndAttributes());
571  func->Finish();
572  delete func;
573}
574
575void CUFixtureBase::FillFunctions() {
576  if (functions_filled_)
577    return;
578  module_.GetFunctions(&functions_, functions_.end());
579  sort(functions_.begin(), functions_.end(),
580       Module::Function::CompareByAddress);
581  functions_filled_ = true;
582}
583
584void CUFixtureBase::TestFunctionCount(size_t expected) {
585  FillFunctions();
586  ASSERT_EQ(expected, functions_.size());
587}
588
589void CUFixtureBase::TestFunction(int i, const string &name,
590                                 Module::Address address,
591                                 Module::Address size) {
592  FillFunctions();
593  ASSERT_LT((size_t) i, functions_.size());
594
595  Module::Function *function = functions_[i];
596  EXPECT_EQ(name,    function->name);
597  EXPECT_EQ(address, function->address);
598  EXPECT_EQ(size,    function->size);
599  EXPECT_EQ(0U,      function->parameter_size);
600}
601
602void CUFixtureBase::TestLineCount(int i, size_t expected) {
603  FillFunctions();
604  ASSERT_LT((size_t) i, functions_.size());
605
606  ASSERT_EQ(expected, functions_[i]->lines.size());
607}
608
609void CUFixtureBase::TestLine(int i, int j,
610                             Module::Address address, Module::Address size,
611                             const string &filename, int number) {
612  FillFunctions();
613  ASSERT_LT((size_t) i, functions_.size());
614  ASSERT_LT((size_t) j, functions_[i]->lines.size());
615
616  Module::Line *line = &functions_[i]->lines[j];
617  EXPECT_EQ(address,  line->address);
618  EXPECT_EQ(size,     line->size);
619  EXPECT_EQ(filename, line->file->name.c_str());
620  EXPECT_EQ(number,   line->number);
621}
622
623// Include caller locations for our test subroutines.
624#define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0)
625#define PushLine(a,b,c,d)         TRACE(PushLine((a),(b),(c),(d)))
626#define SetLanguage(a)            TRACE(SetLanguage(a))
627#define StartCU()                 TRACE(StartCU())
628#define DefineFunction(a,b,c,d,e) TRACE(DefineFunction((a),(b),(c),(d),(e)))
629// (DefineFunction) instead of DefineFunction to avoid macro expansion.
630#define DefineFunction6(a,b,c,d,e,f) \
631    TRACE((DefineFunction)((a),(b),(c),(d),(e),(f)))
632#define DeclarationDIE(a,b,c,d,e) TRACE(DeclarationDIE((a),(b),(c),(d),(e)))
633#define DefinitionDIE(a,b,c,d,e,f) \
634    TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f)))
635#define TestFunctionCount(a)      TRACE(TestFunctionCount(a))
636#define TestFunction(a,b,c,d)     TRACE(TestFunction((a),(b),(c),(d)))
637#define TestLineCount(a,b)        TRACE(TestLineCount((a),(b)))
638#define TestLine(a,b,c,d,e,f)     TRACE(TestLine((a),(b),(c),(d),(e),(f)))
639
640class SimpleCU: public CUFixtureBase, public Test {
641};
642
643TEST_F(SimpleCU, CompilationDir) {
644  compilation_dir_ = "/src/build/";
645
646  StartCU();
647  root_handler_.Finish();
648}
649
650TEST_F(SimpleCU, OneFunc) {
651  PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);
652
653  StartCU();
654  DefineFunction(&root_handler_, "function1",
655                 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL);
656  root_handler_.Finish();
657
658  TestFunctionCount(1);
659  TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
660  TestLineCount(0, 1);
661  TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file",
662           246571772);
663}
664
665// As above, only DW_AT_high_pc is a length rather than an address.
666TEST_F(SimpleCU, OneFuncHighPcIsLength) {
667  PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);
668
669  StartCU();
670  DefineFunction6(&root_handler_, "function1",
671                  0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL,
672                  dwarf2reader::DW_FORM_udata);
673  root_handler_.Finish();
674
675  TestFunctionCount(1);
676  TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
677  TestLineCount(0, 1);
678  TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file",
679           246571772);
680}
681
682TEST_F(SimpleCU, MangledName) {
683  PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);
684
685  StartCU();
686  DefineFunction(&root_handler_, "function1",
687                 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "_ZN1n1fEi");
688  root_handler_.Finish();
689
690  TestFunctionCount(1);
691  TestFunction(0, "n::f(int)", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
692}
693
694TEST_F(SimpleCU, IrrelevantRootChildren) {
695  StartCU();
696  EXPECT_FALSE(root_handler_
697               .FindChildHandler(0x7db32bff4e2dcfb1ULL,
698                                 dwarf2reader::DW_TAG_lexical_block));
699}
700
701TEST_F(SimpleCU, IrrelevantNamedScopeChildren) {
702  StartCU();
703  DIEHandler *class_A_handler
704    = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
705  EXPECT_TRUE(class_A_handler != NULL);
706  EXPECT_FALSE(class_A_handler
707               ->FindChildHandler(0x02e55999b865e4e9ULL,
708                                  dwarf2reader::DW_TAG_lexical_block));
709  delete class_A_handler;
710}
711
712// Verify that FileContexts can safely be deleted unused.
713TEST_F(SimpleCU, UnusedFileContext) {
714  Module m("module-name", "module-os", "module-arch", "module-id");
715  DwarfCUToModule::FileContext fc("dwarf-filename", &m, true);
716
717  // Kludge: satisfy reporter_'s expectation.
718  reporter_.SetCUName("compilation-unit-name");
719}
720
721TEST_F(SimpleCU, InlineFunction) {
722  PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
723
724  StartCU();
725  AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
726                      dwarf2reader::DW_INL_inlined, 0, "inline-name");
727  DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
728                       0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
729  root_handler_.Finish();
730
731  TestFunctionCount(1);
732  TestFunction(0, "inline-name",
733               0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
734}
735
736TEST_F(SimpleCU, InlineFunctionSignedAttribute) {
737  PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
738
739  StartCU();
740  AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
741                      dwarf2reader::DW_INL_inlined, 0, "inline-name",
742                      dwarf2reader::DW_FORM_sdata);
743  DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
744                       0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
745  root_handler_.Finish();
746
747  TestFunctionCount(1);
748  TestFunction(0, "inline-name",
749               0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
750}
751
752// Any DIE with an DW_AT_inline attribute can be cited by
753// DW_AT_abstract_origin attributes --- even if the value of the
754// DW_AT_inline attribute is DW_INL_not_inlined.
755TEST_F(SimpleCU, AbstractOriginNotInlined) {
756  PushLine(0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL, "line-file", 6111581);
757
758  StartCU();
759  AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL,
760                      dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance");
761  DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL,
762                          0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL);
763  root_handler_.Finish();
764
765  TestFunctionCount(1);
766  TestFunction(0, "abstract-instance",
767               0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL);
768}
769
770TEST_F(SimpleCU, UnknownAbstractOrigin) {
771  EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return());
772  EXPECT_CALL(reporter_, UnnamedFunction(0x11c70f94c6e87ccdLL))
773    .WillOnce(Return());
774  PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
775
776  StartCU();
777  AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
778                      dwarf2reader::DW_INL_inlined, 0, "inline-name");
779  DefineInlineInstanceDIE(&root_handler_, "", 1ULL,
780                       0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
781  root_handler_.Finish();
782
783  TestFunctionCount(1);
784  TestFunction(0, "<name omitted>",
785               0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
786}
787
788TEST_F(SimpleCU, UnnamedFunction) {
789  EXPECT_CALL(reporter_, UnnamedFunction(0xe34797c7e68590a8LL))
790    .WillOnce(Return());
791  PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850);
792
793  StartCU();
794  DefineFunction(&root_handler_, "",
795                 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, NULL);
796  root_handler_.Finish();
797
798  TestFunctionCount(1);
799  TestFunction(0, "<name omitted>",
800               0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL);
801}
802
803// An address range.
804struct Range {
805  Module::Address start, end;
806};
807
808// Test data for pairing functions and lines.
809struct Situation {
810  // Two function intervals, and two line intervals.
811  Range functions[2], lines[2];
812
813  // The number of lines we expect to be assigned to each of the
814  // functions, and the address ranges.
815  int paired_count[2];
816  Range paired[2][2];
817
818  // The number of functions that are not entirely covered by lines,
819  // and vice versa.
820  int uncovered_functions, uncovered_lines;
821};
822
823#define PAIRING(func1_start, func1_end, func2_start, func2_end, \
824                line1_start, line1_end, line2_start, line2_end, \
825                func1_num_lines, func2_num_lines,               \
826                func1_line1_start, func1_line1_end,             \
827                func1_line2_start, func1_line2_end,             \
828                func2_line1_start, func2_line1_end,             \
829                func2_line2_start, func2_line2_end,             \
830                uncovered_functions, uncovered_lines)           \
831  { { { func1_start, func1_end }, { func2_start, func2_end } }, \
832    { { line1_start, line1_end }, { line2_start, line2_end } }, \
833    { func1_num_lines, func2_num_lines },                       \
834    { { { func1_line1_start, func1_line1_end },                 \
835        { func1_line2_start, func1_line2_end } },               \
836      { { func2_line1_start, func2_line1_end },                 \
837          { func2_line2_start, func2_line2_end } } },           \
838    uncovered_functions, uncovered_lines },
839
840Situation situations[] = {
841#include "common/testdata/func-line-pairing.h"
842};
843
844#undef PAIRING
845
846class FuncLinePairing: public CUFixtureBase,
847                       public TestWithParam<Situation> { };
848
849INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing,
850                        ValuesIn(situations));
851
852TEST_P(FuncLinePairing, Pairing) {
853  const Situation &s = GetParam();
854  PushLine(s.lines[0].start,
855           s.lines[0].end - s.lines[0].start,
856           "line-file", 67636963);
857  PushLine(s.lines[1].start,
858           s.lines[1].end - s.lines[1].start,
859           "line-file", 67636963);
860  if (s.uncovered_functions)
861    EXPECT_CALL(reporter_, UncoveredFunction(_))
862      .Times(s.uncovered_functions)
863      .WillRepeatedly(Return());
864  if (s.uncovered_lines)
865    EXPECT_CALL(reporter_, UncoveredLine(_))
866      .Times(s.uncovered_lines)
867      .WillRepeatedly(Return());
868
869  StartCU();
870  DefineFunction(&root_handler_, "function1",
871                 s.functions[0].start,
872                 s.functions[0].end - s.functions[0].start, NULL);
873  DefineFunction(&root_handler_, "function2",
874                 s.functions[1].start,
875                 s.functions[1].end - s.functions[1].start, NULL);
876  root_handler_.Finish();
877
878  TestFunctionCount(2);
879  TestFunction(0, "function1",
880               s.functions[0].start,
881               s.functions[0].end - s.functions[0].start);
882  TestLineCount(0, s.paired_count[0]);
883  for (int i = 0; i < s.paired_count[0]; i++)
884    TestLine(0, i, s.paired[0][i].start,
885             s.paired[0][i].end - s.paired[0][i].start,
886             "line-file", 67636963);
887  TestFunction(1, "function2",
888               s.functions[1].start,
889               s.functions[1].end - s.functions[1].start);
890  TestLineCount(1, s.paired_count[1]);
891  for (int i = 0; i < s.paired_count[1]; i++)
892    TestLine(1, i, s.paired[1][i].start,
893             s.paired[1][i].end - s.paired[1][i].start,
894             "line-file", 67636963);
895}
896
897TEST_F(FuncLinePairing, EmptyCU) {
898  StartCU();
899  root_handler_.Finish();
900
901  TestFunctionCount(0);
902}
903
904TEST_F(FuncLinePairing, LinesNoFuncs) {
905  PushLine(40, 2, "line-file", 82485646);
906  EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
907
908  StartCU();
909  root_handler_.Finish();
910
911  TestFunctionCount(0);
912}
913
914TEST_F(FuncLinePairing, FuncsNoLines) {
915  EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
916
917  StartCU();
918  DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U,
919                 NULL);
920  root_handler_.Finish();
921
922  TestFunctionCount(1);
923  TestFunction(0, "function1", 0x127da12ffcf5c51fULL, 0x1000U);
924}
925
926TEST_F(FuncLinePairing, GapThenFunction) {
927  PushLine(20, 2, "line-file-2", 174314698);
928  PushLine(10, 2, "line-file-1", 263008005);
929
930  StartCU();
931  DefineFunction(&root_handler_, "function1", 10, 2, NULL);
932  DefineFunction(&root_handler_, "function2", 20, 2, NULL);
933  root_handler_.Finish();
934
935  TestFunctionCount(2);
936  TestFunction(0, "function1", 10, 2);
937  TestLineCount(0, 1);
938  TestLine(0, 0, 10, 2, "line-file-1", 263008005);
939  TestFunction(1, "function2", 20, 2);
940  TestLineCount(1, 1);
941  TestLine(1, 0, 20, 2, "line-file-2", 174314698);
942}
943
944// If GCC emits padding after one function to align the start of
945// the next, then it will attribute the padding instructions to
946// the last source line of function (to reduce the size of the
947// line number info), but omit it from the DW_AT_{low,high}_pc
948// range given in .debug_info (since it costs nothing to be
949// precise there).  If we did use at least some of the line
950// we're about to skip, then assume this is what happened, and
951// don't warn.
952TEST_F(FuncLinePairing, GCCAlignmentStretch) {
953  PushLine(10, 10, "line-file", 63351048);
954  PushLine(20, 10, "line-file", 61661044);
955
956  StartCU();
957  DefineFunction(&root_handler_, "function1", 10, 5, NULL);
958  // five-byte gap between functions, covered by line 63351048.
959  // This should not elicit a warning.
960  DefineFunction(&root_handler_, "function2", 20, 10, NULL);
961  root_handler_.Finish();
962
963  TestFunctionCount(2);
964  TestFunction(0, "function1", 10, 5);
965  TestLineCount(0, 1);
966  TestLine(0, 0, 10, 5, "line-file", 63351048);
967  TestFunction(1, "function2", 20, 10);
968  TestLineCount(1, 1);
969  TestLine(1, 0, 20, 10, "line-file", 61661044);
970}
971
972// Unfortunately, neither the DWARF parser's handler interface nor the
973// DIEHandler interface is capable of expressing a function that abuts
974// the end of the address space: the high_pc value looks like zero.
975
976TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) {
977  PushLine(0xfffffffffffffff0ULL, 16, "line-file", 63351048);
978  EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
979
980  StartCU();
981  DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6, NULL);
982  DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5, NULL);
983  root_handler_.Finish();
984
985  TestFunctionCount(2);
986  TestFunction(0, "function1", 0xfffffffffffffff0ULL, 6);
987  TestLineCount(0, 1);
988  TestLine(0, 0, 0xfffffffffffffff0ULL, 6, "line-file", 63351048);
989  TestFunction(1, "function2", 0xfffffffffffffffaULL, 5);
990  TestLineCount(1, 1);
991  TestLine(1, 0, 0xfffffffffffffffaULL, 5, "line-file", 63351048);
992}
993
994// A function with more than one uncovered area should only be warned
995// about once.
996TEST_F(FuncLinePairing, WarnOnceFunc) {
997  PushLine(20, 1, "line-file-2", 262951329);
998  PushLine(11, 1, "line-file-1", 219964021);
999  EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
1000
1001  StartCU();
1002  DefineFunction(&root_handler_, "function", 10, 11, NULL);
1003  root_handler_.Finish();
1004
1005  TestFunctionCount(1);
1006  TestFunction(0, "function", 10, 11);
1007  TestLineCount(0, 2);
1008  TestLine(0, 0, 11, 1, "line-file-1", 219964021);
1009  TestLine(0, 1, 20, 1, "line-file-2", 262951329);
1010}
1011
1012// A line with more than one uncovered area should only be warned
1013// about once.
1014TEST_F(FuncLinePairing, WarnOnceLine) {
1015  PushLine(10, 20, "filename1", 118581871);
1016  EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
1017
1018  StartCU();
1019  DefineFunction(&root_handler_, "function1", 11, 1, NULL);
1020  DefineFunction(&root_handler_, "function2", 13, 1, NULL);
1021  root_handler_.Finish();
1022
1023  TestFunctionCount(2);
1024  TestFunction(0, "function1", 11, 1);
1025  TestLineCount(0, 1);
1026  TestLine(0, 0, 11, 1, "filename1", 118581871);
1027  TestFunction(1, "function2", 13, 1);
1028  TestLineCount(1, 1);
1029  TestLine(1, 0, 13, 1, "filename1", 118581871);
1030}
1031
1032class CXXQualifiedNames: public CUFixtureBase,
1033                         public TestWithParam<DwarfTag> { };
1034
1035INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames,
1036                        Values(dwarf2reader::DW_TAG_class_type,
1037                               dwarf2reader::DW_TAG_structure_type,
1038                               dwarf2reader::DW_TAG_union_type,
1039                               dwarf2reader::DW_TAG_namespace));
1040
1041TEST_P(CXXQualifiedNames, TwoFunctions) {
1042  DwarfTag tag = GetParam();
1043
1044  SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
1045  PushLine(10, 1, "filename1", 69819327);
1046  PushLine(20, 1, "filename2", 95115701);
1047
1048  StartCU();
1049  DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag,
1050                                                "Enclosure");
1051  EXPECT_TRUE(enclosure_handler != NULL);
1052  DefineFunction(enclosure_handler, "func_B", 10, 1, NULL);
1053  DefineFunction(enclosure_handler, "func_C", 20, 1, NULL);
1054  enclosure_handler->Finish();
1055  delete enclosure_handler;
1056  root_handler_.Finish();
1057
1058  TestFunctionCount(2);
1059  TestFunction(0, "Enclosure::func_B", 10, 1);
1060  TestFunction(1, "Enclosure::func_C", 20, 1);
1061}
1062
1063TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) {
1064  DwarfTag tag = GetParam();
1065
1066  SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
1067  PushLine(10, 1, "line-file", 69819327);
1068
1069  StartCU();
1070  DIEHandler *namespace_handler
1071      = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
1072                      "Namespace");
1073  EXPECT_TRUE(namespace_handler != NULL);
1074  DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag,
1075                                                "Enclosure");
1076  EXPECT_TRUE(enclosure_handler != NULL);
1077  DefineFunction(enclosure_handler, "function", 10, 1, NULL);
1078  enclosure_handler->Finish();
1079  delete enclosure_handler;
1080  namespace_handler->Finish();
1081  delete namespace_handler;
1082  root_handler_.Finish();
1083
1084  TestFunctionCount(1);
1085  TestFunction(0, "Namespace::Enclosure::function", 10, 1);
1086}
1087
1088TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) {
1089  SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
1090  PushLine(10, 1, "filename1", 69819327);
1091
1092  StartCU();
1093  DIEHandler *namespace_handler
1094      = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
1095                      "namespace_A");
1096  EXPECT_TRUE(namespace_handler != NULL);
1097  DIEHandler *struct_handler
1098      = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type,
1099                      "struct_B");
1100  EXPECT_TRUE(struct_handler != NULL);
1101  DIEHandler *class_handler
1102      = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type,
1103                      "class_C");
1104  DefineFunction(class_handler, "function_D", 10, 1, NULL);
1105  class_handler->Finish();
1106  delete class_handler;
1107  struct_handler->Finish();
1108  delete struct_handler;
1109  namespace_handler->Finish();
1110  delete namespace_handler;
1111  root_handler_.Finish();
1112
1113  TestFunctionCount(1);
1114  TestFunction(0, "namespace_A::struct_B::class_C::function_D", 10, 1);
1115}
1116
1117struct LanguageAndQualifiedName {
1118  dwarf2reader::DwarfLanguage language;
1119  const char *name;
1120};
1121
1122const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = {
1123  { dwarf2reader::DW_LANG_none,           "class_A::function_B" },
1124  { dwarf2reader::DW_LANG_C,              "class_A::function_B" },
1125  { dwarf2reader::DW_LANG_C89,            "class_A::function_B" },
1126  { dwarf2reader::DW_LANG_C99,            "class_A::function_B" },
1127  { dwarf2reader::DW_LANG_C_plus_plus,    "class_A::function_B" },
1128  { dwarf2reader::DW_LANG_Java,           "class_A.function_B" },
1129  { dwarf2reader::DW_LANG_Cobol74,        "class_A::function_B" },
1130  { dwarf2reader::DW_LANG_Mips_Assembler, NULL }
1131};
1132
1133class QualifiedForLanguage
1134    : public CUFixtureBase,
1135      public TestWithParam<LanguageAndQualifiedName> { };
1136
1137INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage,
1138                        ValuesIn(LanguageAndQualifiedNameCases));
1139
1140TEST_P(QualifiedForLanguage, MemberFunction) {
1141  const LanguageAndQualifiedName &param = GetParam();
1142
1143  PushLine(10, 1, "line-file", 212966758);
1144  SetLanguage(param.language);
1145
1146  StartCU();
1147  DIEHandler *class_handler
1148      = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
1149                      "class_A");
1150  DefineFunction(class_handler, "function_B", 10, 1, NULL);
1151  class_handler->Finish();
1152  delete class_handler;
1153  root_handler_.Finish();
1154
1155  if (param.name) {
1156    TestFunctionCount(1);
1157    TestFunction(0, param.name, 10, 1);
1158  } else {
1159    TestFunctionCount(0);
1160  }
1161}
1162
1163TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) {
1164  const LanguageAndQualifiedName &param = GetParam();
1165
1166  PushLine(10, 1, "line-file", 212966758);
1167  SetLanguage(param.language);
1168  SetLanguageSigned(true);
1169
1170  StartCU();
1171  DIEHandler *class_handler
1172      = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
1173                      "class_A");
1174  DefineFunction(class_handler, "function_B", 10, 1, NULL);
1175  class_handler->Finish();
1176  delete class_handler;
1177  root_handler_.Finish();
1178
1179  if (param.name) {
1180    TestFunctionCount(1);
1181    TestFunction(0, param.name, 10, 1);
1182  } else {
1183    TestFunctionCount(0);
1184  }
1185}
1186
1187class Specifications: public CUFixtureBase, public Test { };
1188
1189TEST_F(Specifications, Function) {
1190  PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
1191
1192  StartCU();
1193  DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
1194                 dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
1195  DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
1196                0xcd3c51b946fb1eeeLL, "",
1197                0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
1198  root_handler_.Finish();
1199
1200  TestFunctionCount(1);
1201  TestFunction(0, "declaration-name",
1202               0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
1203}
1204
1205TEST_F(Specifications, MangledName) {
1206  PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
1207
1208  StartCU();
1209  DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
1210                 dwarf2reader::DW_TAG_subprogram, "declaration-name",
1211                 "_ZN1C1fEi");
1212  DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
1213                0xcd3c51b946fb1eeeLL, "",
1214                0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
1215  root_handler_.Finish();
1216
1217  TestFunctionCount(1);
1218  TestFunction(0, "C::f(int)",
1219               0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
1220}
1221
1222TEST_F(Specifications, MemberFunction) {
1223  PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691);
1224
1225  StartCU();
1226  DIEHandler *class_handler
1227    = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
1228  DeclarationDIE(class_handler, 0x7d83028c431406e8ULL,
1229                 dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
1230  class_handler->Finish();
1231  delete class_handler;
1232  DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
1233                0x7d83028c431406e8ULL, "",
1234                0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
1235  root_handler_.Finish();
1236
1237  TestFunctionCount(1);
1238  TestFunction(0, "class_A::declaration-name",
1239               0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
1240}
1241
1242// This case should gather the name from both the definition and the
1243// declaration's parent.
1244TEST_F(Specifications, FunctionDeclarationParent) {
1245  PushLine(0x463c9ddf405be227ULL, 0x6a47774af5049680ULL, "line-file", 70254922);
1246
1247  StartCU();
1248  {
1249    DIEHandler *class_handler
1250      = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
1251                      "class_A");
1252    ASSERT_TRUE(class_handler != NULL);
1253    DeclarationDIE(class_handler, 0x0e0e877c8404544aULL,
1254                   dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
1255    class_handler->Finish();
1256    delete class_handler;
1257  }
1258
1259  DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
1260                0x0e0e877c8404544aULL, "definition-name",
1261                0x463c9ddf405be227ULL, 0x6a47774af5049680ULL);
1262
1263  root_handler_.Finish();
1264
1265  TestFunctionCount(1);
1266  TestFunction(0, "class_A::definition-name",
1267               0x463c9ddf405be227ULL, 0x6a47774af5049680ULL);
1268}
1269
1270// Named scopes should also gather enclosing name components from
1271// their declarations.
1272TEST_F(Specifications, NamedScopeDeclarationParent) {
1273  PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604);
1274
1275  StartCU();
1276  {
1277    DIEHandler *space_handler
1278      = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
1279                      "space_A");
1280    ASSERT_TRUE(space_handler != NULL);
1281    DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL,
1282                   dwarf2reader::DW_TAG_class_type, "class-declaration-name",
1283                   "");
1284    space_handler->Finish();
1285    delete space_handler;
1286  }
1287
1288  {
1289    DIEHandler *class_handler
1290      = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
1291                          0x419bb1d12f9a73a2ULL, "class-definition-name");
1292    ASSERT_TRUE(class_handler != NULL);
1293    DefineFunction(class_handler, "function",
1294                   0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, NULL);
1295    class_handler->Finish();
1296    delete class_handler;
1297  }
1298
1299  root_handler_.Finish();
1300
1301  TestFunctionCount(1);
1302  TestFunction(0, "space_A::class-definition-name::function",
1303               0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL);
1304}
1305
1306// This test recreates bug 364.
1307TEST_F(Specifications, InlineFunction) {
1308  PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
1309
1310  StartCU();
1311  DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
1312                 dwarf2reader::DW_TAG_subprogram, "inline-name", "");
1313  AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
1314                      dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, "");
1315  DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
1316                       0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
1317  root_handler_.Finish();
1318
1319  TestFunctionCount(1);
1320  TestFunction(0, "inline-name",
1321               0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
1322}
1323
1324// Check name construction for a long chain containing each combination of:
1325// - struct, union, class, namespace
1326// - direct and definition
1327TEST_F(Specifications, LongChain) {
1328  PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926);
1329  SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
1330
1331  StartCU();
1332  // The structure we're building here is:
1333  // space_A full definition
1334  //   space_B declaration
1335  // space_B definition
1336  //   struct_C full definition
1337  //     struct_D declaration
1338  // struct_D definition
1339  //   union_E full definition
1340  //     union_F declaration
1341  // union_F definition
1342  //   class_G full definition
1343  //     class_H declaration
1344  // class_H definition
1345  //   func_I declaration
1346  // func_I definition
1347  //
1348  // So:
1349  // - space_A, struct_C, union_E, and class_G don't use specifications;
1350  // - space_B, struct_D, union_F, and class_H do.
1351  // - func_I uses a specification.
1352  //
1353  // The full name for func_I is thus:
1354  //
1355  // space_A::space_B::struct_C::struct_D::union_E::union_F::
1356  //   class_G::class_H::func_I
1357  {
1358    DIEHandler *space_A_handler
1359      = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
1360                      "space_A");
1361    DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL,
1362                   dwarf2reader::DW_TAG_namespace, "space_B", "");
1363    space_A_handler->Finish();
1364    delete space_A_handler;
1365  }
1366
1367  {
1368    DIEHandler *space_B_handler
1369      = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
1370                          0x2e111126496596e2ULL);
1371    DIEHandler *struct_C_handler
1372      = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type,
1373                      "struct_C");
1374    DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL,
1375                   dwarf2reader::DW_TAG_structure_type, "struct_D", "");
1376    struct_C_handler->Finish();
1377    delete struct_C_handler;
1378    space_B_handler->Finish();
1379    delete space_B_handler;
1380  }
1381
1382  {
1383    DIEHandler *struct_D_handler
1384      = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type,
1385                          0x20cd423bf2a25a4cULL);
1386    DIEHandler *union_E_handler
1387      = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type,
1388                      "union_E");
1389    DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL,
1390                   dwarf2reader::DW_TAG_union_type, "union_F", "");
1391    union_E_handler->Finish();
1392    delete union_E_handler;
1393    struct_D_handler->Finish();
1394    delete struct_D_handler;
1395  }
1396
1397  {
1398    DIEHandler *union_F_handler
1399      = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type,
1400                          0xe25c84805aa58c32ULL);
1401    DIEHandler *class_G_handler
1402      = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type,
1403                      "class_G");
1404    DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL,
1405                   dwarf2reader::DW_TAG_class_type, "class_H", "");
1406    class_G_handler->Finish();
1407    delete class_G_handler;
1408    union_F_handler->Finish();
1409    delete union_F_handler;
1410  }
1411
1412  {
1413    DIEHandler *class_H_handler
1414      = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
1415                          0xb70d960dcc173b6eULL);
1416    DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL,
1417                   dwarf2reader::DW_TAG_subprogram, "func_I", "");
1418    class_H_handler->Finish();
1419    delete class_H_handler;
1420  }
1421
1422  DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
1423                0x27ff829e3bf69f37ULL, "",
1424                0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
1425  root_handler_.Finish();
1426
1427  TestFunctionCount(1);
1428  TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F"
1429               "::class_G::class_H::func_I",
1430               0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
1431}
1432
1433TEST_F(Specifications, InterCU) {
1434  Module m("module-name", "module-os", "module-arch", "module-id");
1435  DwarfCUToModule::FileContext fc("dwarf-filename", &m, true);
1436  EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
1437  MockLineToModuleHandler lr;
1438  EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
1439
1440  // Kludge: satisfy reporter_'s expectation.
1441  reporter_.SetCUName("compilation-unit-name");
1442
1443  // First CU.  Declares class_A.
1444  {
1445    DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
1446    ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
1447    ASSERT_TRUE(root1_handler.StartRootDIE(1,
1448                                           dwarf2reader::DW_TAG_compile_unit));
1449    ProcessStrangeAttributes(&root1_handler);
1450    ASSERT_TRUE(root1_handler.EndAttributes());
1451    DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL,
1452                   dwarf2reader::DW_TAG_class_type, "class_A", "");
1453    root1_handler.Finish();
1454  }
1455
1456  // Second CU.  Defines class_A, declares member_func_B.
1457  {
1458    DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
1459    ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
1460    ASSERT_TRUE(root2_handler.StartRootDIE(1,
1461                                           dwarf2reader::DW_TAG_compile_unit));
1462    ASSERT_TRUE(root2_handler.EndAttributes());
1463    DIEHandler *class_A_handler
1464      = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type,
1465                          0xb8fbfdd5f0b26fceULL);
1466    DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL,
1467                   dwarf2reader::DW_TAG_subprogram, "member_func_B", "");
1468    class_A_handler->Finish();
1469    delete class_A_handler;
1470    root2_handler.Finish();
1471  }
1472
1473  // Third CU.  Defines member_func_B.
1474  {
1475    DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
1476    ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
1477    ASSERT_TRUE(root3_handler.StartRootDIE(1,
1478                                           dwarf2reader::DW_TAG_compile_unit));
1479    ASSERT_TRUE(root3_handler.EndAttributes());
1480    DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram,
1481                  0xb01fef8b380bd1a2ULL, "",
1482                  0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL);
1483    root3_handler.Finish();
1484  }
1485
1486  vector<Module::Function *> functions;
1487  m.GetFunctions(&functions, functions.end());
1488  EXPECT_EQ(1U, functions.size());
1489  EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str());
1490}
1491
1492TEST_F(Specifications, UnhandledInterCU) {
1493  Module m("module-name", "module-os", "module-arch", "module-id");
1494  DwarfCUToModule::FileContext fc("dwarf-filename", &m, false);
1495  EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
1496  MockLineToModuleHandler lr;
1497  EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
1498
1499  // Kludge: satisfy reporter_'s expectation.
1500  reporter_.SetCUName("compilation-unit-name");
1501
1502  // First CU.  Declares class_A.
1503  {
1504    DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
1505    ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
1506    ASSERT_TRUE(root1_handler.StartRootDIE(1,
1507                                           dwarf2reader::DW_TAG_compile_unit));
1508    ProcessStrangeAttributes(&root1_handler);
1509    ASSERT_TRUE(root1_handler.EndAttributes());
1510    DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL,
1511                   dwarf2reader::DW_TAG_class_type, "class_A", "");
1512    root1_handler.Finish();
1513  }
1514
1515  // Second CU.  Defines class_A, declares member_func_B.
1516  {
1517    DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
1518    ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
1519    ASSERT_TRUE(root2_handler.StartRootDIE(1,
1520                                           dwarf2reader::DW_TAG_compile_unit));
1521    ASSERT_TRUE(root2_handler.EndAttributes());
1522    EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1);
1523    DIEHandler *class_A_handler
1524      = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type,
1525                          0xb8fbfdd5f0b26fceULL);
1526    DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL,
1527                   dwarf2reader::DW_TAG_subprogram, "member_func_B", "");
1528    class_A_handler->Finish();
1529    delete class_A_handler;
1530    root2_handler.Finish();
1531  }
1532
1533  // Third CU.  Defines member_func_B.
1534  {
1535    DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
1536    ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
1537    ASSERT_TRUE(root3_handler.StartRootDIE(1,
1538                                           dwarf2reader::DW_TAG_compile_unit));
1539    ASSERT_TRUE(root3_handler.EndAttributes());
1540    EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1);
1541    EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1);
1542    DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram,
1543                  0xb01fef8b380bd1a2ULL, "",
1544                  0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL);
1545    root3_handler.Finish();
1546  }
1547}
1548
1549TEST_F(Specifications, BadOffset) {
1550  PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272);
1551  EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL))
1552    .WillOnce(Return());
1553
1554  StartCU();
1555  DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL,
1556                 dwarf2reader::DW_TAG_subprogram, "", "");
1557  DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
1558                0x2be953efa6f9a996ULL, "function",
1559                0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL);
1560  root_handler_.Finish();
1561}
1562
1563TEST_F(Specifications, FunctionDefinitionHasOwnName) {
1564  PushLine(0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL, "line-file", 56792403);
1565
1566  StartCU();
1567  DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL,
1568                 dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
1569  DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
1570                0xc34ff4786cae78bdULL, "definition-name",
1571                0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL);
1572  root_handler_.Finish();
1573
1574  TestFunctionCount(1);
1575  TestFunction(0, "definition-name",
1576               0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL);
1577}
1578
1579TEST_F(Specifications, ClassDefinitionHasOwnName) {
1580  PushLine(0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL, "line-file", 57119241);
1581
1582  StartCU();
1583  DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL,
1584                 dwarf2reader::DW_TAG_class_type, "class-declaration-name", "");
1585
1586  dwarf2reader::DIEHandler *class_definition
1587    = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
1588                        0xd0fe467ec2f1a58cULL, "class-definition-name");
1589  ASSERT_TRUE(class_definition);
1590  DeclarationDIE(class_definition, 0x6d028229c15623dbULL,
1591                 dwarf2reader::DW_TAG_subprogram,
1592                 "function-declaration-name", "");
1593  class_definition->Finish();
1594  delete class_definition;
1595
1596  DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
1597                0x6d028229c15623dbULL, "function-definition-name",
1598                0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL);
1599
1600  root_handler_.Finish();
1601
1602  TestFunctionCount(1);
1603  TestFunction(0, "class-definition-name::function-definition-name",
1604               0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL);
1605}
1606
1607// DIEs that cite a specification should prefer the specification's
1608// parents over their own when choosing qualified names. In this test,
1609// we take the name from our definition but the enclosing scope name
1610// from our declaration. I don't see why they'd ever be different, but
1611// we want to verify what DwarfCUToModule is looking at.
1612TEST_F(Specifications, PreferSpecificationParents) {
1613  PushLine(0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL, "line-file", 79488694);
1614
1615  StartCU();
1616  {
1617    dwarf2reader::DIEHandler *declaration_class_handler =
1618      StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
1619                    "declaration-class");
1620    DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL,
1621                   dwarf2reader::DW_TAG_subprogram, "function-declaration",
1622                   "");
1623    declaration_class_handler->Finish();
1624    delete declaration_class_handler;
1625  }
1626  {
1627    dwarf2reader::DIEHandler *definition_class_handler
1628      = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
1629                      "definition-class");
1630    DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram,
1631                  0x9ddb35517455ef7aULL, "function-definition",
1632                  0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL);
1633    definition_class_handler->Finish();
1634    delete definition_class_handler;
1635  }
1636  root_handler_.Finish();
1637
1638  TestFunctionCount(1);
1639  TestFunction(0, "declaration-class::function-definition",
1640               0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL);
1641}
1642
1643class CUErrors: public CUFixtureBase, public Test { };
1644
1645TEST_F(CUErrors, BadStmtList) {
1646  EXPECT_CALL(reporter_, BadLineInfoOffset(dummy_line_size_ + 10)).Times(1);
1647
1648  ASSERT_TRUE(root_handler_
1649              .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd,
1650                                    0x2d7d19546cf6590cULL, 3));
1651  ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL,
1652                                         dwarf2reader::DW_TAG_compile_unit));
1653  root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name,
1654                                       dwarf2reader::DW_FORM_strp,
1655                                       "compilation-unit-name");
1656  root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list,
1657                                         dwarf2reader::DW_FORM_ref4,
1658                                         dummy_line_size_ + 10);
1659  root_handler_.EndAttributes();
1660  root_handler_.Finish();
1661}
1662
1663TEST_F(CUErrors, NoLineSection) {
1664  EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1);
1665  PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290);
1666  // Delete the entry for .debug_line added by the fixture class's constructor.
1667  file_context_.ClearSectionMapForTest();
1668
1669  StartCU();
1670  root_handler_.Finish();
1671}
1672
1673TEST_F(CUErrors, BadDwarfVersion1) {
1674  // Kludge: satisfy reporter_'s expectation.
1675  reporter_.SetCUName("compilation-unit-name");
1676
1677  ASSERT_FALSE(root_handler_
1678               .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
1679                                     0xc9de224ccb99ac3eULL, 1));
1680}
1681
1682TEST_F(CUErrors, GoodDwarfVersion2) {
1683  // Kludge: satisfy reporter_'s expectation.
1684  reporter_.SetCUName("compilation-unit-name");
1685
1686  ASSERT_TRUE(root_handler_
1687               .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
1688                                     0xc9de224ccb99ac3eULL, 2));
1689}
1690
1691TEST_F(CUErrors, GoodDwarfVersion3) {
1692  // Kludge: satisfy reporter_'s expectation.
1693  reporter_.SetCUName("compilation-unit-name");
1694
1695  ASSERT_TRUE(root_handler_
1696               .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
1697                                     0xc9de224ccb99ac3eULL, 3));
1698}
1699
1700TEST_F(CUErrors, BadCURootDIETag) {
1701  // Kludge: satisfy reporter_'s expectation.
1702  reporter_.SetCUName("compilation-unit-name");
1703
1704  ASSERT_TRUE(root_handler_
1705               .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
1706                                     0xc9de224ccb99ac3eULL, 3));
1707
1708  ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL,
1709                                          dwarf2reader::DW_TAG_subprogram));
1710}
1711
1712// Tests for DwarfCUToModule::Reporter. These just produce (or fail to
1713// produce) output, so their results need to be checked by hand.
1714struct Reporter: public Test {
1715  Reporter()
1716      : reporter("filename", 0x123456789abcdef0ULL),
1717        function("function name", 0x19c45c30770c1eb0ULL),
1718        file("source file name") {
1719    reporter.SetCUName("compilation-unit-name");
1720
1721    function.size = 0x89808a5bdfa0a6a3ULL;
1722    function.parameter_size = 0x6a329f18683dcd51ULL;
1723
1724    line.address = 0x3606ac6267aebeccULL;
1725    line.size = 0x5de482229f32556aULL;
1726    line.file = &file;
1727    line.number = 93400201;
1728  }
1729
1730  DwarfCUToModule::WarningReporter reporter;
1731  Module::Function function;
1732  Module::File file;
1733  Module::Line line;
1734};
1735
1736TEST_F(Reporter, UnknownSpecification) {
1737  reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL);
1738}
1739
1740TEST_F(Reporter, UnknownAbstractOrigin) {
1741  reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL);
1742}
1743
1744TEST_F(Reporter, MissingSection) {
1745  reporter.MissingSection("section name");
1746}
1747
1748TEST_F(Reporter, BadLineInfoOffset) {
1749  reporter.BadLineInfoOffset(0x123456789abcdef1ULL);
1750}
1751
1752TEST_F(Reporter, UncoveredFunctionDisabled) {
1753  reporter.UncoveredFunction(function);
1754  EXPECT_FALSE(reporter.uncovered_warnings_enabled());
1755}
1756
1757TEST_F(Reporter, UncoveredFunctionEnabled) {
1758  reporter.set_uncovered_warnings_enabled(true);
1759  reporter.UncoveredFunction(function);
1760  EXPECT_TRUE(reporter.uncovered_warnings_enabled());
1761}
1762
1763TEST_F(Reporter, UncoveredLineDisabled) {
1764  reporter.UncoveredLine(line);
1765  EXPECT_FALSE(reporter.uncovered_warnings_enabled());
1766}
1767
1768TEST_F(Reporter, UncoveredLineEnabled) {
1769  reporter.set_uncovered_warnings_enabled(true);
1770  reporter.UncoveredLine(line);
1771  EXPECT_TRUE(reporter.uncovered_warnings_enabled());
1772}
1773
1774TEST_F(Reporter, UnnamedFunction) {
1775  reporter.UnnamedFunction(0x90c0baff9dedb2d9ULL);
1776}
1777
1778// Would be nice to also test:
1779// - overlapping lines, functions
1780