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