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