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