• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
42 using std::make_pair;
43 using std::vector;
44 
45 using dwarf2reader::DIEHandler;
46 using dwarf2reader::DwarfTag;
47 using dwarf2reader::DwarfAttribute;
48 using dwarf2reader::DwarfForm;
49 using dwarf2reader::DwarfInline;
50 using dwarf2reader::RootDIEHandler;
51 using google_breakpad::DwarfCUToModule;
52 using google_breakpad::Module;
53 
54 using ::testing::_;
55 using ::testing::AtMost;
56 using ::testing::Invoke;
57 using ::testing::Return;
58 using ::testing::Test;
59 using ::testing::TestWithParam;
60 using ::testing::Values;
61 using ::testing::ValuesIn;
62 
63 // Mock classes.
64 
65 class 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 
72 class MockWarningReporter: public DwarfCUToModule::WarningReporter {
73  public:
MockWarningReporter(const string & filename,uint64 cu_offset)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.
91 class 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:
AppendLinesFunctor(const vector<Module::Line> * lines)112     explicit AppendLinesFunctor(
113         const vector<Module::Line> *lines) : lines_(lines) { }
operator ()(const char * program,uint64 length,Module * module,vector<Module::Line> * 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 
CUFixtureBase()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.
SetLanguage(dwarf2reader::DwarfLanguage 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.
SetLanguageSigned(bool is_signed)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 
305 const char CUFixtureBase::dummy_line_program_[] = "lots of fun data";
306 const size_t CUFixtureBase::dummy_line_size_ =
307     sizeof(CUFixtureBase::dummy_line_program_);
308 
PushLine(Module::Address address,Module::Address size,const string & filename,int line_number)309 void 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 
StartCU()319 void 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 
ProcessStrangeAttributes(dwarf2reader::DIEHandler * handler)367 void 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 
StartNamedDIE(DIEHandler * parent,DwarfTag tag,const string & name)387 DIEHandler *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 
StartSpecifiedDIE(DIEHandler * parent,DwarfTag tag,uint64 specification,const char * name)407 DIEHandler *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 
DefineFunction(dwarf2reader::DIEHandler * parent,const string & name,Module::Address address,Module::Address size,const char * mangled_name,DwarfForm high_pc_form)431 void 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 
DeclarationDIE(DIEHandler * parent,uint64 offset,DwarfTag tag,const string & name,const string & mangled_name)466 void 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 
DefinitionDIE(DIEHandler * parent,DwarfTag tag,uint64 specification,const string & name,Module::Address address,Module::Address size)489 void 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 
AbstractInstanceDIE(DIEHandler * parent,uint64 offset,DwarfInline type,uint64 specification,const string & name,DwarfForm form)518 void 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 
DefineInlineInstanceDIE(DIEHandler * parent,const string & name,uint64 origin,Module::Address address,Module::Address size)546 void 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 
FillFunctions()575 void 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 
TestFunctionCount(size_t expected)584 void CUFixtureBase::TestFunctionCount(size_t expected) {
585   FillFunctions();
586   ASSERT_EQ(expected, functions_.size());
587 }
588 
TestFunction(int i,const string & name,Module::Address address,Module::Address size)589 void 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 
TestLineCount(int i,size_t expected)602 void 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 
TestLine(int i,int j,Module::Address address,Module::Address size,const string & filename,int number)609 void 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 
640 class SimpleCU: public CUFixtureBase, public Test {
641 };
642 
TEST_F(SimpleCU,CompilationDir)643 TEST_F(SimpleCU, CompilationDir) {
644   compilation_dir_ = "/src/build/";
645 
646   StartCU();
647   root_handler_.Finish();
648 }
649 
TEST_F(SimpleCU,OneFunc)650 TEST_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.
TEST_F(SimpleCU,OneFuncHighPcIsLength)666 TEST_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 
TEST_F(SimpleCU,MangledName)682 TEST_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 
TEST_F(SimpleCU,IrrelevantRootChildren)694 TEST_F(SimpleCU, IrrelevantRootChildren) {
695   StartCU();
696   EXPECT_FALSE(root_handler_
697                .FindChildHandler(0x7db32bff4e2dcfb1ULL,
698                                  dwarf2reader::DW_TAG_lexical_block));
699 }
700 
TEST_F(SimpleCU,IrrelevantNamedScopeChildren)701 TEST_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.
TEST_F(SimpleCU,UnusedFileContext)713 TEST_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 
TEST_F(SimpleCU,InlineFunction)721 TEST_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 
TEST_F(SimpleCU,InlineFunctionSignedAttribute)736 TEST_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.
TEST_F(SimpleCU,AbstractOriginNotInlined)755 TEST_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 
TEST_F(SimpleCU,UnknownAbstractOrigin)770 TEST_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 
TEST_F(SimpleCU,UnnamedFunction)788 TEST_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.
804 struct Range {
805   Module::Address start, end;
806 };
807 
808 // Test data for pairing functions and lines.
809 struct 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 
840 Situation situations[] = {
841 #include "common/testdata/func-line-pairing.h"
842 };
843 
844 #undef PAIRING
845 
846 class FuncLinePairing: public CUFixtureBase,
847                        public TestWithParam<Situation> { };
848 
849 INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing,
850                         ValuesIn(situations));
851 
TEST_P(FuncLinePairing,Pairing)852 TEST_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 
TEST_F(FuncLinePairing,EmptyCU)897 TEST_F(FuncLinePairing, EmptyCU) {
898   StartCU();
899   root_handler_.Finish();
900 
901   TestFunctionCount(0);
902 }
903 
TEST_F(FuncLinePairing,LinesNoFuncs)904 TEST_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 
TEST_F(FuncLinePairing,FuncsNoLines)914 TEST_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 
TEST_F(FuncLinePairing,GapThenFunction)926 TEST_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.
TEST_F(FuncLinePairing,GCCAlignmentStretch)952 TEST_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 
TEST_F(FuncLinePairing,LineAtEndOfAddressSpace)976 TEST_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.
TEST_F(FuncLinePairing,WarnOnceFunc)996 TEST_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.
TEST_F(FuncLinePairing,WarnOnceLine)1014 TEST_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 
1032 class CXXQualifiedNames: public CUFixtureBase,
1033                          public TestWithParam<DwarfTag> { };
1034 
1035 INSTANTIATE_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 
TEST_P(CXXQualifiedNames,TwoFunctions)1041 TEST_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 
TEST_P(CXXQualifiedNames,FuncInEnclosureInNamespace)1063 TEST_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 
TEST_F(CXXQualifiedNames,FunctionInClassInStructInNamespace)1088 TEST_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 
1117 struct LanguageAndQualifiedName {
1118   dwarf2reader::DwarfLanguage language;
1119   const char *name;
1120 };
1121 
1122 const 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 
1133 class QualifiedForLanguage
1134     : public CUFixtureBase,
1135       public TestWithParam<LanguageAndQualifiedName> { };
1136 
1137 INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage,
1138                         ValuesIn(LanguageAndQualifiedNameCases));
1139 
TEST_P(QualifiedForLanguage,MemberFunction)1140 TEST_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 
TEST_P(QualifiedForLanguage,MemberFunctionSignedLanguage)1163 TEST_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 
1187 class Specifications: public CUFixtureBase, public Test { };
1188 
TEST_F(Specifications,Function)1189 TEST_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 
TEST_F(Specifications,MangledName)1205 TEST_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 
TEST_F(Specifications,MemberFunction)1222 TEST_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.
TEST_F(Specifications,FunctionDeclarationParent)1244 TEST_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.
TEST_F(Specifications,NamedScopeDeclarationParent)1272 TEST_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.
TEST_F(Specifications,InlineFunction)1307 TEST_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
TEST_F(Specifications,LongChain)1327 TEST_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 
TEST_F(Specifications,InterCU)1433 TEST_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 
TEST_F(Specifications,UnhandledInterCU)1492 TEST_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 
TEST_F(Specifications,BadOffset)1549 TEST_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 
TEST_F(Specifications,FunctionDefinitionHasOwnName)1563 TEST_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 
TEST_F(Specifications,ClassDefinitionHasOwnName)1579 TEST_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.
TEST_F(Specifications,PreferSpecificationParents)1612 TEST_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 
1643 class CUErrors: public CUFixtureBase, public Test { };
1644 
TEST_F(CUErrors,BadStmtList)1645 TEST_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 
TEST_F(CUErrors,NoLineSection)1663 TEST_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 
TEST_F(CUErrors,BadDwarfVersion1)1673 TEST_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 
TEST_F(CUErrors,GoodDwarfVersion2)1682 TEST_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 
TEST_F(CUErrors,GoodDwarfVersion3)1691 TEST_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 
TEST_F(CUErrors,BadCURootDIETag)1700 TEST_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.
1714 struct Reporter: public Test {
ReporterReporter1715   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 
TEST_F(Reporter,UnknownSpecification)1736 TEST_F(Reporter, UnknownSpecification) {
1737   reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL);
1738 }
1739 
TEST_F(Reporter,UnknownAbstractOrigin)1740 TEST_F(Reporter, UnknownAbstractOrigin) {
1741   reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL);
1742 }
1743 
TEST_F(Reporter,MissingSection)1744 TEST_F(Reporter, MissingSection) {
1745   reporter.MissingSection("section name");
1746 }
1747 
TEST_F(Reporter,BadLineInfoOffset)1748 TEST_F(Reporter, BadLineInfoOffset) {
1749   reporter.BadLineInfoOffset(0x123456789abcdef1ULL);
1750 }
1751 
TEST_F(Reporter,UncoveredFunctionDisabled)1752 TEST_F(Reporter, UncoveredFunctionDisabled) {
1753   reporter.UncoveredFunction(function);
1754   EXPECT_FALSE(reporter.uncovered_warnings_enabled());
1755 }
1756 
TEST_F(Reporter,UncoveredFunctionEnabled)1757 TEST_F(Reporter, UncoveredFunctionEnabled) {
1758   reporter.set_uncovered_warnings_enabled(true);
1759   reporter.UncoveredFunction(function);
1760   EXPECT_TRUE(reporter.uncovered_warnings_enabled());
1761 }
1762 
TEST_F(Reporter,UncoveredLineDisabled)1763 TEST_F(Reporter, UncoveredLineDisabled) {
1764   reporter.UncoveredLine(line);
1765   EXPECT_FALSE(reporter.uncovered_warnings_enabled());
1766 }
1767 
TEST_F(Reporter,UncoveredLineEnabled)1768 TEST_F(Reporter, UncoveredLineEnabled) {
1769   reporter.set_uncovered_warnings_enabled(true);
1770   reporter.UncoveredLine(line);
1771   EXPECT_TRUE(reporter.uncovered_warnings_enabled());
1772 }
1773 
TEST_F(Reporter,UnnamedFunction)1774 TEST_F(Reporter, UnnamedFunction) {
1775   reporter.UnnamedFunction(0x90c0baff9dedb2d9ULL);
1776 }
1777 
1778 // Would be nice to also test:
1779 // - overlapping lines, functions
1780