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