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