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