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 &LT = 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 &LT2 = 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 &LT = 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 &LT = 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 &LT2 = 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 &LT = 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 &LT = 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 &LT = 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 &LT = 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 &LT = 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 &LT = 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 &LT = 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 &LT = 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 &LT = 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 &LT = 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 &LT = Gen->addLineTable(DWARF32);
575   LT.setCustomPrologue({{2, LineTable::Long}, {0, LineTable::Half}});
576   LineTable &LT2 = 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 &LT = Gen->addLineTable(DWARF32);
600   LT.addExtendedOpcode(0x42, DW_LNE_end_sequence, {});
601   LineTable &LT2 = 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 &LT = Gen->addLineTable(DWARF32);
632   LT.setCustomPrologue({{2, LineTable::Long}, {0, LineTable::Half}});
633   LineTable &LT2 = 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 &LT = 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