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