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