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) { 40 Triple T = getHostTripleForAddrSize(8); 41 if (!isConfigurationSupported(T)) 42 return false; 43 auto ExpectedGenerator = Generator::create(T, Version); 44 if (ExpectedGenerator) 45 Gen.reset(ExpectedGenerator->release()); 46 return true; 47 } 48 49 void generate() { 50 Context = createContext(); 51 assert(Context != nullptr && "test state is not valid"); 52 const DWARFObject &Obj = Context->getDWARFObj(); 53 LineData = DWARFDataExtractor(Obj, Obj.getLineSection(), 54 sys::IsLittleEndianHost, 8); 55 } 56 57 std::unique_ptr<DWARFContext> createContext() { 58 if (!Gen) 59 return nullptr; 60 StringRef FileBytes = Gen->generate(); 61 MemoryBufferRef FileBuffer(FileBytes, "dwarf"); 62 auto Obj = object::ObjectFile::createObjectFile(FileBuffer); 63 if (Obj) 64 return DWARFContext::create(**Obj); 65 return nullptr; 66 } 67 68 DWARFDebugLine::SectionParser setupParser() { 69 LineTable < = Gen->addLineTable(DWARF32); 70 LT.addExtendedOpcode(9, DW_LNE_set_address, {{0xadd4e55, LineTable::Quad}}); 71 LT.addStandardOpcode(DW_LNS_copy, {}); 72 LT.addByte(0xaa); 73 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 74 75 LineTable <2 = Gen->addLineTable(DWARF64); 76 LT2.addExtendedOpcode(9, DW_LNE_set_address, 77 {{0x11223344, LineTable::Quad}}); 78 LT2.addStandardOpcode(DW_LNS_copy, {}); 79 LT2.addByte(0xbb); 80 LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 81 82 generate(); 83 84 return DWARFDebugLine::SectionParser(LineData, *Context, CUs, TUs); 85 } 86 87 void recordRecoverable(Error Err) { 88 Recoverable = joinErrors(std::move(Recoverable), std::move(Err)); 89 } 90 void recordUnrecoverable(Error Err) { 91 Unrecoverable = joinErrors(std::move(Unrecoverable), std::move(Err)); 92 } 93 94 void checkError(ArrayRef<StringRef> ExpectedMsgs, Error Err) { 95 ASSERT_TRUE(Err.operator bool()); 96 size_t WhichMsg = 0; 97 Error Remaining = 98 handleErrors(std::move(Err), [&](const ErrorInfoBase &Actual) { 99 ASSERT_LT(WhichMsg, ExpectedMsgs.size()); 100 // Use .str(), because googletest doesn't visualise a StringRef 101 // properly. 102 EXPECT_EQ(Actual.message(), ExpectedMsgs[WhichMsg++].str()); 103 }); 104 EXPECT_EQ(WhichMsg, ExpectedMsgs.size()); 105 EXPECT_FALSE(Remaining); 106 } 107 108 void checkError(StringRef ExpectedMsg, Error Err) { 109 checkError(ArrayRef<StringRef>{ExpectedMsg}, std::move(Err)); 110 } 111 112 void checkGetOrParseLineTableEmitsError(StringRef ExpectedMsg, 113 uint64_t Offset = 0) { 114 auto ExpectedLineTable = Line.getOrParseLineTable( 115 LineData, Offset, *Context, nullptr, RecordRecoverable); 116 EXPECT_FALSE(ExpectedLineTable); 117 EXPECT_FALSE(Recoverable); 118 119 checkError(ExpectedMsg, ExpectedLineTable.takeError()); 120 } 121 122 std::unique_ptr<Generator> Gen; 123 std::unique_ptr<DWARFContext> Context; 124 DWARFDataExtractor LineData; 125 DWARFDebugLine Line; 126 Error Recoverable; 127 std::function<void(Error)> RecordRecoverable; 128 Error Unrecoverable; 129 std::function<void(Error)> RecordUnrecoverable; 130 131 SmallVector<std::unique_ptr<DWARFUnit>, 2> CUs; 132 SmallVector<std::unique_ptr<DWARFUnit>, 2> TUs; 133 }; 134 135 // Fixtures must derive from "Test", but parameterised fixtures from 136 // "TestWithParam". It does not seem possible to inherit from both, so we share 137 // the common state in a separate class, inherited by the two fixture classes. 138 struct DebugLineBasicFixture : public Test, public CommonFixture {}; 139 140 struct DebugLineParameterisedFixture 141 : public TestWithParam<std::pair<uint16_t, DwarfFormat>>, 142 public CommonFixture { 143 void SetUp() { std::tie(Version, Format) = GetParam(); } 144 145 uint16_t Version; 146 DwarfFormat Format; 147 }; 148 149 void checkDefaultPrologue(uint16_t Version, DwarfFormat Format, 150 DWARFDebugLine::Prologue Prologue, 151 uint64_t BodyLength) { 152 // Check version specific fields and values. 153 uint64_t UnitLength; 154 uint64_t PrologueLength; 155 switch (Version) { 156 case 4: 157 PrologueLength = 36; 158 UnitLength = PrologueLength + 2; 159 EXPECT_EQ(Prologue.MaxOpsPerInst, 1u); 160 break; 161 case 2: 162 case 3: 163 PrologueLength = 35; 164 UnitLength = PrologueLength + 2; 165 break; 166 case 5: 167 PrologueLength = 39; 168 UnitLength = PrologueLength + 4; 169 EXPECT_EQ(Prologue.getAddressSize(), 8u); 170 EXPECT_EQ(Prologue.SegSelectorSize, 0u); 171 break; 172 default: 173 llvm_unreachable("unsupported DWARF version"); 174 } 175 UnitLength += BodyLength + (Format == DWARF32 ? 4 : 8); 176 177 EXPECT_EQ(Prologue.TotalLength, UnitLength); 178 EXPECT_EQ(Prologue.PrologueLength, PrologueLength); 179 EXPECT_EQ(Prologue.MinInstLength, 1u); 180 EXPECT_EQ(Prologue.DefaultIsStmt, 1u); 181 EXPECT_EQ(Prologue.LineBase, -5); 182 EXPECT_EQ(Prologue.LineRange, 14u); 183 EXPECT_EQ(Prologue.OpcodeBase, 13u); 184 std::vector<uint8_t> ExpectedLengths = {0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1}; 185 EXPECT_EQ(Prologue.StandardOpcodeLengths, ExpectedLengths); 186 ASSERT_EQ(Prologue.IncludeDirectories.size(), 1u); 187 ASSERT_EQ(Prologue.IncludeDirectories[0].getForm(), DW_FORM_string); 188 EXPECT_STREQ(*Prologue.IncludeDirectories[0].getAsCString(), "a dir"); 189 ASSERT_EQ(Prologue.FileNames.size(), 1u); 190 ASSERT_EQ(Prologue.FileNames[0].Name.getForm(), DW_FORM_string); 191 EXPECT_STREQ(*Prologue.FileNames[0].Name.getAsCString(), "a file"); 192 } 193 194 TEST_F(DebugLineBasicFixture, GetOrParseLineTableAtInvalidOffset) { 195 if (!setupGenerator()) 196 return; 197 generate(); 198 199 checkGetOrParseLineTableEmitsError( 200 "offset 0x00000000 is not a valid debug line section offset", 0); 201 // Repeat to show that an error is reported each time. 202 checkGetOrParseLineTableEmitsError( 203 "offset 0x00000000 is not a valid debug line section offset", 0); 204 // Show that an error is reported for later offsets too. 205 checkGetOrParseLineTableEmitsError( 206 "offset 0x00000001 is not a valid debug line section offset", 1); 207 } 208 209 TEST_F(DebugLineBasicFixture, GetOrParseLineTableAtInvalidOffsetAfterData) { 210 if (!setupGenerator()) 211 return; 212 213 LineTable < = Gen->addLineTable(); 214 LT.setCustomPrologue({{0, LineTable::Byte}}); 215 216 generate(); 217 218 checkGetOrParseLineTableEmitsError( 219 "offset 0x00000001 is not a valid debug line section offset", 1); 220 } 221 222 TEST_P(DebugLineParameterisedFixture, GetOrParseLineTableValidTable) { 223 if (!setupGenerator(Version)) 224 return; 225 226 SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " + 227 (Format == DWARF64 ? "DWARF64" : "DWARF32")); 228 229 LineTable < = Gen->addLineTable(Format); 230 LT.addExtendedOpcode(9, DW_LNE_set_address, {{0xadd4e55, LineTable::Quad}}); 231 LT.addStandardOpcode(DW_LNS_copy, {}); 232 LT.addByte(0xaa); 233 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 234 235 LineTable <2 = Gen->addLineTable(Format); 236 LT2.addExtendedOpcode(9, DW_LNE_set_address, {{0x11223344, LineTable::Quad}}); 237 LT2.addStandardOpcode(DW_LNS_copy, {}); 238 LT2.addByte(0xbb); 239 LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 240 LT2.addExtendedOpcode(9, DW_LNE_set_address, {{0x55667788, LineTable::Quad}}); 241 LT2.addStandardOpcode(DW_LNS_copy, {}); 242 LT2.addByte(0xcc); 243 LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 244 245 generate(); 246 247 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 248 nullptr, RecordRecoverable); 249 ASSERT_TRUE(ExpectedLineTable.operator bool()); 250 EXPECT_FALSE(Recoverable); 251 const DWARFDebugLine::LineTable *Expected = *ExpectedLineTable; 252 checkDefaultPrologue(Version, Format, Expected->Prologue, 16); 253 EXPECT_EQ(Expected->Sequences.size(), 1u); 254 255 uint64_t SecondOffset = 256 Expected->Prologue.sizeofTotalLength() + Expected->Prologue.TotalLength; 257 Recoverable = Error::success(); 258 auto ExpectedLineTable2 = Line.getOrParseLineTable( 259 LineData, SecondOffset, *Context, nullptr, RecordRecoverable); 260 ASSERT_TRUE(ExpectedLineTable2.operator bool()); 261 EXPECT_FALSE(Recoverable); 262 const DWARFDebugLine::LineTable *Expected2 = *ExpectedLineTable2; 263 checkDefaultPrologue(Version, Format, Expected2->Prologue, 32); 264 EXPECT_EQ(Expected2->Sequences.size(), 2u); 265 266 EXPECT_NE(Expected, Expected2); 267 268 // Check that if the same offset is requested, the exact same pointer is 269 // returned. 270 Recoverable = Error::success(); 271 auto ExpectedLineTable3 = Line.getOrParseLineTable( 272 LineData, 0, *Context, nullptr, RecordRecoverable); 273 ASSERT_TRUE(ExpectedLineTable3.operator bool()); 274 EXPECT_FALSE(Recoverable); 275 EXPECT_EQ(Expected, *ExpectedLineTable3); 276 277 Recoverable = Error::success(); 278 auto ExpectedLineTable4 = Line.getOrParseLineTable( 279 LineData, SecondOffset, *Context, nullptr, RecordRecoverable); 280 ASSERT_TRUE(ExpectedLineTable4.operator bool()); 281 EXPECT_FALSE(Recoverable); 282 EXPECT_EQ(Expected2, *ExpectedLineTable4); 283 284 // TODO: Add tests that show that the body of the programs have been read 285 // correctly. 286 } 287 288 TEST_F(DebugLineBasicFixture, ErrorForReservedLength) { 289 if (!setupGenerator()) 290 return; 291 292 LineTable < = Gen->addLineTable(); 293 LT.setCustomPrologue({{0xffffff00, LineTable::Long}}); 294 295 generate(); 296 297 checkGetOrParseLineTableEmitsError( 298 "parsing line table prologue at offset 0x00000000 unsupported reserved " 299 "unit length found of value 0xffffff00"); 300 } 301 302 TEST_F(DebugLineBasicFixture, ErrorForLowVersion) { 303 if (!setupGenerator()) 304 return; 305 306 LineTable < = Gen->addLineTable(); 307 LT.setCustomPrologue( 308 {{LineTable::Half, LineTable::Long}, {1, LineTable::Half}}); 309 310 generate(); 311 312 checkGetOrParseLineTableEmitsError("parsing line table prologue at offset " 313 "0x00000000 found unsupported version " 314 "0x01"); 315 } 316 317 TEST_F(DebugLineBasicFixture, ErrorForInvalidV5IncludeDirTable) { 318 if (!setupGenerator(5)) 319 return; 320 321 LineTable < = Gen->addLineTable(); 322 LT.setCustomPrologue({ 323 {19, LineTable::Long}, // unit length 324 {5, LineTable::Half}, // version 325 {8, LineTable::Byte}, // addr size 326 {0, LineTable::Byte}, // segment selector size 327 {11, LineTable::Long}, // prologue length 328 {1, LineTable::Byte}, // min instruction length 329 {1, LineTable::Byte}, // max ops per instruction 330 {1, LineTable::Byte}, // default is_stmt 331 {0, LineTable::Byte}, // line base 332 {14, LineTable::Byte}, // line range 333 {2, LineTable::Byte}, // opcode base (small to reduce the amount of 334 // setup required). 335 {0, LineTable::Byte}, // standard opcode lengths 336 {0, LineTable::Byte}, // directory entry format count (should not be 337 // zero). 338 {0, LineTable::ULEB}, // directories count 339 {0, LineTable::Byte}, // file name entry format count 340 {0, LineTable::ULEB} // file name entry count 341 }); 342 343 generate(); 344 345 checkGetOrParseLineTableEmitsError( 346 "parsing line table prologue at 0x00000000 found an invalid directory or " 347 "file table description at 0x00000014"); 348 } 349 350 TEST_P(DebugLineParameterisedFixture, ErrorForTooLargePrologueLength) { 351 if (!setupGenerator(Version)) 352 return; 353 354 SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " + 355 (Format == DWARF64 ? "DWARF64" : "DWARF32")); 356 357 LineTable < = Gen->addLineTable(Format); 358 DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); 359 ++Prologue.PrologueLength; 360 LT.setPrologue(Prologue); 361 362 generate(); 363 364 uint64_t ExpectedEnd = 365 Prologue.TotalLength + 1 + Prologue.sizeofTotalLength(); 366 checkGetOrParseLineTableEmitsError( 367 (Twine("parsing line table prologue at 0x00000000 should have ended at " 368 "0x000000") + 369 Twine::utohexstr(ExpectedEnd) + " but it ended at 0x000000" + 370 Twine::utohexstr(ExpectedEnd - 1)) 371 .str()); 372 } 373 374 TEST_P(DebugLineParameterisedFixture, ErrorForTooShortPrologueLength) { 375 if (!setupGenerator(Version)) 376 return; 377 378 SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " + 379 (Format == DWARF64 ? "DWARF64" : "DWARF32")); 380 381 LineTable < = Gen->addLineTable(Format); 382 DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue(); 383 // FIXME: Ideally, we'd test for 1 less than expected, but the code does not 384 // currently fail if missing only the terminator of a v2-4 file table. 385 if (Version < 5) 386 Prologue.PrologueLength -= 2; 387 else 388 Prologue.PrologueLength -= 1; 389 LT.setPrologue(Prologue); 390 391 generate(); 392 393 uint64_t ExpectedEnd = 394 Prologue.TotalLength - 1 + Prologue.sizeofTotalLength(); 395 if (Version < 5) 396 --ExpectedEnd; 397 checkGetOrParseLineTableEmitsError( 398 (Twine("parsing line table prologue at 0x00000000 should have ended at " 399 "0x000000") + 400 Twine::utohexstr(ExpectedEnd) + " but it ended at 0x000000" + 401 Twine::utohexstr(ExpectedEnd + 1)) 402 .str()); 403 } 404 405 INSTANTIATE_TEST_CASE_P( 406 LineTableTestParams, DebugLineParameterisedFixture, 407 Values(std::make_pair( 408 2, DWARF32), // Test lower-bound of v2-3 fields and DWARF32. 409 std::make_pair(3, DWARF32), // Test upper-bound of v2-3 fields. 410 std::make_pair(4, DWARF64), // Test v4 fields and DWARF64. 411 std::make_pair(5, DWARF32), std::make_pair(5, DWARF64)), ); 412 413 TEST_F(DebugLineBasicFixture, ErrorForInvalidExtendedOpcodeLength) { 414 if (!setupGenerator()) 415 return; 416 417 LineTable < = Gen->addLineTable(); 418 // The Length should be 1 for an end sequence opcode. 419 LT.addExtendedOpcode(2, DW_LNE_end_sequence, {}); 420 421 generate(); 422 423 checkGetOrParseLineTableEmitsError("unexpected line op length at offset " 424 "0x00000030 expected 0x02 found 0x01"); 425 } 426 427 TEST_F(DebugLineBasicFixture, ErrorForMismatchedAddressSize) { 428 if (!setupGenerator()) 429 return; 430 431 LineTable < = Gen->addLineTable(); 432 // The line data extractor expects size 8 (Quad) addresses. 433 LT.addExtendedOpcode(5, DW_LNE_set_address, {{0x11223344, LineTable::Long}}); 434 LT.addStandardOpcode(DW_LNS_copy, {}); 435 LT.addByte(0xaa); 436 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 437 438 generate(); 439 440 checkGetOrParseLineTableEmitsError( 441 "mismatching address size at offset 0x00000030 expected 0x08 found 0x04"); 442 } 443 444 TEST_F(DebugLineBasicFixture, CallbackUsedForUnterminatedSequence) { 445 if (!setupGenerator()) 446 return; 447 448 LineTable < = Gen->addLineTable(); 449 LT.addExtendedOpcode(9, DW_LNE_set_address, 450 {{0x1122334455667788, LineTable::Quad}}); 451 LT.addStandardOpcode(DW_LNS_copy, {}); 452 LT.addByte(0xaa); 453 LT.addExtendedOpcode(1, DW_LNE_end_sequence, {}); 454 LT.addExtendedOpcode(9, DW_LNE_set_address, 455 {{0x99aabbccddeeff00, LineTable::Quad}}); 456 LT.addStandardOpcode(DW_LNS_copy, {}); 457 LT.addByte(0xbb); 458 LT.addByte(0xcc); 459 460 generate(); 461 462 auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context, 463 nullptr, RecordRecoverable); 464 checkError("last sequence in debug line table is not terminated!", 465 std::move(Recoverable)); 466 ASSERT_TRUE(ExpectedLineTable.operator bool()); 467 EXPECT_EQ((*ExpectedLineTable)->Rows.size(), 6u); 468 // The unterminated sequence is not added to the sequence list. 469 EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u); 470 } 471 472 TEST_F(DebugLineBasicFixture, ParserParsesCorrectly) { 473 if (!setupGenerator()) 474 return; 475 476 DWARFDebugLine::SectionParser Parser = setupParser(); 477 478 EXPECT_EQ(Parser.getOffset(), 0u); 479 ASSERT_FALSE(Parser.done()); 480 481 DWARFDebugLine::LineTable Parsed = 482 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 483 checkDefaultPrologue(4, DWARF32, Parsed.Prologue, 16); 484 EXPECT_EQ(Parsed.Sequences.size(), 1u); 485 EXPECT_EQ(Parser.getOffset(), 62u); 486 ASSERT_FALSE(Parser.done()); 487 488 DWARFDebugLine::LineTable Parsed2 = 489 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 490 checkDefaultPrologue(4, DWARF64, Parsed2.Prologue, 16); 491 EXPECT_EQ(Parsed2.Sequences.size(), 1u); 492 EXPECT_EQ(Parser.getOffset(), 136u); 493 EXPECT_TRUE(Parser.done()); 494 495 EXPECT_FALSE(Recoverable); 496 EXPECT_FALSE(Unrecoverable); 497 } 498 499 TEST_F(DebugLineBasicFixture, ParserSkipsCorrectly) { 500 if (!setupGenerator()) 501 return; 502 503 DWARFDebugLine::SectionParser Parser = setupParser(); 504 505 EXPECT_EQ(Parser.getOffset(), 0u); 506 ASSERT_FALSE(Parser.done()); 507 508 Parser.skip(RecordUnrecoverable); 509 EXPECT_EQ(Parser.getOffset(), 62u); 510 ASSERT_FALSE(Parser.done()); 511 512 Parser.skip(RecordUnrecoverable); 513 EXPECT_EQ(Parser.getOffset(), 136u); 514 EXPECT_TRUE(Parser.done()); 515 516 EXPECT_FALSE(Unrecoverable); 517 } 518 519 TEST_F(DebugLineBasicFixture, ParserAlwaysDoneForEmptySection) { 520 if (!setupGenerator()) 521 return; 522 523 generate(); 524 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 525 526 EXPECT_TRUE(Parser.done()); 527 } 528 529 TEST_F(DebugLineBasicFixture, ParserMovesToEndForBadLengthWhenParsing) { 530 if (!setupGenerator()) 531 return; 532 533 LineTable < = Gen->addLineTable(); 534 LT.setCustomPrologue({{0xffffff00, LineTable::Long}}); 535 Gen->addLineTable(); 536 generate(); 537 538 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 539 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 540 541 EXPECT_EQ(Parser.getOffset(), 4u); 542 EXPECT_TRUE(Parser.done()); 543 EXPECT_FALSE(Recoverable); 544 545 checkError("parsing line table prologue at offset 0x00000000 unsupported " 546 "reserved unit length found of value 0xffffff00", 547 std::move(Unrecoverable)); 548 } 549 550 TEST_F(DebugLineBasicFixture, ParserMovesToEndForBadLengthWhenSkipping) { 551 if (!setupGenerator()) 552 return; 553 554 LineTable < = Gen->addLineTable(); 555 LT.setCustomPrologue({{0xffffff00, LineTable::Long}}); 556 Gen->addLineTable(); 557 generate(); 558 559 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 560 Parser.skip(RecordUnrecoverable); 561 562 EXPECT_EQ(Parser.getOffset(), 4u); 563 EXPECT_TRUE(Parser.done()); 564 565 checkError("parsing line table prologue at offset 0x00000000 unsupported " 566 "reserved unit length found of value 0xffffff00", 567 std::move(Unrecoverable)); 568 } 569 570 TEST_F(DebugLineBasicFixture, ParserReportsFirstErrorInEachTableWhenParsing) { 571 if (!setupGenerator()) 572 return; 573 574 LineTable < = Gen->addLineTable(DWARF32); 575 LT.setCustomPrologue({{2, LineTable::Long}, {0, LineTable::Half}}); 576 LineTable <2 = Gen->addLineTable(DWARF32); 577 LT2.setCustomPrologue({{2, LineTable::Long}, {1, LineTable::Half}}); 578 generate(); 579 580 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 581 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 582 ASSERT_FALSE(Parser.done()); 583 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 584 585 EXPECT_TRUE(Parser.done()); 586 EXPECT_FALSE(Recoverable); 587 588 checkError({"parsing line table prologue at offset 0x00000000 found " 589 "unsupported version 0x00", 590 "parsing line table prologue at offset 0x00000006 found " 591 "unsupported version 0x01"}, 592 std::move(Unrecoverable)); 593 } 594 595 TEST_F(DebugLineBasicFixture, ParserReportsNonPrologueProblemsWhenParsing) { 596 if (!setupGenerator()) 597 return; 598 599 LineTable < = Gen->addLineTable(DWARF32); 600 LT.addExtendedOpcode(0x42, DW_LNE_end_sequence, {}); 601 LineTable <2 = Gen->addLineTable(DWARF32); 602 LT2.addExtendedOpcode(9, DW_LNE_set_address, 603 {{0x1234567890abcdef, LineTable::Quad}}); 604 LT2.addStandardOpcode(DW_LNS_copy, {}); 605 LT2.addByte(0xbb); 606 generate(); 607 608 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 609 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 610 EXPECT_FALSE(Recoverable); 611 ASSERT_FALSE(Parser.done()); 612 checkError( 613 "unexpected line op length at offset 0x00000030 expected 0x42 found 0x01", 614 std::move(Unrecoverable)); 615 616 // Reset the error state so that it does not confuse the next set of checks. 617 Unrecoverable = Error::success(); 618 Parser.parseNext(RecordRecoverable, RecordUnrecoverable); 619 620 EXPECT_TRUE(Parser.done()); 621 checkError("last sequence in debug line table is not terminated!", 622 std::move(Recoverable)); 623 EXPECT_FALSE(Unrecoverable); 624 } 625 626 TEST_F(DebugLineBasicFixture, 627 ParserReportsPrologueErrorsInEachTableWhenSkipping) { 628 if (!setupGenerator()) 629 return; 630 631 LineTable < = Gen->addLineTable(DWARF32); 632 LT.setCustomPrologue({{2, LineTable::Long}, {0, LineTable::Half}}); 633 LineTable <2 = Gen->addLineTable(DWARF32); 634 LT2.setCustomPrologue({{2, LineTable::Long}, {1, LineTable::Half}}); 635 generate(); 636 637 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 638 Parser.skip(RecordUnrecoverable); 639 ASSERT_FALSE(Parser.done()); 640 Parser.skip(RecordUnrecoverable); 641 642 EXPECT_TRUE(Parser.done()); 643 644 checkError({"parsing line table prologue at offset 0x00000000 found " 645 "unsupported version 0x00", 646 "parsing line table prologue at offset 0x00000006 found " 647 "unsupported version 0x01"}, 648 std::move(Unrecoverable)); 649 } 650 651 TEST_F(DebugLineBasicFixture, ParserIgnoresNonPrologueErrorsWhenSkipping) { 652 if (!setupGenerator()) 653 return; 654 655 LineTable < = Gen->addLineTable(DWARF32); 656 LT.addExtendedOpcode(42, DW_LNE_end_sequence, {}); 657 generate(); 658 659 DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs); 660 Parser.skip(RecordUnrecoverable); 661 662 EXPECT_TRUE(Parser.done()); 663 EXPECT_FALSE(Unrecoverable); 664 } 665 666 } // end anonymous namespace 667