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