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