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