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 = 42;
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   ASSERT_EQ(Prologue.FileNames[0].DirIdx, 0u);
208   EXPECT_STREQ(*Prologue.FileNames[0].Name.getAsCString(), "a file");
209 }
210 
211 TEST_F(DebugLineBasicFixture, GetOrParseLineTableAtInvalidOffset) {
212   if (!setupGenerator())
213     return;
214   generate();
215 
216   checkGetOrParseLineTableEmitsFatalError(
217       "offset 0x00000000 is not a valid debug line section offset", 0);
218   // Repeat to show that an error is reported each time.
219   checkGetOrParseLineTableEmitsFatalError(
220       "offset 0x00000000 is not a valid debug line section offset", 0);
221   // Show that an error is reported for later offsets too.
222   checkGetOrParseLineTableEmitsFatalError(
223       "offset 0x00000001 is not a valid debug line section offset", 1);
224 }
225 
226 TEST_F(DebugLineBasicFixture, GetOrParseLineTableAtInvalidOffsetAfterData) {
227   if (!setupGenerator())
228     return;
229 
230   LineTable &LT = Gen->addLineTable();
231   LT.setCustomPrologue({{0, LineTable::Byte}});
232 
233   generate();
234 
235   checkGetOrParseLineTableEmitsFatalError(
236       "offset 0x00000001 is not a valid debug line section offset", 1);
237 }
238 
239 TEST_P(DebugLineParameterisedFixture, PrologueGetLength) {
240   if (!setupGenerator(Version))
241     return;
242   LineTable &LT = Gen->addLineTable(Format);
243   DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue();
244   LT.setPrologue(Prologue);
245   generate();
246 
247   // + 10 for sizes of DWARF-32 unit length, version, prologue length.
248   uint64_t ExpectedLength = Prologue.PrologueLength + 10;
249   if (Version == 5)
250     // Add address and segment selector size fields.
251     ExpectedLength += 2;
252   if (Format == DWARF64)
253     // Unit length grows by 8, prologue length by 4.
254     ExpectedLength += 12;
255 
256   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
257                                                     nullptr, RecordRecoverable);
258   ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
259   EXPECT_EQ((*ExpectedLineTable)->Prologue.getLength(), ExpectedLength);
260 }
261 
262 TEST_P(DebugLineParameterisedFixture, GetOrParseLineTableValidTable) {
263   if (!setupGenerator(Version))
264     return;
265 
266   SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " +
267                (Format == DWARF64 ? "DWARF64" : "DWARF32"));
268 
269   LineTable &LT = Gen->addLineTable(Format);
270   LT.addExtendedOpcode(9, DW_LNE_set_address, {{0xadd4e55, LineTable::Quad}});
271   LT.addStandardOpcode(DW_LNS_copy, {});
272   LT.addByte(0xaa);
273   LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
274 
275   LineTable &LT2 = Gen->addLineTable(Format);
276   LT2.addExtendedOpcode(9, DW_LNE_set_address, {{0x11223344, LineTable::Quad}});
277   LT2.addStandardOpcode(DW_LNS_copy, {});
278   LT2.addByte(0xbb);
279   LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {});
280   LT2.addExtendedOpcode(9, DW_LNE_set_address, {{0x55667788, LineTable::Quad}});
281   LT2.addStandardOpcode(DW_LNS_copy, {});
282   LT2.addByte(0xcc);
283   LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {});
284 
285   generate();
286 
287   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
288                                                     nullptr, RecordRecoverable);
289   ASSERT_TRUE(ExpectedLineTable.operator bool());
290   EXPECT_FALSE(Recoverable);
291   const DWARFDebugLine::LineTable *Expected = *ExpectedLineTable;
292   checkDefaultPrologue(Version, Format, Expected->Prologue, 16);
293   EXPECT_EQ(Expected->Sequences.size(), 1u);
294 
295   uint64_t SecondOffset =
296       Expected->Prologue.sizeofTotalLength() + Expected->Prologue.TotalLength;
297   Recoverable = Error::success();
298   auto ExpectedLineTable2 = Line.getOrParseLineTable(
299       LineData, SecondOffset, *Context, nullptr, RecordRecoverable);
300   ASSERT_TRUE(ExpectedLineTable2.operator bool());
301   EXPECT_FALSE(Recoverable);
302   const DWARFDebugLine::LineTable *Expected2 = *ExpectedLineTable2;
303   checkDefaultPrologue(Version, Format, Expected2->Prologue, 32);
304   EXPECT_EQ(Expected2->Sequences.size(), 2u);
305 
306   EXPECT_NE(Expected, Expected2);
307 
308   // Check that if the same offset is requested, the exact same pointer is
309   // returned.
310   Recoverable = Error::success();
311   auto ExpectedLineTable3 = Line.getOrParseLineTable(
312       LineData, 0, *Context, nullptr, RecordRecoverable);
313   ASSERT_TRUE(ExpectedLineTable3.operator bool());
314   EXPECT_FALSE(Recoverable);
315   EXPECT_EQ(Expected, *ExpectedLineTable3);
316 
317   Recoverable = Error::success();
318   auto ExpectedLineTable4 = Line.getOrParseLineTable(
319       LineData, SecondOffset, *Context, nullptr, RecordRecoverable);
320   ASSERT_TRUE(ExpectedLineTable4.operator bool());
321   EXPECT_FALSE(Recoverable);
322   EXPECT_EQ(Expected2, *ExpectedLineTable4);
323 
324   // TODO: Add tests that show that the body of the programs have been read
325   // correctly.
326 }
327 
328 TEST_F(DebugLineBasicFixture, ErrorForReservedLength) {
329   if (!setupGenerator())
330     return;
331 
332   LineTable &LT = Gen->addLineTable();
333   LT.setCustomPrologue({{0xfffffff0, LineTable::Long}});
334 
335   generate();
336 
337   checkGetOrParseLineTableEmitsFatalError(
338       "parsing line table prologue at offset 0x00000000 unsupported reserved "
339       "unit length found of value 0xfffffff0");
340 }
341 
342 struct DebugLineUnsupportedVersionFixture : public TestWithParam<uint16_t>,
343                                             public CommonFixture {
344   void SetUp() { Version = GetParam(); }
345 
346   uint16_t Version;
347 };
348 
349 TEST_P(DebugLineUnsupportedVersionFixture, ErrorForUnsupportedVersion) {
350   if (!setupGenerator())
351     return;
352 
353   LineTable &LT = Gen->addLineTable();
354   LT.setCustomPrologue(
355       {{LineTable::Half, LineTable::Long}, {Version, LineTable::Half}});
356 
357   generate();
358 
359   checkGetOrParseLineTableEmitsFatalError(
360       "parsing line table prologue at offset 0x00000000 found unsupported "
361       "version " +
362       std::to_string(Version));
363 }
364 
365 INSTANTIATE_TEST_CASE_P(UnsupportedVersionTestParams,
366                         DebugLineUnsupportedVersionFixture,
367                         Values(/*1 below min */ 1, /* 1 above max */ 6,
368                                /* Maximum possible */ 0xffff), );
369 
370 TEST_F(DebugLineBasicFixture, ErrorForInvalidV5IncludeDirTable) {
371   if (!setupGenerator(5))
372     return;
373 
374   LineTable &LT = Gen->addLineTable();
375   LT.setCustomPrologue({
376       {19, LineTable::Long}, // unit length
377       {5, LineTable::Half},  // version
378       {8, LineTable::Byte},  // addr size
379       {0, LineTable::Byte},  // segment selector size
380       {11, LineTable::Long}, // prologue length
381       {1, LineTable::Byte},  // min instruction length
382       {1, LineTable::Byte},  // max ops per instruction
383       {1, LineTable::Byte},  // default is_stmt
384       {0, LineTable::Byte},  // line base
385       {14, LineTable::Byte}, // line range
386       {2, LineTable::Byte},  // opcode base (small to reduce the amount of
387                              // setup required).
388       {0, LineTable::Byte},  // standard opcode lengths
389       {0, LineTable::Byte},  // directory entry format count (should not be
390                              // zero).
391       {0, LineTable::ULEB},  // directories count
392       {0, LineTable::Byte},  // file name entry format count
393       {0, LineTable::ULEB}   // file name entry count
394   });
395 
396   generate();
397 
398   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
399                                                     nullptr, RecordRecoverable);
400   EXPECT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
401 
402   checkError(
403       {"parsing line table prologue at 0x00000000 found an invalid directory "
404        "or file table description at 0x00000014",
405        "failed to parse entry content descriptions because no path was found"},
406       std::move(Recoverable));
407 }
408 
409 TEST_P(DebugLineParameterisedFixture, ErrorForTooLargePrologueLength) {
410   if (!setupGenerator(Version))
411     return;
412 
413   SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " +
414                (Format == DWARF64 ? "DWARF64" : "DWARF32"));
415 
416   LineTable &LT = Gen->addLineTable(Format);
417   DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue();
418   ++Prologue.PrologueLength;
419   LT.setPrologue(Prologue);
420 
421   generate();
422 
423   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
424                                                     nullptr, RecordRecoverable);
425   ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
426   DWARFDebugLine::LineTable Result(**ExpectedLineTable);
427   // Undo the earlier modification so that it can be compared against a
428   // "default" prologue.
429   --Result.Prologue.PrologueLength;
430   checkDefaultPrologue(Version, Format, Result.Prologue, 0);
431 
432   uint64_t ExpectedEnd =
433       Prologue.TotalLength + 1 + Prologue.sizeofTotalLength();
434   checkError(
435       (Twine("parsing line table prologue at 0x00000000 should have ended at "
436              "0x000000") +
437        Twine::utohexstr(ExpectedEnd) + " but it ended at 0x000000" +
438        Twine::utohexstr(ExpectedEnd - 1))
439           .str(),
440       std::move(Recoverable));
441 }
442 
443 TEST_P(DebugLineParameterisedFixture, ErrorForTooShortPrologueLength) {
444   if (!setupGenerator(Version))
445     return;
446 
447   SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " +
448                (Format == DWARF64 ? "DWARF64" : "DWARF32"));
449 
450   LineTable &LT = Gen->addLineTable(Format);
451   DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue();
452   Prologue.PrologueLength -= 2;
453   LT.setPrologue(Prologue);
454 
455   generate();
456 
457   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
458                                                     nullptr, RecordRecoverable);
459   ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
460   DWARFDebugLine::LineTable Result(**ExpectedLineTable);
461   // Undo the earlier modification so that it can be compared against a
462   // "default" prologue.
463   Result.Prologue.PrologueLength += 2;
464   checkDefaultPrologue(Version, Format, Result.Prologue, 0);
465 
466   uint64_t ExpectedEnd =
467       Prologue.TotalLength - 2 + Prologue.sizeofTotalLength();
468   std::vector<std::string> Errs;
469   // Parsing of a DWARFv2-4 file table stops at the end of an entry once the
470   // prologue end has been reached, whether or not the trailing null terminator
471   // has been found. As such, the expected error message will be slightly
472   // different.
473   uint64_t ActualEnd = Version == 5 ? ExpectedEnd + 2 : ExpectedEnd + 1;
474   if (Version != 5) {
475     Errs.emplace_back(
476         (Twine("parsing line table prologue at 0x00000000 found an invalid "
477                "directory or file table description at 0x000000") +
478          Twine::utohexstr(ActualEnd))
479             .str());
480     Errs.emplace_back("file names table was not null terminated before the end "
481                       "of the prologue");
482   }
483   Errs.emplace_back(
484       (Twine("parsing line table prologue at 0x00000000 should have ended at "
485              "0x000000") +
486        Twine::utohexstr(ExpectedEnd) + " but it ended at 0x000000" +
487        Twine::utohexstr(ActualEnd))
488           .str());
489   std::vector<StringRef> ErrRefs(Errs.begin(), Errs.end());
490   checkError(ErrRefs, std::move(Recoverable));
491 }
492 
493 INSTANTIATE_TEST_CASE_P(
494     LineTableTestParams, DebugLineParameterisedFixture,
495     Values(std::make_pair(
496                2, DWARF32), // Test lower-bound of v2-3 fields and DWARF32.
497            std::make_pair(3, DWARF32), // Test upper-bound of v2-3 fields.
498            std::make_pair(4, DWARF64), // Test v4 fields and DWARF64.
499            std::make_pair(5, DWARF32), std::make_pair(5, DWARF64)), );
500 
501 TEST_F(DebugLineBasicFixture, ErrorForExtendedOpcodeLengthSmallerThanExpected) {
502   if (!setupGenerator())
503     return;
504 
505   LineTable &LT = Gen->addLineTable();
506   LT.addByte(0xaa);
507   // The Length should be 1 + sizeof(ULEB) for a set discriminator opcode.
508   // The operand will be read for both the discriminator opcode and then parsed
509   // again as DW_LNS_negate_stmt, to respect the claimed length.
510   LT.addExtendedOpcode(1, DW_LNE_set_discriminator,
511                        {{DW_LNS_negate_stmt, LineTable::ULEB}});
512   LT.addByte(0xbb);
513   LT.addStandardOpcode(DW_LNS_const_add_pc, {});
514   LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
515 
516   generate();
517 
518   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
519                                                     nullptr, RecordRecoverable);
520   checkError(
521       "unexpected line op length at offset 0x00000031 expected 0x01 found 0x02",
522       std::move(Recoverable));
523   ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
524   ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 3u);
525   EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u);
526   EXPECT_EQ((*ExpectedLineTable)->Rows[1].IsStmt, 0u);
527   EXPECT_EQ((*ExpectedLineTable)->Rows[1].Discriminator, DW_LNS_negate_stmt);
528 }
529 
530 TEST_F(DebugLineBasicFixture, ErrorForExtendedOpcodeLengthLargerThanExpected) {
531   if (!setupGenerator())
532     return;
533 
534   LineTable &LT = Gen->addLineTable();
535   LT.addByte(0xaa);
536   LT.addStandardOpcode(DW_LNS_const_add_pc, {});
537   // The Length should be 1 for an end sequence opcode.
538   LT.addExtendedOpcode(2, DW_LNE_end_sequence, {});
539   // The negate statement opcode will be skipped.
540   LT.addStandardOpcode(DW_LNS_negate_stmt, {});
541   LT.addByte(0xbb);
542   LT.addStandardOpcode(DW_LNS_const_add_pc, {});
543   LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
544 
545   generate();
546 
547   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
548                                                     nullptr, RecordRecoverable);
549   checkError(
550       "unexpected line op length at offset 0x00000032 expected 0x02 found 0x01",
551       std::move(Recoverable));
552   ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
553   ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 4u);
554   EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 2u);
555   ASSERT_EQ((*ExpectedLineTable)->Sequences[1].FirstRowIndex, 2u);
556   EXPECT_EQ((*ExpectedLineTable)->Rows[2].IsStmt, 1u);
557 }
558 
559 TEST_F(DebugLineBasicFixture, ErrorForUnitLengthTooLarge) {
560   if (!setupGenerator())
561     return;
562 
563   LineTable &Padding = Gen->addLineTable();
564   // Add some padding to show that a non-zero offset is handled correctly.
565   Padding.setCustomPrologue({{0, LineTable::Byte}});
566   LineTable &LT = Gen->addLineTable();
567   LT.addStandardOpcode(DW_LNS_copy, {});
568   LT.addStandardOpcode(DW_LNS_const_add_pc, {});
569   LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
570   DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue();
571   // Set the total length to 1 higher than the actual length.
572   ++Prologue.TotalLength;
573   LT.setPrologue(Prologue);
574 
575   generate();
576 
577   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 1, *Context,
578                                                     nullptr, RecordRecoverable);
579   checkError("line table program with offset 0x00000001 has length 0x00000034 "
580              "but only 0x00000033 bytes are available",
581              std::move(Recoverable));
582   ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
583   EXPECT_EQ((*ExpectedLineTable)->Rows.size(), 2u);
584   EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u);
585 }
586 
587 TEST_F(DebugLineBasicFixture, ErrorForMismatchedAddressSize) {
588   if (!setupGenerator(4, 8))
589     return;
590 
591   LineTable &LT = Gen->addLineTable();
592   // The line data extractor expects size 8 (Quad) addresses.
593   uint64_t Addr1 = 0x11223344;
594   LT.addExtendedOpcode(5, DW_LNE_set_address, {{Addr1, LineTable::Long}});
595   LT.addStandardOpcode(DW_LNS_copy, {});
596   // Show that the expected address size is unchanged, so later valid lines
597   // don't cause a problem.
598   uint64_t Addr2 = 0x1122334455667788;
599   LT.addExtendedOpcode(9, DW_LNE_set_address, {{Addr2, LineTable::Quad}});
600   LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
601 
602   generate();
603 
604   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
605                                                     nullptr, RecordRecoverable);
606   checkError(
607       "mismatching address size at offset 0x00000030 expected 0x08 found 0x04",
608       std::move(Recoverable));
609   ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
610   ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 2u);
611   EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u);
612   EXPECT_EQ((*ExpectedLineTable)->Rows[0].Address.Address, Addr1);
613   EXPECT_EQ((*ExpectedLineTable)->Rows[1].Address.Address, Addr2);
614 }
615 
616 TEST_F(DebugLineBasicFixture,
617        ErrorForMismatchedAddressSizeUnsetInitialAddress) {
618   if (!setupGenerator(4, 0))
619     return;
620 
621   LineTable &LT = Gen->addLineTable();
622   uint64_t Addr1 = 0x11223344;
623   LT.addExtendedOpcode(5, DW_LNE_set_address, {{Addr1, LineTable::Long}});
624   LT.addStandardOpcode(DW_LNS_copy, {});
625   uint64_t Addr2 = 0x1122334455667788;
626   LT.addExtendedOpcode(9, DW_LNE_set_address, {{Addr2, LineTable::Quad}});
627   LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
628 
629   generate();
630 
631   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
632                                                     nullptr, RecordRecoverable);
633   checkError(
634       "mismatching address size at offset 0x00000038 expected 0x04 found 0x08",
635       std::move(Recoverable));
636   ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
637   ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 2u);
638   EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u);
639   EXPECT_EQ((*ExpectedLineTable)->Rows[0].Address.Address, Addr1);
640   EXPECT_EQ((*ExpectedLineTable)->Rows[1].Address.Address, Addr2);
641 }
642 
643 TEST_F(DebugLineBasicFixture, CallbackUsedForUnterminatedSequence) {
644   if (!setupGenerator())
645     return;
646 
647   LineTable &LT = Gen->addLineTable();
648   LT.addExtendedOpcode(9, DW_LNE_set_address,
649                        {{0x1122334455667788, LineTable::Quad}});
650   LT.addStandardOpcode(DW_LNS_copy, {});
651   LT.addByte(0xaa);
652   LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
653   LT.addExtendedOpcode(9, DW_LNE_set_address,
654                        {{0x99aabbccddeeff00, LineTable::Quad}});
655   LT.addStandardOpcode(DW_LNS_copy, {});
656   LT.addByte(0xbb);
657   LT.addByte(0xcc);
658 
659   generate();
660 
661   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
662                                                     nullptr, RecordRecoverable);
663   checkError("last sequence in debug line table at offset 0x00000000 is not "
664              "terminated",
665              std::move(Recoverable));
666   ASSERT_TRUE(ExpectedLineTable.operator bool());
667   EXPECT_EQ((*ExpectedLineTable)->Rows.size(), 6u);
668   // The unterminated sequence is not added to the sequence list.
669   EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u);
670 }
671 
672 TEST_F(DebugLineBasicFixture, ParserParsesCorrectly) {
673   if (!setupGenerator())
674     return;
675 
676   DWARFDebugLine::SectionParser Parser = setupParser();
677 
678   EXPECT_EQ(Parser.getOffset(), 0u);
679   ASSERT_FALSE(Parser.done());
680 
681   DWARFDebugLine::LineTable Parsed =
682       Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
683   checkDefaultPrologue(4, DWARF32, Parsed.Prologue, 16);
684   EXPECT_EQ(Parsed.Sequences.size(), 1u);
685   EXPECT_EQ(Parser.getOffset(), 62u);
686   ASSERT_FALSE(Parser.done());
687 
688   DWARFDebugLine::LineTable Parsed2 =
689       Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
690   checkDefaultPrologue(4, DWARF64, Parsed2.Prologue, 16);
691   EXPECT_EQ(Parsed2.Sequences.size(), 1u);
692   EXPECT_EQ(Parser.getOffset(), 136u);
693   EXPECT_TRUE(Parser.done());
694 
695   EXPECT_FALSE(Recoverable);
696   EXPECT_FALSE(Unrecoverable);
697 }
698 
699 TEST_F(DebugLineBasicFixture, ParserSkipsCorrectly) {
700   if (!setupGenerator())
701     return;
702 
703   DWARFDebugLine::SectionParser Parser = setupParser();
704 
705   EXPECT_EQ(Parser.getOffset(), 0u);
706   ASSERT_FALSE(Parser.done());
707 
708   Parser.skip(RecordRecoverable, RecordUnrecoverable);
709   EXPECT_EQ(Parser.getOffset(), 62u);
710   ASSERT_FALSE(Parser.done());
711 
712   Parser.skip(RecordRecoverable, RecordUnrecoverable);
713   EXPECT_EQ(Parser.getOffset(), 136u);
714   EXPECT_TRUE(Parser.done());
715 
716   EXPECT_FALSE(Recoverable);
717   EXPECT_FALSE(Unrecoverable);
718 }
719 
720 TEST_F(DebugLineBasicFixture, ParserAlwaysDoneForEmptySection) {
721   if (!setupGenerator())
722     return;
723 
724   generate();
725   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
726 
727   EXPECT_TRUE(Parser.done());
728 }
729 
730 TEST_F(DebugLineBasicFixture, ParserMovesToEndForBadLengthWhenParsing) {
731   if (!setupGenerator())
732     return;
733 
734   LineTable &LT = Gen->addLineTable();
735   LT.setCustomPrologue({{0xfffffff0, LineTable::Long}});
736   Gen->addLineTable();
737   generate();
738 
739   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
740   Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
741 
742   EXPECT_EQ(Parser.getOffset(), 4u);
743   EXPECT_TRUE(Parser.done());
744   EXPECT_FALSE(Recoverable);
745 
746   checkError("parsing line table prologue at offset 0x00000000 unsupported "
747              "reserved unit length found of value 0xfffffff0",
748              std::move(Unrecoverable));
749 }
750 
751 TEST_F(DebugLineBasicFixture, ParserMovesToEndForBadLengthWhenSkipping) {
752   if (!setupGenerator())
753     return;
754 
755   LineTable &LT = Gen->addLineTable();
756   LT.setCustomPrologue({{0xfffffff0, LineTable::Long}});
757   Gen->addLineTable();
758   generate();
759 
760   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
761   Parser.skip(RecordRecoverable, RecordUnrecoverable);
762 
763   EXPECT_EQ(Parser.getOffset(), 4u);
764   EXPECT_TRUE(Parser.done());
765   EXPECT_FALSE(Recoverable);
766 
767   checkError("parsing line table prologue at offset 0x00000000 unsupported "
768              "reserved unit length found of value 0xfffffff0",
769              std::move(Unrecoverable));
770 }
771 
772 TEST_F(DebugLineBasicFixture, ParserReportsFirstErrorInEachTableWhenParsing) {
773   if (!setupGenerator())
774     return;
775 
776   LineTable &LT = Gen->addLineTable(DWARF32);
777   LT.setCustomPrologue({{2, LineTable::Long}, {0, LineTable::Half}});
778   LineTable &LT2 = Gen->addLineTable(DWARF32);
779   LT2.setCustomPrologue({{2, LineTable::Long}, {1, LineTable::Half}});
780   generate();
781 
782   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
783   Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
784   ASSERT_FALSE(Parser.done());
785   Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
786 
787   EXPECT_TRUE(Parser.done());
788   EXPECT_FALSE(Recoverable);
789 
790   checkError({"parsing line table prologue at offset 0x00000000 found "
791               "unsupported version 0",
792               "parsing line table prologue at offset 0x00000006 found "
793               "unsupported version 1"},
794              std::move(Unrecoverable));
795 }
796 
797 TEST_F(DebugLineBasicFixture, ParserReportsNonPrologueProblemsWhenParsing) {
798   if (!setupGenerator())
799     return;
800 
801   LineTable &LT = Gen->addLineTable(DWARF32);
802   LT.addExtendedOpcode(0x42, DW_LNE_end_sequence, {});
803   LineTable &LT2 = Gen->addLineTable(DWARF32);
804   LT2.addExtendedOpcode(9, DW_LNE_set_address,
805                         {{0x1234567890abcdef, LineTable::Quad}});
806   LT2.addStandardOpcode(DW_LNS_copy, {});
807   LT2.addByte(0xbb);
808   generate();
809 
810   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
811   Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
812   EXPECT_FALSE(Unrecoverable);
813   ASSERT_FALSE(Parser.done());
814   checkError(
815       "unexpected line op length at offset 0x00000030 expected 0x42 found 0x01",
816       std::move(Recoverable));
817 
818   // Reset the error state so that it does not confuse the next set of checks.
819   Unrecoverable = Error::success();
820   Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
821 
822   EXPECT_TRUE(Parser.done());
823   checkError("last sequence in debug line table at offset 0x00000031 is not "
824              "terminated",
825              std::move(Recoverable));
826   EXPECT_FALSE(Unrecoverable);
827 }
828 
829 TEST_F(DebugLineBasicFixture,
830        ParserReportsPrologueErrorsInEachTableWhenSkipping) {
831   if (!setupGenerator())
832     return;
833 
834   LineTable &LT = Gen->addLineTable(DWARF32);
835   LT.setCustomPrologue({{2, LineTable::Long}, {0, LineTable::Half}});
836   LineTable &LT2 = Gen->addLineTable(DWARF32);
837   LT2.setCustomPrologue({{2, LineTable::Long}, {1, LineTable::Half}});
838   generate();
839 
840   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
841   Parser.skip(RecordRecoverable, RecordUnrecoverable);
842   ASSERT_FALSE(Parser.done());
843   Parser.skip(RecordRecoverable, RecordUnrecoverable);
844 
845   EXPECT_TRUE(Parser.done());
846   EXPECT_FALSE(Recoverable);
847 
848   checkError({"parsing line table prologue at offset 0x00000000 found "
849               "unsupported version 0",
850               "parsing line table prologue at offset 0x00000006 found "
851               "unsupported version 1"},
852              std::move(Unrecoverable));
853 }
854 
855 TEST_F(DebugLineBasicFixture, ParserIgnoresNonPrologueErrorsWhenSkipping) {
856   if (!setupGenerator())
857     return;
858 
859   LineTable &LT = Gen->addLineTable(DWARF32);
860   LT.addExtendedOpcode(42, DW_LNE_end_sequence, {});
861   generate();
862 
863   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
864   Parser.skip(RecordRecoverable, RecordUnrecoverable);
865 
866   EXPECT_TRUE(Parser.done());
867   EXPECT_FALSE(Recoverable);
868   EXPECT_FALSE(Unrecoverable);
869 }
870 
871 TEST_F(DebugLineBasicFixture, ParserPrintsStandardOpcodesWhenRequested) {
872   if (!setupGenerator())
873     return;
874 
875   using ValLen = dwarfgen::LineTable::ValueAndLength;
876   LineTable &LT = Gen->addLineTable(DWARF32);
877   LT.addStandardOpcode(DW_LNS_copy, {});
878   LT.addStandardOpcode(DW_LNS_advance_pc, {ValLen{11, LineTable::ULEB}});
879   LT.addStandardOpcode(DW_LNS_advance_line, {ValLen{22, LineTable::SLEB}});
880   LT.addStandardOpcode(DW_LNS_set_file, {ValLen{33, LineTable::ULEB}});
881   LT.addStandardOpcode(DW_LNS_set_column, {ValLen{44, LineTable::ULEB}});
882   LT.addStandardOpcode(DW_LNS_negate_stmt, {});
883   LT.addStandardOpcode(DW_LNS_set_basic_block, {});
884   LT.addStandardOpcode(DW_LNS_const_add_pc, {});
885   LT.addStandardOpcode(DW_LNS_fixed_advance_pc, {ValLen{55, LineTable::Half}});
886   LT.addStandardOpcode(DW_LNS_set_prologue_end, {});
887   LT.addStandardOpcode(DW_LNS_set_epilogue_begin, {});
888   LT.addStandardOpcode(DW_LNS_set_isa, {ValLen{66, LineTable::ULEB}});
889   LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
890   generate();
891 
892   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
893   std::string Output;
894   raw_string_ostream OS(Output);
895   Parser.parseNext(RecordRecoverable, RecordUnrecoverable, &OS);
896   OS.flush();
897 
898   EXPECT_FALSE(Recoverable);
899   EXPECT_FALSE(Unrecoverable);
900   auto InOutput = [&Output](char const *Str) {
901     return Output.find(Str) != std::string::npos;
902   };
903   EXPECT_TRUE(InOutput("0x0000002e: 01 DW_LNS_copy\n")) << Output;
904   EXPECT_TRUE(InOutput("0x0000002f: 02 DW_LNS_advance_pc (11)\n")) << Output;
905   // FIXME: The value printed after DW_LNS_advance_line is currently the result
906   // of the advance, but it should be the value being advanced by. See
907   // https://bugs.llvm.org/show_bug.cgi?id=44261 for details.
908   EXPECT_TRUE(InOutput("0x00000031: 03 DW_LNS_advance_line (23)\n")) << Output;
909   EXPECT_TRUE(InOutput("0x00000033: 04 DW_LNS_set_file (33)\n")) << Output;
910   EXPECT_TRUE(InOutput("0x00000035: 05 DW_LNS_set_column (44)\n")) << Output;
911   EXPECT_TRUE(InOutput("0x00000037: 06 DW_LNS_negate_stmt\n")) << Output;
912   EXPECT_TRUE(InOutput("0x00000038: 07 DW_LNS_set_basic_block\n")) << Output;
913   EXPECT_TRUE(
914       InOutput("0x00000039: 08 DW_LNS_const_add_pc (0x0000000000000011)\n"))
915       << Output;
916   EXPECT_TRUE(InOutput("0x0000003a: 09 DW_LNS_fixed_advance_pc (0x0037)\n"))
917       << Output;
918   EXPECT_TRUE(InOutput("0x0000003d: 0a DW_LNS_set_prologue_end\n")) << Output;
919   EXPECT_TRUE(InOutput("0x0000003e: 0b DW_LNS_set_epilogue_begin\n")) << Output;
920   EXPECT_TRUE(InOutput("0x0000003f: 0c DW_LNS_set_isa (66)\n")) << Output;
921 }
922 
923 TEST_F(DebugLineBasicFixture, PrintPathsProperly) {
924   if (!setupGenerator(5))
925     return;
926 
927   LineTable &LT = Gen->addLineTable();
928   DWARFDebugLine::Prologue P = LT.createBasicPrologue();
929   P.IncludeDirectories.push_back(
930       DWARFFormValue::createFromPValue(DW_FORM_string, "b dir"));
931   P.FileNames.push_back(DWARFDebugLine::FileNameEntry());
932   P.FileNames.back().Name =
933       DWARFFormValue::createFromPValue(DW_FORM_string, "b file");
934   P.FileNames.back().DirIdx = 1;
935   P.PrologueLength += 14;
936   LT.setPrologue(P);
937   generate();
938 
939   auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
940                                                     nullptr, RecordRecoverable);
941   EXPECT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
942   std::string Result;
943   // DWARF 5 stores the compilation directory in two places: the Compilation
944   // Unit and the directory table entry 0, and implementations are free to use
945   // one or the other. This copy serves as the one stored in the CU.
946   StringRef CompDir = "a dir";
947   EXPECT_FALSE(
948       (*ExpectedLineTable)
949           ->Prologue.getFileNameByIndex(
950               1, CompDir, DILineInfoSpecifier::FileLineInfoKind::None, Result));
951   EXPECT_TRUE((*ExpectedLineTable)
952                   ->Prologue.getFileNameByIndex(
953                       1, CompDir,
954                       DILineInfoSpecifier::FileLineInfoKind::Default, Result));
955   EXPECT_STREQ(Result.c_str(), "b file");
956   EXPECT_TRUE((*ExpectedLineTable)
957                   ->Prologue.getFileNameByIndex(
958                       1, CompDir,
959                       DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath,
960                       Result));
961   EXPECT_THAT(Result.c_str(), MatchesRegex("b dir.b file"));
962   EXPECT_TRUE((*ExpectedLineTable)
963                   ->Prologue.getFileNameByIndex(
964                       1, CompDir,
965                       DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
966                       Result));
967   EXPECT_THAT(Result.c_str(), MatchesRegex("a dir.b dir.b file"));
968 }
969 
970 } // end anonymous namespace
971