1 //===- DWARFDebugLineTest.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 "DwarfGenerator.h" 10 #include "DwarfUtils.h" 11 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 12 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" 13 #include "llvm/Object/ObjectFile.h" 14 #include "llvm/Testing/Support/Error.h" 15 #include "gtest/gtest.h" 16 17 using namespace llvm; 18 using namespace dwarf; 19 using namespace dwarfgen; 20 using namespace object; 21 using namespace utils; 22 using namespace testing; 23 24 namespace { 25 struct CommonFixture { 26 CommonFixture() 27 : LineData("", true, 0), Recoverable(Error::success()), 28 RecordRecoverable(std::bind(&CommonFixture::recordRecoverable, this, 29 std::placeholders::_1)), 30 Unrecoverable(Error::success()), 31 RecordUnrecoverable(std::bind(&CommonFixture::recordUnrecoverable, this, 32 std::placeholders::_1)){}; 33 34 ~CommonFixture() { 35 EXPECT_FALSE(Recoverable); 36 EXPECT_FALSE(Unrecoverable); 37 } 38 39 bool setupGenerator(uint16_t Version = 4, uint8_t AddrSize = 8) { 40 AddressSize = AddrSize; 41 Triple T = 42 getDefaultTargetTripleForAddrSize(AddressSize == 0 ? 8 : AddressSize); 43 if (!isConfigurationSupported(T)) 44 return false; 45 auto ExpectedGenerator = Generator::create(T, Version); 46 if (ExpectedGenerator) 47 Gen.reset(ExpectedGenerator->release()); 48 return true; 49 } 50 51 void generate() { 52 Context = createContext(); 53 assert(Context != nullptr && "test state is not valid"); 54 const DWARFObject &Obj = Context->getDWARFObj(); 55 uint8_t TargetAddrSize = AddressSize == 0 ? 8 : AddressSize; 56 LineData = DWARFDataExtractor( 57 Obj, Obj.getLineSection(), 58 getDefaultTargetTripleForAddrSize(TargetAddrSize).isLittleEndian(), 59 AddressSize); 60 } 61 62 std::unique_ptr<DWARFContext> createContext() { 63 if (!Gen) 64 return nullptr; 65 StringRef FileBytes = Gen->generate(); 66 MemoryBufferRef FileBuffer(FileBytes, "dwarf"); 67 auto Obj = object::ObjectFile::createObjectFile(FileBuffer); 68 if (Obj) 69 return DWARFContext::create(**Obj); 70 return nullptr; 71 } 72 73 DWARFDebugLine::SectionParser setupParser() { 74 LineTable < = Gen->addLineTable(DWARF32); 75 LT.addExtendedOpcode(9, DW_LNE_set_address, {{0xadd4e55, LineTable::Quad}}); 76 LT.addStandardOpcode(DW_LNS_copy, {}); 77 LT.addByte(0xaa); 78 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 79 80 LineTable <2 = Gen->addLineTable(DWARF64); 81 LT2.addExtendedOpcode(9, DW_LNE_set_address, 82 {{0x11223344, LineTable::Quad}}); 83 LT2.addStandardOpcode(DW_LNS_copy, {}); 84 LT2.addByte(0xbb); 85 LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 86 87 generate(); 88 89 return DWARFDebugLine::SectionParser(LineData, *Context, CUs, TUs); 90 } 91 92 void recordRecoverable(Error Err) { 93 Recoverable = joinErrors(std::move(Recoverable), std::move(Err)); 94 } 95 void recordUnrecoverable(Error Err) { 96 Unrecoverable = joinErrors(std::move(Unrecoverable), std::move(Err)); 97 } 98 99 void checkError(ArrayRef<StringRef> ExpectedMsgs, Error Err) { 100 ASSERT_TRUE(Err.operator bool()); 101 size_t WhichMsg = 0; 102 Error Remaining = 103 handleErrors(std::move(Err), [&](const ErrorInfoBase &Actual) { 104 ASSERT_LT(WhichMsg, ExpectedMsgs.size()); 105 // Use .str(), because googletest doesn't visualise a StringRef 106 // properly. 107 EXPECT_EQ(Actual.message(), ExpectedMsgs[WhichMsg++].str()); 108 }); 109 EXPECT_EQ(WhichMsg, ExpectedMsgs.size()); 110 EXPECT_FALSE(Remaining); 111 } 112 113 void checkError(StringRef ExpectedMsg, Error Err) { 114 checkError(ArrayRef<StringRef>{ExpectedMsg}, std::move(Err)); 115 } 116 117 void checkGetOrParseLineTableEmitsFatalError(StringRef ExpectedMsg, 118 uint64_t Offset = 0) { 119 auto ExpectedLineTable = Line.getOrParseLineTable( 120 LineData, Offset, *Context, nullptr, RecordRecoverable); 121 EXPECT_FALSE(ExpectedLineTable); 122 EXPECT_FALSE(Recoverable); 123 124 checkError(ExpectedMsg, ExpectedLineTable.takeError()); 125 } 126 127 void checkGetOrParseLineTableEmitsFatalError(ArrayRef<StringRef> ExpectedMsgs, 128 uint64_t Offset = 0) { 129 auto ExpectedLineTable = Line.getOrParseLineTable( 130 LineData, Offset, *Context, nullptr, RecordRecoverable); 131 EXPECT_FALSE(ExpectedLineTable); 132 EXPECT_FALSE(Recoverable); 133 134 checkError(ExpectedMsgs, ExpectedLineTable.takeError()); 135 } 136 137 uint8_t AddressSize; 138 std::unique_ptr<Generator> Gen; 139 std::unique_ptr<DWARFContext> Context; 140 DWARFDataExtractor LineData; 141 DWARFDebugLine Line; 142 Error Recoverable; 143 std::function<void(Error)> RecordRecoverable; 144 Error Unrecoverable; 145 std::function<void(Error)> RecordUnrecoverable; 146 147 SmallVector<std::unique_ptr<DWARFUnit>, 2> CUs; 148 SmallVector<std::unique_ptr<DWARFUnit>, 2> TUs; 149 }; 150 151 // Fixtures must derive from "Test", but parameterised fixtures from 152 // "TestWithParam". It does not seem possible to inherit from both, so we share 153 // the common state in a separate class, inherited by the two fixture classes. 154 struct DebugLineBasicFixture : public Test, public CommonFixture {}; 155 156 struct DebugLineParameterisedFixture 157 : public TestWithParam<std::pair<uint16_t, DwarfFormat>>, 158 public CommonFixture { 159 void SetUp() { std::tie(Version, Format) = GetParam(); } 160 161 uint16_t Version; 162 DwarfFormat Format; 163 }; 164 165 void checkDefaultPrologue(uint16_t Version, DwarfFormat Format, 166 DWARFDebugLine::Prologue Prologue, 167 uint64_t BodyLength) { 168 // Check version specific fields and values. 169 uint64_t UnitLength; 170 uint64_t PrologueLength; 171 switch (Version) { 172 case 4: 173 PrologueLength = 36; 174 UnitLength = PrologueLength + 2; 175 EXPECT_EQ(Prologue.MaxOpsPerInst, 1u); 176 break; 177 case 2: 178 case 3: 179 PrologueLength = 35; 180 UnitLength = PrologueLength + 2; 181 break; 182 case 5: 183 PrologueLength = 42; 184 UnitLength = PrologueLength + 4; 185 EXPECT_EQ(Prologue.getAddressSize(), 8u); 186 EXPECT_EQ(Prologue.SegSelectorSize, 0u); 187 break; 188 default: 189 llvm_unreachable("unsupported DWARF version"); 190 } 191 UnitLength += BodyLength + (Format == DWARF32 ? 4 : 8); 192 193 EXPECT_EQ(Prologue.TotalLength, UnitLength); 194 EXPECT_EQ(Prologue.PrologueLength, PrologueLength); 195 EXPECT_EQ(Prologue.MinInstLength, 1u); 196 EXPECT_EQ(Prologue.DefaultIsStmt, 1u); 197 EXPECT_EQ(Prologue.LineBase, -5); 198 EXPECT_EQ(Prologue.LineRange, 14u); 199 EXPECT_EQ(Prologue.OpcodeBase, 13u); 200 std::vector<uint8_t> ExpectedLengths = {0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1}; 201 EXPECT_EQ(Prologue.StandardOpcodeLengths, ExpectedLengths); 202 ASSERT_EQ(Prologue.IncludeDirectories.size(), 1u); 203 ASSERT_EQ(Prologue.IncludeDirectories[0].getForm(), DW_FORM_string); 204 EXPECT_STREQ(*Prologue.IncludeDirectories[0].getAsCString(), "a dir"); 205 ASSERT_EQ(Prologue.FileNames.size(), 1u); 206 ASSERT_EQ(Prologue.FileNames[0].Name.getForm(), DW_FORM_string); 207 ASSERT_EQ(Prologue.FileNames[0].DirIdx, 0u); 208 EXPECT_STREQ(*Prologue.FileNames[0].Name.getAsCString(), "a file"); 209 } 210 211 TEST_F(DebugLineBasicFixture, GetOrParseLineTableAtInvalidOffset) { 212 if (!setupGenerator()) 213 return; 214 generate(); 215 216 checkGetOrParseLineTableEmitsFatalError( 217 "offset 0x00000000 is not a valid debug line section offset", 0); 218 // Repeat to show that an error is reported each time. 219 checkGetOrParseLineTableEmitsFatalError( 220 "offset 0x00000000 is not a valid debug line section offset", 0); 221 // Show that an error is reported for later offsets too. 222 checkGetOrParseLineTableEmitsFatalError( 223 "offset 0x00000001 is not a valid debug line section offset", 1); 224 } 225 226 TEST_F(DebugLineBasicFixture, GetOrParseLineTableAtInvalidOffsetAfterData) { 227 if (!setupGenerator()) 228 return; 229 230 LineTable < = Gen->addLineTable(); 231 LT.setCustomPrologue({{0, LineTable::Byte}}); 232 233 generate(); 234 235 checkGetOrParseLineTableEmitsFatalError( 236 "offset 0x00000001 is not a valid debug line section offset", 1); 237 } 238 239 TEST_P(DebugLineParameterisedFixture, PrologueGetLength) { 240 if (!setupGenerator(Version)) 241 return; 242 LineTable < = Gen->addLineTable(Format); 243 DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); 244 LT.setPrologue(Prologue); 245 generate(); 246 247 // + 10 for sizes of DWARF-32 unit length, version, prologue length. 248 uint64_t ExpectedLength = Prologue.PrologueLength + 10; 249 if (Version == 5) 250 // Add address and segment selector size fields. 251 ExpectedLength += 2; 252 if (Format == DWARF64) 253 // Unit length grows by 8, prologue length by 4. 254 ExpectedLength += 12; 255 256 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 257 nullptr, RecordRecoverable); 258 ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 259 EXPECT_EQ((*ExpectedLineTable)->Prologue.getLength(), ExpectedLength); 260 } 261 262 TEST_P(DebugLineParameterisedFixture, GetOrParseLineTableValidTable) { 263 if (!setupGenerator(Version)) 264 return; 265 266 SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " + 267 (Format == DWARF64 ? "DWARF64" : "DWARF32")); 268 269 LineTable < = Gen->addLineTable(Format); 270 LT.addExtendedOpcode(9, DW_LNE_set_address, {{0xadd4e55, LineTable::Quad}}); 271 LT.addStandardOpcode(DW_LNS_copy, {}); 272 LT.addByte(0xaa); 273 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 274 275 LineTable <2 = Gen->addLineTable(Format); 276 LT2.addExtendedOpcode(9, DW_LNE_set_address, {{0x11223344, LineTable::Quad}}); 277 LT2.addStandardOpcode(DW_LNS_copy, {}); 278 LT2.addByte(0xbb); 279 LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 280 LT2.addExtendedOpcode(9, DW_LNE_set_address, {{0x55667788, LineTable::Quad}}); 281 LT2.addStandardOpcode(DW_LNS_copy, {}); 282 LT2.addByte(0xcc); 283 LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 284 285 generate(); 286 287 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 288 nullptr, RecordRecoverable); 289 ASSERT_TRUE(ExpectedLineTable.operator bool()); 290 EXPECT_FALSE(Recoverable); 291 const DWARFDebugLine::LineTable *Expected = *ExpectedLineTable; 292 checkDefaultPrologue(Version, Format, Expected->Prologue, 16); 293 EXPECT_EQ(Expected->Sequences.size(), 1u); 294 295 uint64_t SecondOffset = 296 Expected->Prologue.sizeofTotalLength() + Expected->Prologue.TotalLength; 297 Recoverable = Error::success(); 298 auto ExpectedLineTable2 = Line.getOrParseLineTable( 299 LineData, SecondOffset, *Context, nullptr, RecordRecoverable); 300 ASSERT_TRUE(ExpectedLineTable2.operator bool()); 301 EXPECT_FALSE(Recoverable); 302 const DWARFDebugLine::LineTable *Expected2 = *ExpectedLineTable2; 303 checkDefaultPrologue(Version, Format, Expected2->Prologue, 32); 304 EXPECT_EQ(Expected2->Sequences.size(), 2u); 305 306 EXPECT_NE(Expected, Expected2); 307 308 // Check that if the same offset is requested, the exact same pointer is 309 // returned. 310 Recoverable = Error::success(); 311 auto ExpectedLineTable3 = Line.getOrParseLineTable( 312 LineData, 0, *Context, nullptr, RecordRecoverable); 313 ASSERT_TRUE(ExpectedLineTable3.operator bool()); 314 EXPECT_FALSE(Recoverable); 315 EXPECT_EQ(Expected, *ExpectedLineTable3); 316 317 Recoverable = Error::success(); 318 auto ExpectedLineTable4 = Line.getOrParseLineTable( 319 LineData, SecondOffset, *Context, nullptr, RecordRecoverable); 320 ASSERT_TRUE(ExpectedLineTable4.operator bool()); 321 EXPECT_FALSE(Recoverable); 322 EXPECT_EQ(Expected2, *ExpectedLineTable4); 323 324 // TODO: Add tests that show that the body of the programs have been read 325 // correctly. 326 } 327 328 TEST_F(DebugLineBasicFixture, ErrorForReservedLength) { 329 if (!setupGenerator()) 330 return; 331 332 LineTable < = Gen->addLineTable(); 333 LT.setCustomPrologue({{0xfffffff0, LineTable::Long}}); 334 335 generate(); 336 337 checkGetOrParseLineTableEmitsFatalError( 338 "parsing line table prologue at offset 0x00000000 unsupported reserved " 339 "unit length found of value 0xfffffff0"); 340 } 341 342 struct DebugLineUnsupportedVersionFixture : public TestWithParam<uint16_t>, 343 public CommonFixture { 344 void SetUp() { Version = GetParam(); } 345 346 uint16_t Version; 347 }; 348 349 TEST_P(DebugLineUnsupportedVersionFixture, ErrorForUnsupportedVersion) { 350 if (!setupGenerator()) 351 return; 352 353 LineTable < = Gen->addLineTable(); 354 LT.setCustomPrologue( 355 {{LineTable::Half, LineTable::Long}, {Version, LineTable::Half}}); 356 357 generate(); 358 359 checkGetOrParseLineTableEmitsFatalError( 360 "parsing line table prologue at offset 0x00000000 found unsupported " 361 "version " + 362 std::to_string(Version)); 363 } 364 365 INSTANTIATE_TEST_CASE_P(UnsupportedVersionTestParams, 366 DebugLineUnsupportedVersionFixture, 367 Values(/*1 below min */ 1, /* 1 above max */ 6, 368 /* Maximum possible */ 0xffff), ); 369 370 TEST_F(DebugLineBasicFixture, ErrorForInvalidV5IncludeDirTable) { 371 if (!setupGenerator(5)) 372 return; 373 374 LineTable < = Gen->addLineTable(); 375 LT.setCustomPrologue({ 376 {19, LineTable::Long}, // unit length 377 {5, LineTable::Half}, // version 378 {8, LineTable::Byte}, // addr size 379 {0, LineTable::Byte}, // segment selector size 380 {11, LineTable::Long}, // prologue length 381 {1, LineTable::Byte}, // min instruction length 382 {1, LineTable::Byte}, // max ops per instruction 383 {1, LineTable::Byte}, // default is_stmt 384 {0, LineTable::Byte}, // line base 385 {14, LineTable::Byte}, // line range 386 {2, LineTable::Byte}, // opcode base (small to reduce the amount of 387 // setup required). 388 {0, LineTable::Byte}, // standard opcode lengths 389 {0, LineTable::Byte}, // directory entry format count (should not be 390 // zero). 391 {0, LineTable::ULEB}, // directories count 392 {0, LineTable::Byte}, // file name entry format count 393 {0, LineTable::ULEB} // file name entry count 394 }); 395 396 generate(); 397 398 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 399 nullptr, RecordRecoverable); 400 EXPECT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 401 402 checkError( 403 {"parsing line table prologue at 0x00000000 found an invalid directory " 404 "or file table description at 0x00000014", 405 "failed to parse entry content descriptions because no path was found"}, 406 std::move(Recoverable)); 407 } 408 409 TEST_P(DebugLineParameterisedFixture, ErrorForTooLargePrologueLength) { 410 if (!setupGenerator(Version)) 411 return; 412 413 SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " + 414 (Format == DWARF64 ? "DWARF64" : "DWARF32")); 415 416 LineTable < = Gen->addLineTable(Format); 417 DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); 418 ++Prologue.PrologueLength; 419 LT.setPrologue(Prologue); 420 421 generate(); 422 423 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 424 nullptr, RecordRecoverable); 425 ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 426 DWARFDebugLine::LineTable Result(**ExpectedLineTable); 427 // Undo the earlier modification so that it can be compared against a 428 // "default" prologue. 429 --Result.Prologue.PrologueLength; 430 checkDefaultPrologue(Version, Format, Result.Prologue, 0); 431 432 uint64_t ExpectedEnd = 433 Prologue.TotalLength + 1 + Prologue.sizeofTotalLength(); 434 checkError( 435 (Twine("parsing line table prologue at 0x00000000 should have ended at " 436 "0x000000") + 437 Twine::utohexstr(ExpectedEnd) + " but it ended at 0x000000" + 438 Twine::utohexstr(ExpectedEnd - 1)) 439 .str(), 440 std::move(Recoverable)); 441 } 442 443 TEST_P(DebugLineParameterisedFixture, ErrorForTooShortPrologueLength) { 444 if (!setupGenerator(Version)) 445 return; 446 447 SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " + 448 (Format == DWARF64 ? "DWARF64" : "DWARF32")); 449 450 LineTable < = Gen->addLineTable(Format); 451 DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); 452 Prologue.PrologueLength -= 2; 453 LT.setPrologue(Prologue); 454 455 generate(); 456 457 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 458 nullptr, RecordRecoverable); 459 ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 460 DWARFDebugLine::LineTable Result(**ExpectedLineTable); 461 // Undo the earlier modification so that it can be compared against a 462 // "default" prologue. 463 Result.Prologue.PrologueLength += 2; 464 checkDefaultPrologue(Version, Format, Result.Prologue, 0); 465 466 uint64_t ExpectedEnd = 467 Prologue.TotalLength - 2 + Prologue.sizeofTotalLength(); 468 std::vector<std::string> Errs; 469 // Parsing of a DWARFv2-4 file table stops at the end of an entry once the 470 // prologue end has been reached, whether or not the trailing null terminator 471 // has been found. As such, the expected error message will be slightly 472 // different. 473 uint64_t ActualEnd = Version == 5 ? ExpectedEnd + 2 : ExpectedEnd + 1; 474 if (Version != 5) { 475 Errs.emplace_back( 476 (Twine("parsing line table prologue at 0x00000000 found an invalid " 477 "directory or file table description at 0x000000") + 478 Twine::utohexstr(ActualEnd)) 479 .str()); 480 Errs.emplace_back("file names table was not null terminated before the end " 481 "of the prologue"); 482 } 483 Errs.emplace_back( 484 (Twine("parsing line table prologue at 0x00000000 should have ended at " 485 "0x000000") + 486 Twine::utohexstr(ExpectedEnd) + " but it ended at 0x000000" + 487 Twine::utohexstr(ActualEnd)) 488 .str()); 489 std::vector<StringRef> ErrRefs(Errs.begin(), Errs.end()); 490 checkError(ErrRefs, std::move(Recoverable)); 491 } 492 493 INSTANTIATE_TEST_CASE_P( 494 LineTableTestParams, DebugLineParameterisedFixture, 495 Values(std::make_pair( 496 2, DWARF32), // Test lower-bound of v2-3 fields and DWARF32. 497 std::make_pair(3, DWARF32), // Test upper-bound of v2-3 fields. 498 std::make_pair(4, DWARF64), // Test v4 fields and DWARF64. 499 std::make_pair(5, DWARF32), std::make_pair(5, DWARF64)), ); 500 501 TEST_F(DebugLineBasicFixture, ErrorForExtendedOpcodeLengthSmallerThanExpected) { 502 if (!setupGenerator()) 503 return; 504 505 LineTable < = Gen->addLineTable(); 506 LT.addByte(0xaa); 507 // The Length should be 1 + sizeof(ULEB) for a set discriminator opcode. 508 // The operand will be read for both the discriminator opcode and then parsed 509 // again as DW_LNS_negate_stmt, to respect the claimed length. 510 LT.addExtendedOpcode(1, DW_LNE_set_discriminator, 511 {{DW_LNS_negate_stmt, LineTable::ULEB}}); 512 LT.addByte(0xbb); 513 LT.addStandardOpcode(DW_LNS_const_add_pc, {}); 514 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 515 516 generate(); 517 518 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 519 nullptr, RecordRecoverable); 520 checkError( 521 "unexpected line op length at offset 0x00000031 expected 0x01 found 0x02", 522 std::move(Recoverable)); 523 ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 524 ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 3u); 525 EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); 526 EXPECT_EQ((*ExpectedLineTable)->Rows[1].IsStmt, 0u); 527 EXPECT_EQ((*ExpectedLineTable)->Rows[1].Discriminator, DW_LNS_negate_stmt); 528 } 529 530 TEST_F(DebugLineBasicFixture, ErrorForExtendedOpcodeLengthLargerThanExpected) { 531 if (!setupGenerator()) 532 return; 533 534 LineTable < = Gen->addLineTable(); 535 LT.addByte(0xaa); 536 LT.addStandardOpcode(DW_LNS_const_add_pc, {}); 537 // The Length should be 1 for an end sequence opcode. 538 LT.addExtendedOpcode(2, DW_LNE_end_sequence, {}); 539 // The negate statement opcode will be skipped. 540 LT.addStandardOpcode(DW_LNS_negate_stmt, {}); 541 LT.addByte(0xbb); 542 LT.addStandardOpcode(DW_LNS_const_add_pc, {}); 543 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 544 545 generate(); 546 547 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 548 nullptr, RecordRecoverable); 549 checkError( 550 "unexpected line op length at offset 0x00000032 expected 0x02 found 0x01", 551 std::move(Recoverable)); 552 ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 553 ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 4u); 554 EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 2u); 555 ASSERT_EQ((*ExpectedLineTable)->Sequences[1].FirstRowIndex, 2u); 556 EXPECT_EQ((*ExpectedLineTable)->Rows[2].IsStmt, 1u); 557 } 558 559 TEST_F(DebugLineBasicFixture, ErrorForUnitLengthTooLarge) { 560 if (!setupGenerator()) 561 return; 562 563 LineTable &Padding = Gen->addLineTable(); 564 // Add some padding to show that a non-zero offset is handled correctly. 565 Padding.setCustomPrologue({{0, LineTable::Byte}}); 566 LineTable < = Gen->addLineTable(); 567 LT.addStandardOpcode(DW_LNS_copy, {}); 568 LT.addStandardOpcode(DW_LNS_const_add_pc, {}); 569 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 570 DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); 571 // Set the total length to 1 higher than the actual length. 572 ++Prologue.TotalLength; 573 LT.setPrologue(Prologue); 574 575 generate(); 576 577 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 1, *Context, 578 nullptr, RecordRecoverable); 579 checkError("line table program with offset 0x00000001 has length 0x00000034 " 580 "but only 0x00000033 bytes are available", 581 std::move(Recoverable)); 582 ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 583 EXPECT_EQ((*ExpectedLineTable)->Rows.size(), 2u); 584 EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); 585 } 586 587 TEST_F(DebugLineBasicFixture, ErrorForMismatchedAddressSize) { 588 if (!setupGenerator(4, 8)) 589 return; 590 591 LineTable < = Gen->addLineTable(); 592 // The line data extractor expects size 8 (Quad) addresses. 593 uint64_t Addr1 = 0x11223344; 594 LT.addExtendedOpcode(5, DW_LNE_set_address, {{Addr1, LineTable::Long}}); 595 LT.addStandardOpcode(DW_LNS_copy, {}); 596 // Show that the expected address size is unchanged, so later valid lines 597 // don't cause a problem. 598 uint64_t Addr2 = 0x1122334455667788; 599 LT.addExtendedOpcode(9, DW_LNE_set_address, {{Addr2, LineTable::Quad}}); 600 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 601 602 generate(); 603 604 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 605 nullptr, RecordRecoverable); 606 checkError( 607 "mismatching address size at offset 0x00000030 expected 0x08 found 0x04", 608 std::move(Recoverable)); 609 ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 610 ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 2u); 611 EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); 612 EXPECT_EQ((*ExpectedLineTable)->Rows[0].Address.Address, Addr1); 613 EXPECT_EQ((*ExpectedLineTable)->Rows[1].Address.Address, Addr2); 614 } 615 616 TEST_F(DebugLineBasicFixture, 617 ErrorForMismatchedAddressSizeUnsetInitialAddress) { 618 if (!setupGenerator(4, 0)) 619 return; 620 621 LineTable < = Gen->addLineTable(); 622 uint64_t Addr1 = 0x11223344; 623 LT.addExtendedOpcode(5, DW_LNE_set_address, {{Addr1, LineTable::Long}}); 624 LT.addStandardOpcode(DW_LNS_copy, {}); 625 uint64_t Addr2 = 0x1122334455667788; 626 LT.addExtendedOpcode(9, DW_LNE_set_address, {{Addr2, LineTable::Quad}}); 627 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 628 629 generate(); 630 631 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 632 nullptr, RecordRecoverable); 633 checkError( 634 "mismatching address size at offset 0x00000038 expected 0x04 found 0x08", 635 std::move(Recoverable)); 636 ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 637 ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 2u); 638 EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); 639 EXPECT_EQ((*ExpectedLineTable)->Rows[0].Address.Address, Addr1); 640 EXPECT_EQ((*ExpectedLineTable)->Rows[1].Address.Address, Addr2); 641 } 642 643 TEST_F(DebugLineBasicFixture, CallbackUsedForUnterminatedSequence) { 644 if (!setupGenerator()) 645 return; 646 647 LineTable < = Gen->addLineTable(); 648 LT.addExtendedOpcode(9, DW_LNE_set_address, 649 {{0x1122334455667788, LineTable::Quad}}); 650 LT.addStandardOpcode(DW_LNS_copy, {}); 651 LT.addByte(0xaa); 652 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 653 LT.addExtendedOpcode(9, DW_LNE_set_address, 654 {{0x99aabbccddeeff00, LineTable::Quad}}); 655 LT.addStandardOpcode(DW_LNS_copy, {}); 656 LT.addByte(0xbb); 657 LT.addByte(0xcc); 658 659 generate(); 660 661 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 662 nullptr, RecordRecoverable); 663 checkError("last sequence in debug line table at offset 0x00000000 is not " 664 "terminated", 665 std::move(Recoverable)); 666 ASSERT_TRUE(ExpectedLineTable.operator bool()); 667 EXPECT_EQ((*ExpectedLineTable)->Rows.size(), 6u); 668 // The unterminated sequence is not added to the sequence list. 669 EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); 670 } 671 672 TEST_F(DebugLineBasicFixture, ParserParsesCorrectly) { 673 if (!setupGenerator()) 674 return; 675 676 DWARFDebugLine::SectionParser Parser = setupParser(); 677 678 EXPECT_EQ(Parser.getOffset(), 0u); 679 ASSERT_FALSE(Parser.done()); 680 681 DWARFDebugLine::LineTable Parsed = 682 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 683 checkDefaultPrologue(4, DWARF32, Parsed.Prologue, 16); 684 EXPECT_EQ(Parsed.Sequences.size(), 1u); 685 EXPECT_EQ(Parser.getOffset(), 62u); 686 ASSERT_FALSE(Parser.done()); 687 688 DWARFDebugLine::LineTable Parsed2 = 689 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 690 checkDefaultPrologue(4, DWARF64, Parsed2.Prologue, 16); 691 EXPECT_EQ(Parsed2.Sequences.size(), 1u); 692 EXPECT_EQ(Parser.getOffset(), 136u); 693 EXPECT_TRUE(Parser.done()); 694 695 EXPECT_FALSE(Recoverable); 696 EXPECT_FALSE(Unrecoverable); 697 } 698 699 TEST_F(DebugLineBasicFixture, ParserSkipsCorrectly) { 700 if (!setupGenerator()) 701 return; 702 703 DWARFDebugLine::SectionParser Parser = setupParser(); 704 705 EXPECT_EQ(Parser.getOffset(), 0u); 706 ASSERT_FALSE(Parser.done()); 707 708 Parser.skip(RecordRecoverable, RecordUnrecoverable); 709 EXPECT_EQ(Parser.getOffset(), 62u); 710 ASSERT_FALSE(Parser.done()); 711 712 Parser.skip(RecordRecoverable, RecordUnrecoverable); 713 EXPECT_EQ(Parser.getOffset(), 136u); 714 EXPECT_TRUE(Parser.done()); 715 716 EXPECT_FALSE(Recoverable); 717 EXPECT_FALSE(Unrecoverable); 718 } 719 720 TEST_F(DebugLineBasicFixture, ParserAlwaysDoneForEmptySection) { 721 if (!setupGenerator()) 722 return; 723 724 generate(); 725 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 726 727 EXPECT_TRUE(Parser.done()); 728 } 729 730 TEST_F(DebugLineBasicFixture, ParserMovesToEndForBadLengthWhenParsing) { 731 if (!setupGenerator()) 732 return; 733 734 LineTable < = Gen->addLineTable(); 735 LT.setCustomPrologue({{0xfffffff0, LineTable::Long}}); 736 Gen->addLineTable(); 737 generate(); 738 739 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 740 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 741 742 EXPECT_EQ(Parser.getOffset(), 4u); 743 EXPECT_TRUE(Parser.done()); 744 EXPECT_FALSE(Recoverable); 745 746 checkError("parsing line table prologue at offset 0x00000000 unsupported " 747 "reserved unit length found of value 0xfffffff0", 748 std::move(Unrecoverable)); 749 } 750 751 TEST_F(DebugLineBasicFixture, ParserMovesToEndForBadLengthWhenSkipping) { 752 if (!setupGenerator()) 753 return; 754 755 LineTable < = Gen->addLineTable(); 756 LT.setCustomPrologue({{0xfffffff0, LineTable::Long}}); 757 Gen->addLineTable(); 758 generate(); 759 760 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 761 Parser.skip(RecordRecoverable, RecordUnrecoverable); 762 763 EXPECT_EQ(Parser.getOffset(), 4u); 764 EXPECT_TRUE(Parser.done()); 765 EXPECT_FALSE(Recoverable); 766 767 checkError("parsing line table prologue at offset 0x00000000 unsupported " 768 "reserved unit length found of value 0xfffffff0", 769 std::move(Unrecoverable)); 770 } 771 772 TEST_F(DebugLineBasicFixture, ParserReportsFirstErrorInEachTableWhenParsing) { 773 if (!setupGenerator()) 774 return; 775 776 LineTable < = Gen->addLineTable(DWARF32); 777 LT.setCustomPrologue({{2, LineTable::Long}, {0, LineTable::Half}}); 778 LineTable <2 = Gen->addLineTable(DWARF32); 779 LT2.setCustomPrologue({{2, LineTable::Long}, {1, LineTable::Half}}); 780 generate(); 781 782 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 783 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 784 ASSERT_FALSE(Parser.done()); 785 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 786 787 EXPECT_TRUE(Parser.done()); 788 EXPECT_FALSE(Recoverable); 789 790 checkError({"parsing line table prologue at offset 0x00000000 found " 791 "unsupported version 0", 792 "parsing line table prologue at offset 0x00000006 found " 793 "unsupported version 1"}, 794 std::move(Unrecoverable)); 795 } 796 797 TEST_F(DebugLineBasicFixture, ParserReportsNonPrologueProblemsWhenParsing) { 798 if (!setupGenerator()) 799 return; 800 801 LineTable < = Gen->addLineTable(DWARF32); 802 LT.addExtendedOpcode(0x42, DW_LNE_end_sequence, {}); 803 LineTable <2 = Gen->addLineTable(DWARF32); 804 LT2.addExtendedOpcode(9, DW_LNE_set_address, 805 {{0x1234567890abcdef, LineTable::Quad}}); 806 LT2.addStandardOpcode(DW_LNS_copy, {}); 807 LT2.addByte(0xbb); 808 generate(); 809 810 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 811 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 812 EXPECT_FALSE(Unrecoverable); 813 ASSERT_FALSE(Parser.done()); 814 checkError( 815 "unexpected line op length at offset 0x00000030 expected 0x42 found 0x01", 816 std::move(Recoverable)); 817 818 // Reset the error state so that it does not confuse the next set of checks. 819 Unrecoverable = Error::success(); 820 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 821 822 EXPECT_TRUE(Parser.done()); 823 checkError("last sequence in debug line table at offset 0x00000031 is not " 824 "terminated", 825 std::move(Recoverable)); 826 EXPECT_FALSE(Unrecoverable); 827 } 828 829 TEST_F(DebugLineBasicFixture, 830 ParserReportsPrologueErrorsInEachTableWhenSkipping) { 831 if (!setupGenerator()) 832 return; 833 834 LineTable < = Gen->addLineTable(DWARF32); 835 LT.setCustomPrologue({{2, LineTable::Long}, {0, LineTable::Half}}); 836 LineTable <2 = Gen->addLineTable(DWARF32); 837 LT2.setCustomPrologue({{2, LineTable::Long}, {1, LineTable::Half}}); 838 generate(); 839 840 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 841 Parser.skip(RecordRecoverable, RecordUnrecoverable); 842 ASSERT_FALSE(Parser.done()); 843 Parser.skip(RecordRecoverable, RecordUnrecoverable); 844 845 EXPECT_TRUE(Parser.done()); 846 EXPECT_FALSE(Recoverable); 847 848 checkError({"parsing line table prologue at offset 0x00000000 found " 849 "unsupported version 0", 850 "parsing line table prologue at offset 0x00000006 found " 851 "unsupported version 1"}, 852 std::move(Unrecoverable)); 853 } 854 855 TEST_F(DebugLineBasicFixture, ParserIgnoresNonPrologueErrorsWhenSkipping) { 856 if (!setupGenerator()) 857 return; 858 859 LineTable < = Gen->addLineTable(DWARF32); 860 LT.addExtendedOpcode(42, DW_LNE_end_sequence, {}); 861 generate(); 862 863 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 864 Parser.skip(RecordRecoverable, RecordUnrecoverable); 865 866 EXPECT_TRUE(Parser.done()); 867 EXPECT_FALSE(Recoverable); 868 EXPECT_FALSE(Unrecoverable); 869 } 870 871 TEST_F(DebugLineBasicFixture, ParserPrintsStandardOpcodesWhenRequested) { 872 if (!setupGenerator()) 873 return; 874 875 using ValLen = dwarfgen::LineTable::ValueAndLength; 876 LineTable < = Gen->addLineTable(DWARF32); 877 LT.addStandardOpcode(DW_LNS_copy, {}); 878 LT.addStandardOpcode(DW_LNS_advance_pc, {ValLen{11, LineTable::ULEB}}); 879 LT.addStandardOpcode(DW_LNS_advance_line, {ValLen{22, LineTable::SLEB}}); 880 LT.addStandardOpcode(DW_LNS_set_file, {ValLen{33, LineTable::ULEB}}); 881 LT.addStandardOpcode(DW_LNS_set_column, {ValLen{44, LineTable::ULEB}}); 882 LT.addStandardOpcode(DW_LNS_negate_stmt, {}); 883 LT.addStandardOpcode(DW_LNS_set_basic_block, {}); 884 LT.addStandardOpcode(DW_LNS_const_add_pc, {}); 885 LT.addStandardOpcode(DW_LNS_fixed_advance_pc, {ValLen{55, LineTable::Half}}); 886 LT.addStandardOpcode(DW_LNS_set_prologue_end, {}); 887 LT.addStandardOpcode(DW_LNS_set_epilogue_begin, {}); 888 LT.addStandardOpcode(DW_LNS_set_isa, {ValLen{66, LineTable::ULEB}}); 889 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 890 generate(); 891 892 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 893 std::string Output; 894 raw_string_ostream OS(Output); 895 Parser.parseNext(RecordRecoverable, RecordUnrecoverable, &OS); 896 OS.flush(); 897 898 EXPECT_FALSE(Recoverable); 899 EXPECT_FALSE(Unrecoverable); 900 auto InOutput = [&Output](char const *Str) { 901 return Output.find(Str) != std::string::npos; 902 }; 903 EXPECT_TRUE(InOutput("0x0000002e: 01 DW_LNS_copy\n")) << Output; 904 EXPECT_TRUE(InOutput("0x0000002f: 02 DW_LNS_advance_pc (11)\n")) << Output; 905 // FIXME: The value printed after DW_LNS_advance_line is currently the result 906 // of the advance, but it should be the value being advanced by. See 907 // https://bugs.llvm.org/show_bug.cgi?id=44261 for details. 908 EXPECT_TRUE(InOutput("0x00000031: 03 DW_LNS_advance_line (23)\n")) << Output; 909 EXPECT_TRUE(InOutput("0x00000033: 04 DW_LNS_set_file (33)\n")) << Output; 910 EXPECT_TRUE(InOutput("0x00000035: 05 DW_LNS_set_column (44)\n")) << Output; 911 EXPECT_TRUE(InOutput("0x00000037: 06 DW_LNS_negate_stmt\n")) << Output; 912 EXPECT_TRUE(InOutput("0x00000038: 07 DW_LNS_set_basic_block\n")) << Output; 913 EXPECT_TRUE( 914 InOutput("0x00000039: 08 DW_LNS_const_add_pc (0x0000000000000011)\n")) 915 << Output; 916 EXPECT_TRUE(InOutput("0x0000003a: 09 DW_LNS_fixed_advance_pc (0x0037)\n")) 917 << Output; 918 EXPECT_TRUE(InOutput("0x0000003d: 0a DW_LNS_set_prologue_end\n")) << Output; 919 EXPECT_TRUE(InOutput("0x0000003e: 0b DW_LNS_set_epilogue_begin\n")) << Output; 920 EXPECT_TRUE(InOutput("0x0000003f: 0c DW_LNS_set_isa (66)\n")) << Output; 921 } 922 923 TEST_F(DebugLineBasicFixture, PrintPathsProperly) { 924 if (!setupGenerator(5)) 925 return; 926 927 LineTable < = Gen->addLineTable(); 928 DWARFDebugLine::Prologue P = LT.createBasicPrologue(); 929 P.IncludeDirectories.push_back( 930 DWARFFormValue::createFromPValue(DW_FORM_string, "b dir")); 931 P.FileNames.push_back(DWARFDebugLine::FileNameEntry()); 932 P.FileNames.back().Name = 933 DWARFFormValue::createFromPValue(DW_FORM_string, "b file"); 934 P.FileNames.back().DirIdx = 1; 935 P.PrologueLength += 14; 936 LT.setPrologue(P); 937 generate(); 938 939 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 940 nullptr, RecordRecoverable); 941 EXPECT_THAT_EXPECTED(ExpectedLineTable, Succeeded()); 942 std::string Result; 943 // DWARF 5 stores the compilation directory in two places: the Compilation 944 // Unit and the directory table entry 0, and implementations are free to use 945 // one or the other. This copy serves as the one stored in the CU. 946 StringRef CompDir = "a dir"; 947 EXPECT_FALSE( 948 (*ExpectedLineTable) 949 ->Prologue.getFileNameByIndex( 950 1, CompDir, DILineInfoSpecifier::FileLineInfoKind::None, Result)); 951 EXPECT_TRUE((*ExpectedLineTable) 952 ->Prologue.getFileNameByIndex( 953 1, CompDir, 954 DILineInfoSpecifier::FileLineInfoKind::Default, Result)); 955 EXPECT_STREQ(Result.c_str(), "b file"); 956 EXPECT_TRUE((*ExpectedLineTable) 957 ->Prologue.getFileNameByIndex( 958 1, CompDir, 959 DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath, 960 Result)); 961 EXPECT_THAT(Result.c_str(), MatchesRegex("b dir.b file")); 962 EXPECT_TRUE((*ExpectedLineTable) 963 ->Prologue.getFileNameByIndex( 964 1, CompDir, 965 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, 966 Result)); 967 EXPECT_THAT(Result.c_str(), MatchesRegex("a dir.b dir.b file")); 968 } 969 970 } // end anonymous namespace 971