1 //===- llvm/unittest/DebugInfo/DWARFDieTest.cpp ---------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/BinaryFormat/Dwarf.h" 10 #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" 11 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 12 #include "llvm/ObjectYAML/DWARFEmitter.h" 13 #include "llvm/Testing/Support/Error.h" 14 #include "gtest/gtest.h" 15 16 using namespace llvm; 17 using namespace llvm::dwarf; 18 using object::SectionedAddress; 19 20 namespace { 21 22 TEST(DWARFDie, getLocations) { 23 const char *yamldata = R"( 24 debug_abbrev: 25 - Table: 26 - Code: 0x00000001 27 Tag: DW_TAG_compile_unit 28 Children: DW_CHILDREN_no 29 Attributes: 30 - Attribute: DW_AT_location 31 Form: DW_FORM_sec_offset 32 - Attribute: DW_AT_data_member_location 33 Form: DW_FORM_exprloc 34 - Attribute: DW_AT_vtable_elem_location 35 Form: DW_FORM_sec_offset 36 - Attribute: DW_AT_call_data_location 37 Form: DW_FORM_sec_offset 38 debug_info: 39 - Version: 5 40 UnitType: DW_UT_compile 41 AddrSize: 4 42 Entries: 43 - AbbrCode: 0x00000001 44 Values: 45 - Value: 12 46 - Value: 0x0000000000000001 47 BlockData: [ 0x47 ] 48 - Value: 20 49 - Value: 25 50 debug_loclists: 51 - AddressSize: 4 52 OffsetEntryCount: 0 53 Lists: 54 - Entries: 55 - Operator: DW_LLE_start_length 56 Values: [ 0x01, 0x02 ] 57 - Operator: DW_LLE_end_of_list 58 - Entries: 59 - Operator: DW_LLE_startx_length 60 Values: [ 0x01, 0x02 ] 61 - Operator: DW_LLE_end_of_list 62 - Entries: 63 - Operator: DW_LLE_start_length 64 Values: [ 0x01, 0x02 ] 65 ## end_of_list intentionally missing. 66 )"; 67 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections = 68 DWARFYAML::emitDebugSections(StringRef(yamldata), 69 /*IsLittleEndian=*/true, 70 /*Is64BitAddrSize=*/false); 71 ASSERT_THAT_EXPECTED(Sections, Succeeded()); 72 std::unique_ptr<DWARFContext> Ctx = 73 DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true); 74 DWARFCompileUnit *CU = Ctx->getCompileUnitForOffset(0); 75 ASSERT_NE(nullptr, CU); 76 DWARFDie Die = CU->getUnitDIE(); 77 ASSERT_TRUE(Die.isValid()); 78 79 EXPECT_THAT_EXPECTED(Die.getLocations(DW_AT_location), 80 HasValue(testing::ElementsAre(DWARFLocationExpression{ 81 DWARFAddressRange{1, 3}, {}}))); 82 83 EXPECT_THAT_EXPECTED( 84 Die.getLocations(DW_AT_data_member_location), 85 HasValue(testing::ElementsAre(DWARFLocationExpression{None, {0x47}}))); 86 87 EXPECT_THAT_EXPECTED( 88 Die.getLocations(DW_AT_vtable_elem_location), 89 Failed<ErrorInfoBase>(testing::Property( 90 &ErrorInfoBase::message, 91 "unable to resolve indirect address 1 for: DW_LLE_startx_length"))); 92 93 EXPECT_THAT_EXPECTED( 94 Die.getLocations(DW_AT_call_data_location), 95 FailedWithMessage( 96 "unexpected end of data at offset 0x20 while reading [0x20, 0x21)")); 97 98 EXPECT_THAT_EXPECTED( 99 Die.getLocations(DW_AT_call_data_value), 100 Failed<ErrorInfoBase>(testing::Property(&ErrorInfoBase::message, 101 "No DW_AT_call_data_value"))); 102 } 103 104 TEST(DWARFDie, getDeclFile) { 105 const char *yamldata = R"( 106 debug_str: 107 - '' 108 debug_abbrev: 109 - ID: 0 110 Table: 111 - Code: 0x1 112 Tag: DW_TAG_compile_unit 113 Children: DW_CHILDREN_yes 114 Attributes: 115 - Attribute: DW_AT_stmt_list 116 Form: DW_FORM_sec_offset 117 - Code: 0x2 118 Tag: DW_TAG_subprogram 119 Children: DW_CHILDREN_no 120 Attributes: 121 - Attribute: DW_AT_decl_file 122 Form: DW_FORM_data1 123 debug_info: 124 - Length: 0xF 125 Version: 4 126 AbbrevTableID: 0 127 AbbrOffset: 0x0 128 AddrSize: 8 129 Entries: 130 - AbbrCode: 0x1 131 Values: 132 - Value: 0x0 133 - AbbrCode: 0x2 134 Values: 135 - Value: 0x1 136 - AbbrCode: 0x0 137 debug_line: 138 - Length: 42 139 Version: 2 140 PrologueLength: 36 141 MinInstLength: 1 142 DefaultIsStmt: 1 143 LineBase: 251 144 LineRange: 14 145 OpcodeBase: 13 146 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 147 IncludeDirs: 148 - '/tmp' 149 Files: 150 - Name: main.cpp 151 DirIdx: 1 152 ModTime: 0 153 Length: 0 154 )"; 155 156 // Given DWARF like this: 157 // 158 // 0x0000000b: DW_TAG_compile_unit 159 // DW_AT_stmt_list (0x00000000) 160 // 161 // 0x00000010: DW_TAG_subprogram 162 // DW_AT_decl_file ("/tmp/main.cpp") 163 // 164 // 0x00000012: NULL 165 // 166 // This tests that we can extract the right DW_AT_decl_file from a DIE that 167 // has a DW_AT_decl_file attribute. 168 169 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections = 170 DWARFYAML::emitDebugSections(StringRef(yamldata), 171 /*IsLittleEndian=*/true, 172 /*Is64BitAddrSize=*/true); 173 ASSERT_THAT_EXPECTED(Sections, Succeeded()); 174 std::unique_ptr<DWARFContext> Ctx = 175 DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true); 176 DWARFCompileUnit *CU = Ctx->getCompileUnitForOffset(0); 177 ASSERT_NE(nullptr, CU); 178 DWARFDie Die = CU->getUnitDIE(/*ExtractUnitDIEOnly=*/false); 179 ASSERT_TRUE(Die.isValid()); 180 181 DWARFDie MainDie = Die.getFirstChild(); 182 ASSERT_TRUE(MainDie.isValid()); 183 184 std::string DeclFile = MainDie.getDeclFile( 185 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath); 186 187 std::string Ref = 188 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str(); 189 EXPECT_EQ(DeclFile, Ref); 190 } 191 192 TEST(DWARFDie, getDeclFileAbstractOrigin) { 193 const char *yamldata = R"( 194 debug_str: 195 - '' 196 debug_abbrev: 197 - ID: 0 198 Table: 199 - Code: 0x1 200 Tag: DW_TAG_compile_unit 201 Children: DW_CHILDREN_yes 202 Attributes: 203 - Attribute: DW_AT_stmt_list 204 Form: DW_FORM_sec_offset 205 - Code: 0x2 206 Tag: DW_TAG_subprogram 207 Children: DW_CHILDREN_no 208 Attributes: 209 - Attribute: DW_AT_abstract_origin 210 Form: DW_FORM_ref_addr 211 - Code: 0x3 212 Tag: DW_TAG_subprogram 213 Children: DW_CHILDREN_no 214 Attributes: 215 - Attribute: DW_AT_decl_file 216 Form: DW_FORM_data1 217 debug_info: 218 - Length: 0x14 219 Version: 4 220 AbbrevTableID: 0 221 AbbrOffset: 0x0 222 AddrSize: 8 223 Entries: 224 - AbbrCode: 0x1 225 Values: 226 - Value: 0x0 227 - AbbrCode: 0x2 228 Values: 229 - Value: 0x15 230 - AbbrCode: 0x3 231 Values: 232 - Value: 0x1 233 - AbbrCode: 0x0 234 debug_line: 235 - Length: 42 236 Version: 2 237 PrologueLength: 36 238 MinInstLength: 1 239 DefaultIsStmt: 1 240 LineBase: 251 241 LineRange: 14 242 OpcodeBase: 13 243 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 244 IncludeDirs: 245 - '/tmp' 246 Files: 247 - Name: main.cpp 248 DirIdx: 1 249 ModTime: 0 250 Length: 0 251 )"; 252 253 // Given DWARF like this: 254 // 255 // 0x0000000b: DW_TAG_compile_unit 256 // DW_AT_stmt_list (0x00000000) 257 // 258 // 0x00000010: DW_TAG_subprogram 259 // DW_AT_abstract_origin (0x0000000000000015) 260 // 261 // 0x00000015: DW_TAG_subprogram 262 // DW_AT_decl_file ("/tmp/main.cpp") 263 // 264 // 0x00000017: NULL 265 // 266 // 267 // The DIE at 0x00000010 uses a DW_AT_abstract_origin to point to the DIE at 268 // 0x00000015, make sure that DWARFDie::getDeclFile() succeeds by extracting 269 // the right file name of "/tmp/main.cpp". 270 // 271 // This tests that when we have a DW_AT_abstract_origin with a compile unit 272 // relative form (DW_FORM_ref4) to another DIE that we get the right 273 // DW_AT_decl_file value. 274 275 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections = 276 DWARFYAML::emitDebugSections(StringRef(yamldata), 277 /*IsLittleEndian=*/true, 278 /*Is64BitAddrSize=*/true); 279 ASSERT_THAT_EXPECTED(Sections, Succeeded()); 280 std::unique_ptr<DWARFContext> Ctx = 281 DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true); 282 DWARFCompileUnit *CU = Ctx->getCompileUnitForOffset(0); 283 ASSERT_NE(nullptr, CU); 284 DWARFDie Die = CU->getUnitDIE(/*ExtractUnitDIEOnly=*/false); 285 ASSERT_TRUE(Die.isValid()); 286 287 DWARFDie MainDie = Die.getFirstChild(); 288 ASSERT_TRUE(MainDie.isValid()); 289 290 std::string DeclFile = MainDie.getDeclFile( 291 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath); 292 293 std::string Ref = 294 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str(); 295 EXPECT_EQ(DeclFile, Ref); 296 } 297 298 TEST(DWARFDie, getDeclFileSpecification) { 299 const char *yamldata = R"( 300 debug_str: 301 - '' 302 debug_abbrev: 303 - ID: 0 304 Table: 305 - Code: 0x1 306 Tag: DW_TAG_compile_unit 307 Children: DW_CHILDREN_yes 308 Attributes: 309 - Attribute: DW_AT_stmt_list 310 Form: DW_FORM_sec_offset 311 - Code: 0x2 312 Tag: DW_TAG_subprogram 313 Children: DW_CHILDREN_no 314 Attributes: 315 - Attribute: DW_AT_specification 316 Form: DW_FORM_ref_addr 317 - Code: 0x3 318 Tag: DW_TAG_subprogram 319 Children: DW_CHILDREN_no 320 Attributes: 321 - Attribute: DW_AT_decl_file 322 Form: DW_FORM_data1 323 debug_info: 324 - Length: 0x14 325 Version: 4 326 AbbrevTableID: 0 327 AbbrOffset: 0x0 328 AddrSize: 8 329 Entries: 330 - AbbrCode: 0x1 331 Values: 332 - Value: 0x0 333 - AbbrCode: 0x2 334 Values: 335 - Value: 0x15 336 - AbbrCode: 0x3 337 Values: 338 - Value: 0x1 339 - AbbrCode: 0x0 340 debug_line: 341 - Length: 42 342 Version: 2 343 PrologueLength: 36 344 MinInstLength: 1 345 DefaultIsStmt: 1 346 LineBase: 251 347 LineRange: 14 348 OpcodeBase: 13 349 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 350 IncludeDirs: 351 - '/tmp' 352 Files: 353 - Name: main.cpp 354 DirIdx: 1 355 ModTime: 0 356 Length: 0 357 )"; 358 359 // Given DWARF like this: 360 // 361 // 0x0000000b: DW_TAG_compile_unit 362 // DW_AT_stmt_list (0x00000000) 363 // 364 // 0x00000010: DW_TAG_subprogram 365 // DW_AT_specification (0x0000000000000015) 366 // 367 // 0x00000015: DW_TAG_subprogram 368 // DW_AT_decl_file ("/tmp/main.cpp") 369 // 370 // 0x00000017: NULL 371 // 372 // The DIE at 0x00000010 uses a DW_AT_specification to point to the DIE at 373 // 0x00000015, make sure that DWARFDie::getDeclFile() succeeds by extracting 374 // the right file name of "/tmp/main.cpp". 375 // 376 // This tests that when we have a DW_AT_specification with a compile unit 377 // relative form (DW_FORM_ref4) to another DIE that we get the right 378 // DW_AT_decl_file value. 379 380 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections = 381 DWARFYAML::emitDebugSections(StringRef(yamldata), 382 /*IsLittleEndian=*/true, 383 /*Is64BitAddrSize=*/true); 384 ASSERT_THAT_EXPECTED(Sections, Succeeded()); 385 std::unique_ptr<DWARFContext> Ctx = 386 DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true); 387 DWARFCompileUnit *CU = Ctx->getCompileUnitForOffset(0); 388 ASSERT_NE(nullptr, CU); 389 DWARFDie Die = CU->getUnitDIE(/*ExtractUnitDIEOnly=*/false); 390 ASSERT_TRUE(Die.isValid()); 391 392 DWARFDie MainDie = Die.getFirstChild(); 393 ASSERT_TRUE(MainDie.isValid()); 394 395 std::string DeclFile = MainDie.getDeclFile( 396 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath); 397 398 std::string Ref = 399 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str(); 400 EXPECT_EQ(DeclFile, Ref); 401 } 402 403 TEST(DWARFDie, getDeclFileAbstractOriginAcrossCUBoundary) { 404 const char *yamldata = R"( 405 debug_str: 406 - '' 407 debug_abbrev: 408 - ID: 0 409 Table: 410 - Code: 0x1 411 Tag: DW_TAG_compile_unit 412 Children: DW_CHILDREN_yes 413 - Code: 0x2 414 Tag: DW_TAG_subprogram 415 Children: DW_CHILDREN_no 416 Attributes: 417 - Attribute: DW_AT_abstract_origin 418 Form: DW_FORM_ref_addr 419 - Code: 0x3 420 Tag: DW_TAG_compile_unit 421 Children: DW_CHILDREN_yes 422 Attributes: 423 - Attribute: DW_AT_stmt_list 424 Form: DW_FORM_sec_offset 425 - Code: 0x4 426 Tag: DW_TAG_subprogram 427 Children: DW_CHILDREN_no 428 Attributes: 429 - Attribute: DW_AT_decl_file 430 Form: DW_FORM_data1 431 debug_info: 432 - Length: 0xE 433 Version: 4 434 AbbrevTableID: 0 435 AbbrOffset: 0x0 436 AddrSize: 8 437 Entries: 438 - AbbrCode: 0x1 439 - AbbrCode: 0x2 440 Values: 441 - Value: 0x22 442 - AbbrCode: 0x0 443 - Length: 0xF 444 Version: 4 445 AbbrevTableID: 0 446 AbbrOffset: 0x0 447 AddrSize: 8 448 Entries: 449 - AbbrCode: 0x3 450 Values: 451 - Value: 0x0 452 - AbbrCode: 0x4 453 Values: 454 - Value: 0x1 455 - AbbrCode: 0x0 456 debug_line: 457 - Length: 42 458 Version: 2 459 PrologueLength: 36 460 MinInstLength: 1 461 DefaultIsStmt: 1 462 LineBase: 251 463 LineRange: 14 464 OpcodeBase: 13 465 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 466 IncludeDirs: 467 - '/tmp' 468 Files: 469 - Name: main.cpp 470 DirIdx: 1 471 ModTime: 0 472 Length: 0 473 )"; 474 475 // Given DWARF like this: 476 // 477 // 0x0000000b: DW_TAG_compile_unit 478 // 479 // 0x0000000c: DW_TAG_subprogram 480 // DW_AT_abstract_origin (0x0000000000000022) 481 // 482 // 0x00000011: NULL 483 // 484 // 0x0000001d: DW_TAG_compile_unit 485 // DW_AT_stmt_list (0x00000000) 486 // 487 // 0x00000022: DW_TAG_subprogram 488 // DW_AT_decl_file ("/tmp/main.cpp") 489 // 490 // 0x00000024: NULL 491 // 492 // This tests that when we have a DW_AT_abstract_origin with a 493 // DW_FORM_ref_addr to another DIE in another compile unit that we use the 494 // right file table when converting the file index of the DW_AT_decl_file. 495 // 496 // The DIE at 0x0000000c uses a DW_AT_abstract_origin to point to the DIE at 497 // 0x00000022, make sure that DWARFDie::getDeclFile() succeeds by extracting 498 // the right file name of "/tmp/main.cpp". The DW_AT_decl_file must grab the 499 // file from the line table prologue of the compile unit at offset 500 // 0x0000001d. 501 502 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections = 503 DWARFYAML::emitDebugSections(StringRef(yamldata), 504 /*IsLittleEndian=*/true, 505 /*Is64BitAddrSize=*/true); 506 ASSERT_THAT_EXPECTED(Sections, Succeeded()); 507 std::unique_ptr<DWARFContext> Ctx = 508 DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true); 509 DWARFCompileUnit *CU = Ctx->getCompileUnitForOffset(0); 510 ASSERT_NE(nullptr, CU); 511 DWARFDie Die = CU->getUnitDIE(/*ExtractUnitDIEOnly=*/false); 512 ASSERT_TRUE(Die.isValid()); 513 514 DWARFDie MainDie = Die.getFirstChild(); 515 ASSERT_TRUE(MainDie.isValid()); 516 517 std::string DeclFile = MainDie.getDeclFile( 518 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath); 519 520 std::string Ref = 521 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str(); 522 EXPECT_EQ(DeclFile, Ref); 523 } 524 525 TEST(DWARFDie, getDeclFileSpecificationAcrossCUBoundary) { 526 const char *yamldata = R"( 527 debug_str: 528 - '' 529 debug_abbrev: 530 - ID: 0 531 Table: 532 - Code: 0x1 533 Tag: DW_TAG_compile_unit 534 Children: DW_CHILDREN_yes 535 - Code: 0x2 536 Tag: DW_TAG_subprogram 537 Children: DW_CHILDREN_no 538 Attributes: 539 - Attribute: DW_AT_specification 540 Form: DW_FORM_ref_addr 541 - Code: 0x3 542 Tag: DW_TAG_compile_unit 543 Children: DW_CHILDREN_yes 544 Attributes: 545 - Attribute: DW_AT_stmt_list 546 Form: DW_FORM_sec_offset 547 - Code: 0x4 548 Tag: DW_TAG_subprogram 549 Children: DW_CHILDREN_no 550 Attributes: 551 - Attribute: DW_AT_decl_file 552 Form: DW_FORM_data1 553 debug_info: 554 - Length: 0xE 555 Version: 4 556 AbbrevTableID: 0 557 AbbrOffset: 0x0 558 AddrSize: 8 559 Entries: 560 - AbbrCode: 0x1 561 - AbbrCode: 0x2 562 Values: 563 - Value: 0x22 564 - AbbrCode: 0x0 565 - Length: 0xF 566 Version: 4 567 AbbrevTableID: 0 568 AbbrOffset: 0x0 569 AddrSize: 8 570 Entries: 571 - AbbrCode: 0x3 572 Values: 573 - Value: 0x0 574 - AbbrCode: 0x4 575 Values: 576 - Value: 0x1 577 - AbbrCode: 0x0 578 debug_line: 579 - Length: 42 580 Version: 2 581 PrologueLength: 36 582 MinInstLength: 1 583 DefaultIsStmt: 1 584 LineBase: 251 585 LineRange: 14 586 OpcodeBase: 13 587 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 588 IncludeDirs: 589 - '/tmp' 590 Files: 591 - Name: main.cpp 592 DirIdx: 1 593 ModTime: 0 594 Length: 0 595 )"; 596 597 // Given DWARF like this: 598 // 599 // 0x0000000b: DW_TAG_compile_unit 600 // 601 // 0x0000000c: DW_TAG_subprogram 602 // DW_AT_specification (0x0000000000000022) 603 // 604 // 0x00000011: NULL 605 // 606 // 0x0000001d: DW_TAG_compile_unit 607 // DW_AT_stmt_list (0x00000000) 608 // 609 // 0x00000022: DW_TAG_subprogram 610 // DW_AT_decl_file ("/tmp/main.cpp") 611 // 612 // 0x00000024: NULL 613 // 614 // This tests that when we have a DW_AT_specification with a 615 // DW_FORM_ref_addr to another DIE in another compile unit that we use the 616 // right file table when converting the file index of the DW_AT_decl_file. 617 // 618 // The DIE at 0x0000000c uses a DW_AT_specification to point to the DIE at 619 // 0x00000022, make sure that DWARFDie::getDeclFile() succeeds by extracting 620 // the right file name of "/tmp/main.cpp". The DW_AT_decl_file must grab the 621 // file from the line table prologue of the compile unit at offset 622 // 0x0000001d. 623 624 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections = 625 DWARFYAML::emitDebugSections(StringRef(yamldata), 626 /*IsLittleEndian=*/true, 627 /*Is64BitAddrSize=*/true); 628 ASSERT_THAT_EXPECTED(Sections, Succeeded()); 629 std::unique_ptr<DWARFContext> Ctx = 630 DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true); 631 DWARFCompileUnit *CU = Ctx->getCompileUnitForOffset(0); 632 ASSERT_NE(nullptr, CU); 633 DWARFDie Die = CU->getUnitDIE(/*ExtractUnitDIEOnly=*/false); 634 ASSERT_TRUE(Die.isValid()); 635 636 DWARFDie MainDie = Die.getFirstChild(); 637 ASSERT_TRUE(MainDie.isValid()); 638 639 std::string DeclFile = MainDie.getDeclFile( 640 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath); 641 642 std::string Ref = 643 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str(); 644 EXPECT_EQ(DeclFile, Ref); 645 } 646 647 } // end anonymous namespace 648