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