1 //===- DWARFDebugLineTest.cpp ---------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
17 // AIX doesn't support the debug_addr section
19 #define NO_SUPPORT_DEBUG_ADDR
23 using namespace dwarf
;
24 using namespace dwarfgen
;
25 using namespace object
;
26 using namespace utils
;
27 using namespace testing
;
30 struct CommonFixture
{
32 : LineData("", true, 0), Recoverable(Error::success()),
33 RecordRecoverable(std::bind(&CommonFixture::recordRecoverable
, this,
34 std::placeholders::_1
)),
35 Unrecoverable(Error::success()),
36 RecordUnrecoverable(std::bind(&CommonFixture::recordUnrecoverable
, this,
37 std::placeholders::_1
)){};
40 EXPECT_FALSE(Recoverable
);
41 EXPECT_FALSE(Unrecoverable
);
44 // Note: ASSERT_THAT_EXPECTED cannot be used in a non-void function, so
45 // setupGenerator() is split into two.
46 void setupGeneratorImpl(uint16_t Version
, uint8_t AddrSize
) {
47 AddressSize
= AddrSize
;
48 Triple T
= getDefaultTargetTripleForAddrSize(AddressSize
? AddressSize
: 8);
49 if (!isConfigurationSupported(T
))
51 auto ExpectedGenerator
= Generator::create(T
, Version
);
52 ASSERT_THAT_EXPECTED(ExpectedGenerator
, Succeeded());
53 Gen
= std::move(*ExpectedGenerator
);
56 bool setupGenerator(uint16_t Version
= 4, uint8_t AddrSize
= 8) {
57 setupGeneratorImpl(Version
, AddrSize
);
58 return Gen
!= nullptr;
62 Context
= createContext();
63 assert(Context
!= nullptr && "test state is not valid");
64 const DWARFObject
&Obj
= Context
->getDWARFObj();
65 uint8_t TargetAddrSize
= AddressSize
== 0 ? 8 : AddressSize
;
66 LineData
= DWARFDataExtractor(
67 Obj
, Obj
.getLineSection(),
68 getDefaultTargetTripleForAddrSize(TargetAddrSize
).isLittleEndian(),
72 std::unique_ptr
<DWARFContext
> createContext() {
73 assert(Gen
!= nullptr && "Generator is not set up");
74 StringRef FileBytes
= Gen
->generate();
75 MemoryBufferRef
FileBuffer(FileBytes
, "dwarf");
76 auto Obj
= object::ObjectFile::createObjectFile(FileBuffer
);
78 return DWARFContext::create(**Obj
);
82 DWARFDebugLine::SectionParser
setupParser() {
83 LineTable
<
= Gen
->addLineTable(DWARF32
);
84 LT
.addExtendedOpcode(9, DW_LNE_set_address
, {{0xadd4e55, LineTable::Quad
}});
85 LT
.addStandardOpcode(DW_LNS_copy
, {});
87 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
89 LineTable
<2
= Gen
->addLineTable(DWARF64
);
90 LT2
.addExtendedOpcode(9, DW_LNE_set_address
,
91 {{0x11223344, LineTable::Quad
}});
92 LT2
.addStandardOpcode(DW_LNS_copy
, {});
94 LT2
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
98 return DWARFDebugLine::SectionParser(LineData
, *Context
, Units
);
101 void recordRecoverable(Error Err
) {
102 Recoverable
= joinErrors(std::move(Recoverable
), std::move(Err
));
104 void recordUnrecoverable(Error Err
) {
105 Unrecoverable
= joinErrors(std::move(Unrecoverable
), std::move(Err
));
108 Expected
<const DWARFDebugLine::LineTable
*>
109 getOrParseLineTableFatalErrors(uint64_t Offset
= 0) {
110 auto ExpectedLineTable
= Line
.getOrParseLineTable(
111 LineData
, Offset
, *Context
, nullptr, RecordRecoverable
);
112 EXPECT_THAT_ERROR(std::move(Recoverable
), Succeeded());
113 return ExpectedLineTable
;
117 std::unique_ptr
<Generator
> Gen
;
118 std::unique_ptr
<DWARFContext
> Context
;
119 DWARFDataExtractor LineData
;
122 std::function
<void(Error
)> RecordRecoverable
;
124 std::function
<void(Error
)> RecordUnrecoverable
;
126 SmallVector
<std::unique_ptr
<DWARFUnit
>, 2> Units
;
129 // Fixtures must derive from "Test", but parameterised fixtures from
130 // "TestWithParam". It does not seem possible to inherit from both, so we share
131 // the common state in a separate class, inherited by the two fixture classes.
132 struct DebugLineBasicFixture
: public Test
, public CommonFixture
{};
134 struct DebugLineParameterisedFixture
135 : public TestWithParam
<std::pair
<uint16_t, DwarfFormat
>>,
136 public CommonFixture
{
137 void SetUp() override
{ std::tie(Version
, Format
) = GetParam(); }
143 void checkDefaultPrologue(uint16_t Version
, DwarfFormat Format
,
144 DWARFDebugLine::Prologue Prologue
,
145 uint64_t BodyLength
) {
146 // Check version specific fields and values.
148 uint64_t PrologueLength
;
152 UnitLength
= PrologueLength
+ 2;
153 EXPECT_EQ(Prologue
.MaxOpsPerInst
, 1u);
158 UnitLength
= PrologueLength
+ 2;
162 UnitLength
= PrologueLength
+ 4;
163 EXPECT_EQ(Prologue
.getAddressSize(), 8u);
164 EXPECT_EQ(Prologue
.SegSelectorSize
, 0u);
167 llvm_unreachable("unsupported DWARF version");
169 UnitLength
+= BodyLength
+ (Format
== DWARF32
? 4 : 8);
171 EXPECT_EQ(Prologue
.TotalLength
, UnitLength
);
172 EXPECT_EQ(Prologue
.PrologueLength
, PrologueLength
);
173 EXPECT_EQ(Prologue
.MinInstLength
, 1u);
174 EXPECT_EQ(Prologue
.DefaultIsStmt
, 1u);
175 EXPECT_EQ(Prologue
.LineBase
, -5);
176 EXPECT_EQ(Prologue
.LineRange
, 14u);
177 EXPECT_EQ(Prologue
.OpcodeBase
, 13u);
178 std::vector
<uint8_t> ExpectedLengths
= {0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1};
179 EXPECT_EQ(Prologue
.StandardOpcodeLengths
, ExpectedLengths
);
180 ASSERT_EQ(Prologue
.IncludeDirectories
.size(), 1u);
181 ASSERT_EQ(Prologue
.IncludeDirectories
[0].getForm(), DW_FORM_string
);
182 EXPECT_STREQ(*toString(Prologue
.IncludeDirectories
[0]), "a dir");
183 ASSERT_EQ(Prologue
.FileNames
.size(), 1u);
184 ASSERT_EQ(Prologue
.FileNames
[0].Name
.getForm(), DW_FORM_string
);
185 ASSERT_EQ(Prologue
.FileNames
[0].DirIdx
, 0u);
186 EXPECT_STREQ(*toString(Prologue
.FileNames
[0].Name
), "a file");
189 TEST_F(DebugLineBasicFixture
, GetOrParseLineTableAtInvalidOffset
) {
190 if (!setupGenerator())
194 EXPECT_THAT_EXPECTED(
195 getOrParseLineTableFatalErrors(0),
197 "offset 0x00000000 is not a valid debug line section offset"));
198 // Repeat to show that an error is reported each time.
199 EXPECT_THAT_EXPECTED(
200 getOrParseLineTableFatalErrors(0),
202 "offset 0x00000000 is not a valid debug line section offset"));
204 // Show that an error is reported for later offsets too.
205 EXPECT_THAT_EXPECTED(
206 getOrParseLineTableFatalErrors(1),
208 "offset 0x00000001 is not a valid debug line section offset"));
211 TEST_F(DebugLineBasicFixture
, GetOrParseLineTableAtInvalidOffsetAfterData
) {
212 if (!setupGenerator())
215 LineTable
<
= Gen
->addLineTable();
216 LT
.setCustomPrologue({{0, LineTable::Byte
}});
220 EXPECT_THAT_EXPECTED(
221 getOrParseLineTableFatalErrors(0),
223 "parsing line table prologue at offset 0x00000000: "
224 "unexpected end of data at offset 0x1 while reading [0x0, 0x4)"));
226 EXPECT_THAT_EXPECTED(
227 getOrParseLineTableFatalErrors(1),
229 "offset 0x00000001 is not a valid debug line section offset"));
232 #ifdef NO_SUPPORT_DEBUG_ADDR
233 TEST_P(DebugLineParameterisedFixture
, DISABLED_PrologueGetLength
) {
235 TEST_P(DebugLineParameterisedFixture
, PrologueGetLength
) {
237 if (!setupGenerator(Version
))
239 LineTable
<
= Gen
->addLineTable(Format
);
240 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
241 LT
.setPrologue(Prologue
);
244 // + 10 for sizes of DWARF-32 unit length, version, prologue length.
245 uint64_t ExpectedLength
= Prologue
.PrologueLength
+ 10;
247 // Add address and segment selector size fields.
249 if (Format
== DWARF64
)
250 // Unit length grows by 8, prologue length by 4.
251 ExpectedLength
+= 12;
253 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
254 nullptr, RecordRecoverable
);
255 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
256 EXPECT_EQ((*ExpectedLineTable
)->Prologue
.getLength(), ExpectedLength
);
259 #ifdef NO_SUPPORT_DEBUG_ADDR
260 TEST_P(DebugLineParameterisedFixture
, DISABLED_GetOrParseLineTableValidTable
) {
262 TEST_P(DebugLineParameterisedFixture
, GetOrParseLineTableValidTable
) {
264 if (!setupGenerator(Version
))
267 SCOPED_TRACE("Checking Version " + std::to_string(Version
) + ", Format " +
268 (Format
== DWARF64
? "DWARF64" : "DWARF32"));
270 LineTable
<
= Gen
->addLineTable(Format
);
271 LT
.addExtendedOpcode(9, DW_LNE_set_address
, {{0xadd4e55, LineTable::Quad
}});
272 LT
.addStandardOpcode(DW_LNS_copy
, {});
274 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
276 LineTable
<2
= Gen
->addLineTable(Format
);
277 LT2
.addExtendedOpcode(9, DW_LNE_set_address
, {{0x11223344, LineTable::Quad
}});
278 LT2
.addStandardOpcode(DW_LNS_copy
, {});
280 LT2
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
281 LT2
.addExtendedOpcode(9, DW_LNE_set_address
, {{0x55667788, LineTable::Quad
}});
282 LT2
.addStandardOpcode(DW_LNS_copy
, {});
284 LT2
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
288 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
289 nullptr, RecordRecoverable
);
290 ASSERT_TRUE(ExpectedLineTable
.operator bool());
291 EXPECT_FALSE(Recoverable
);
292 const DWARFDebugLine::LineTable
*Expected
= *ExpectedLineTable
;
293 checkDefaultPrologue(Version
, Format
, Expected
->Prologue
, 16);
294 EXPECT_EQ(Expected
->Sequences
.size(), 1u);
296 uint64_t SecondOffset
=
297 Expected
->Prologue
.sizeofTotalLength() + Expected
->Prologue
.TotalLength
;
298 Recoverable
= Error::success();
299 auto ExpectedLineTable2
= Line
.getOrParseLineTable(
300 LineData
, SecondOffset
, *Context
, nullptr, RecordRecoverable
);
301 ASSERT_TRUE(ExpectedLineTable2
.operator bool());
302 EXPECT_FALSE(Recoverable
);
303 const DWARFDebugLine::LineTable
*Expected2
= *ExpectedLineTable2
;
304 checkDefaultPrologue(Version
, Format
, Expected2
->Prologue
, 32);
305 EXPECT_EQ(Expected2
->Sequences
.size(), 2u);
307 EXPECT_NE(Expected
, Expected2
);
309 // Check that if the same offset is requested, the exact same pointer is
311 Recoverable
= Error::success();
312 auto ExpectedLineTable3
= Line
.getOrParseLineTable(
313 LineData
, 0, *Context
, nullptr, RecordRecoverable
);
314 ASSERT_TRUE(ExpectedLineTable3
.operator bool());
315 EXPECT_FALSE(Recoverable
);
316 EXPECT_EQ(Expected
, *ExpectedLineTable3
);
318 Recoverable
= Error::success();
319 auto ExpectedLineTable4
= Line
.getOrParseLineTable(
320 LineData
, SecondOffset
, *Context
, nullptr, RecordRecoverable
);
321 ASSERT_TRUE(ExpectedLineTable4
.operator bool());
322 EXPECT_FALSE(Recoverable
);
323 EXPECT_EQ(Expected2
, *ExpectedLineTable4
);
325 // TODO: Add tests that show that the body of the programs have been read
329 #ifdef NO_SUPPORT_DEBUG_ADDR
330 TEST_P(DebugLineParameterisedFixture
, DISABLED_ClearLineValidTable
) {
332 TEST_P(DebugLineParameterisedFixture
, ClearLineValidTable
) {
334 if (!setupGenerator(Version
))
337 SCOPED_TRACE("Checking Version " + std::to_string(Version
) + ", Format " +
338 (Format
== DWARF64
? "DWARF64" : "DWARF32"));
340 LineTable
<
= Gen
->addLineTable(Format
);
341 LT
.addExtendedOpcode(9, DW_LNE_set_address
, {{0xadd4e55, LineTable::Quad
}});
342 LT
.addStandardOpcode(DW_LNS_copy
, {});
344 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
346 LineTable
<2
= Gen
->addLineTable(Format
);
347 LT2
.addExtendedOpcode(9, DW_LNE_set_address
, {{0x11223344, LineTable::Quad
}});
348 LT2
.addStandardOpcode(DW_LNS_copy
, {});
350 LT2
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
351 LT2
.addExtendedOpcode(9, DW_LNE_set_address
, {{0x55667788, LineTable::Quad
}});
352 LT2
.addStandardOpcode(DW_LNS_copy
, {});
354 LT2
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
358 // Check that we have what we expect before calling clearLineTable().
359 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
360 nullptr, RecordRecoverable
);
361 ASSERT_TRUE((bool)ExpectedLineTable
);
362 EXPECT_FALSE(Recoverable
);
363 const DWARFDebugLine::LineTable
*Expected
= *ExpectedLineTable
;
364 checkDefaultPrologue(Version
, Format
, Expected
->Prologue
, 16);
365 EXPECT_EQ(Expected
->Sequences
.size(), 1u);
367 uint64_t SecondOffset
=
368 Expected
->Prologue
.sizeofTotalLength() + Expected
->Prologue
.TotalLength
;
369 Recoverable
= Error::success();
370 auto ExpectedLineTable2
= Line
.getOrParseLineTable(
371 LineData
, SecondOffset
, *Context
, nullptr, RecordRecoverable
);
372 ASSERT_TRUE((bool)ExpectedLineTable2
);
373 EXPECT_FALSE(Recoverable
);
374 const DWARFDebugLine::LineTable
*Expected2
= *ExpectedLineTable2
;
375 checkDefaultPrologue(Version
, Format
, Expected2
->Prologue
, 32);
376 EXPECT_EQ(Expected2
->Sequences
.size(), 2u);
378 // Check that we no longer get the line tables after clearLineTable().
379 Line
.clearLineTable(0);
380 Line
.clearLineTable(SecondOffset
);
381 EXPECT_EQ(Line
.getLineTable(0), nullptr);
382 EXPECT_EQ(Line
.getLineTable(SecondOffset
), nullptr);
384 // Check that if the same offset is requested, the contents match what we
386 Recoverable
= Error::success();
387 auto ExpectedLineTable3
= Line
.getOrParseLineTable(
388 LineData
, 0, *Context
, nullptr, RecordRecoverable
);
389 ASSERT_TRUE((bool)ExpectedLineTable3
);
390 EXPECT_FALSE(Recoverable
);
391 const DWARFDebugLine::LineTable
*Expected3
= *ExpectedLineTable3
;
392 checkDefaultPrologue(Version
, Format
, Expected3
->Prologue
, 16);
393 EXPECT_EQ(Expected3
->Sequences
.size(), 1u);
395 Recoverable
= Error::success();
396 auto ExpectedLineTable4
= Line
.getOrParseLineTable(
397 LineData
, SecondOffset
, *Context
, nullptr, RecordRecoverable
);
398 ASSERT_TRUE((bool)ExpectedLineTable4
);
399 EXPECT_FALSE(Recoverable
);
400 const DWARFDebugLine::LineTable
*Expected4
= *ExpectedLineTable4
;
401 checkDefaultPrologue(Version
, Format
, Expected4
->Prologue
, 32);
402 EXPECT_EQ(Expected4
->Sequences
.size(), 2u);
405 TEST_F(DebugLineBasicFixture
, ErrorForReservedLength
) {
406 if (!setupGenerator())
409 LineTable
<
= Gen
->addLineTable();
410 LT
.setCustomPrologue({{0xfffffff0, LineTable::Long
}});
414 EXPECT_THAT_EXPECTED(
415 getOrParseLineTableFatalErrors(),
417 "parsing line table prologue at offset 0x00000000: unsupported "
418 "reserved unit length of value 0xfffffff0"));
421 struct DebugLineUnsupportedVersionFixture
: public TestWithParam
<uint16_t>,
422 public CommonFixture
{
423 void SetUp() override
{ Version
= GetParam(); }
428 TEST_P(DebugLineUnsupportedVersionFixture
, ErrorForUnsupportedVersion
) {
429 if (!setupGenerator())
432 LineTable
<
= Gen
->addLineTable();
433 LT
.setCustomPrologue(
434 {{LineTable::Half
, LineTable::Long
}, {Version
, LineTable::Half
}});
438 EXPECT_THAT_EXPECTED(
439 getOrParseLineTableFatalErrors(),
440 FailedWithMessage("parsing line table prologue at offset 0x00000000: "
441 "unsupported version " +
442 std::to_string(Version
)));
445 INSTANTIATE_TEST_SUITE_P(UnsupportedVersionTestParams
,
446 DebugLineUnsupportedVersionFixture
,
447 Values(/*1 below min */ 1, /* 1 above max */ 6,
448 /* Maximum possible */ 0xffff));
450 #ifdef NO_SUPPORT_DEBUG_ADDR
451 TEST_F(DebugLineBasicFixture
, DISABLED_ErrorForInvalidV5IncludeDirTable
) {
453 TEST_F(DebugLineBasicFixture
, ErrorForInvalidV5IncludeDirTable
) {
455 if (!setupGenerator(5))
458 LineTable
<
= Gen
->addLineTable();
459 LT
.setCustomPrologue({
460 {19, LineTable::Long
}, // unit length
461 {5, LineTable::Half
}, // version
462 {8, LineTable::Byte
}, // addr size
463 {0, LineTable::Byte
}, // segment selector size
464 {11, LineTable::Long
}, // prologue length
465 {1, LineTable::Byte
}, // min instruction length
466 {1, LineTable::Byte
}, // max ops per instruction
467 {1, LineTable::Byte
}, // default is_stmt
468 {0, LineTable::Byte
}, // line base
469 {14, LineTable::Byte
}, // line range
470 {2, LineTable::Byte
}, // opcode base (small to reduce the amount of
472 {0, LineTable::Byte
}, // standard opcode lengths
473 {0, LineTable::Byte
}, // directory entry format count (should not be
475 {0, LineTable::ULEB
}, // directories count
476 {0, LineTable::Byte
}, // file name entry format count
477 {0, LineTable::ULEB
} // file name entry count
482 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
483 nullptr, RecordRecoverable
);
484 EXPECT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
487 std::move(Recoverable
),
489 "parsing line table prologue at 0x00000000 found an invalid "
490 "directory or file table description at 0x00000014",
491 "failed to parse entry content descriptions because no path was "
495 #ifdef NO_SUPPORT_DEBUG_ADDR
496 TEST_P(DebugLineParameterisedFixture
, DISABLED_ErrorForTooLargePrologueLength
) {
498 TEST_P(DebugLineParameterisedFixture
, ErrorForTooLargePrologueLength
) {
500 if (!setupGenerator(Version
))
503 SCOPED_TRACE("Checking Version " + std::to_string(Version
) + ", Format " +
504 (Format
== DWARF64
? "DWARF64" : "DWARF32"));
506 LineTable
<
= Gen
->addLineTable(Format
);
507 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
508 ++Prologue
.PrologueLength
;
509 LT
.setPrologue(Prologue
);
513 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
514 nullptr, RecordRecoverable
);
515 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
516 DWARFDebugLine::LineTable
Result(**ExpectedLineTable
);
517 // Undo the earlier modification so that it can be compared against a
518 // "default" prologue.
519 --Result
.Prologue
.PrologueLength
;
520 checkDefaultPrologue(Version
, Format
, Result
.Prologue
, 0);
522 uint64_t ExpectedEnd
=
523 Prologue
.TotalLength
+ 1 + Prologue
.sizeofTotalLength();
525 std::move(Recoverable
),
527 ("unknown data in line table prologue at offset 0x00000000: "
528 "parsing ended (at offset 0x000000" +
529 Twine::utohexstr(ExpectedEnd
- 1) +
530 ") before reaching the prologue end at offset 0x000000" +
531 Twine::utohexstr(ExpectedEnd
))
535 #ifdef NO_SUPPORT_DEBUG_ADDR
536 TEST_P(DebugLineParameterisedFixture
, DISABLED_ErrorForTooShortPrologueLength
) {
538 TEST_P(DebugLineParameterisedFixture
, ErrorForTooShortPrologueLength
) {
540 if (!setupGenerator(Version
))
543 SCOPED_TRACE("Checking Version " + std::to_string(Version
) + ", Format " +
544 (Format
== DWARF64
? "DWARF64" : "DWARF32"));
546 LineTable
<
= Gen
->addLineTable(Format
);
547 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
548 Prologue
.PrologueLength
-= 2;
549 LT
.setPrologue(Prologue
);
553 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
554 nullptr, RecordRecoverable
);
555 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
556 DWARFDebugLine::LineTable
Result(**ExpectedLineTable
);
558 // Parsing will stop before reading a complete file entry.
559 ASSERT_EQ(Result
.Prologue
.IncludeDirectories
.size(), 1u);
560 EXPECT_EQ(toStringRef(Result
.Prologue
.IncludeDirectories
[0]), "a dir");
561 EXPECT_EQ(Result
.Prologue
.FileNames
.size(), 0u);
563 // The exact place where the parsing will stop depends on the structure of the
564 // prologue and the last complete field we are able to read. Before V5 we stop
565 // before reading the file length. In V5, we stop before the filename.
566 uint64_t ExpectedEnd
= Prologue
.TotalLength
+ Prologue
.sizeofTotalLength() -
567 (Version
< 5 ? 2 : 8);
568 std::vector
<std::string
> Errs
;
570 (Twine("parsing line table prologue at 0x00000000 found an invalid "
571 "directory or file table description at 0x000000") +
572 Twine::utohexstr(ExpectedEnd
))
575 Errs
.emplace_back("file names table was not null terminated before the end "
579 "failed to parse file entry because extracting the form value failed");
581 EXPECT_THAT_ERROR(std::move(Recoverable
),
582 FailedWithMessageArray(testing::ElementsAreArray(Errs
)));
585 INSTANTIATE_TEST_SUITE_P(
586 LineTableTestParams
, DebugLineParameterisedFixture
,
587 Values(std::make_pair(
588 2, DWARF32
), // Test lower-bound of v2-3 fields and DWARF32.
589 std::make_pair(3, DWARF32
), // Test upper-bound of v2-3 fields.
590 std::make_pair(4, DWARF64
), // Test v4 fields and DWARF64.
591 std::make_pair(5, DWARF32
), std::make_pair(5, DWARF64
)));
593 TEST_F(DebugLineBasicFixture
, ErrorForExtendedOpcodeLengthSmallerThanExpected
) {
594 if (!setupGenerator())
597 LineTable
<
= Gen
->addLineTable();
599 // The Length should be 1 + sizeof(ULEB) for a set discriminator opcode.
600 // The operand will be read for both the discriminator opcode and then parsed
601 // again as DW_LNS_negate_stmt, to respect the claimed length.
602 LT
.addExtendedOpcode(1, DW_LNE_set_discriminator
,
603 {{DW_LNS_negate_stmt
, LineTable::ULEB
}});
605 LT
.addStandardOpcode(DW_LNS_const_add_pc
, {});
606 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
610 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
611 nullptr, RecordRecoverable
);
612 EXPECT_THAT_ERROR(std::move(Recoverable
),
613 FailedWithMessage("unexpected line op length at offset "
614 "0x00000031 expected 0x01 found 0x02"));
615 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
616 ASSERT_EQ((*ExpectedLineTable
)->Rows
.size(), 3u);
617 EXPECT_EQ((*ExpectedLineTable
)->Sequences
.size(), 1u);
618 EXPECT_EQ((*ExpectedLineTable
)->Rows
[1].IsStmt
, 0u);
619 EXPECT_EQ((*ExpectedLineTable
)->Rows
[1].Discriminator
, DW_LNS_negate_stmt
);
622 TEST_F(DebugLineBasicFixture
, ErrorForExtendedOpcodeLengthLargerThanExpected
) {
623 if (!setupGenerator())
626 LineTable
<
= Gen
->addLineTable();
628 LT
.addStandardOpcode(DW_LNS_const_add_pc
, {});
629 // The Length should be 1 for an end sequence opcode.
630 LT
.addExtendedOpcode(2, DW_LNE_end_sequence
, {});
631 // The negate statement opcode will be skipped.
632 LT
.addStandardOpcode(DW_LNS_negate_stmt
, {});
634 LT
.addStandardOpcode(DW_LNS_const_add_pc
, {});
635 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
639 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
640 nullptr, RecordRecoverable
);
641 EXPECT_THAT_ERROR(std::move(Recoverable
),
642 FailedWithMessage("unexpected line op length at offset "
643 "0x00000032 expected 0x02 found 0x01"));
644 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
645 ASSERT_EQ((*ExpectedLineTable
)->Rows
.size(), 4u);
646 EXPECT_EQ((*ExpectedLineTable
)->Sequences
.size(), 2u);
647 ASSERT_EQ((*ExpectedLineTable
)->Sequences
[1].FirstRowIndex
, 2u);
648 EXPECT_EQ((*ExpectedLineTable
)->Rows
[2].IsStmt
, 1u);
651 TEST_F(DebugLineBasicFixture
, ErrorForUnitLengthTooLarge
) {
652 if (!setupGenerator())
655 LineTable
&Padding
= Gen
->addLineTable();
656 // Add some padding to show that a non-zero offset is handled correctly.
657 Padding
.setCustomPrologue({{0, LineTable::Byte
}});
658 LineTable
<
= Gen
->addLineTable();
659 LT
.addStandardOpcode(DW_LNS_copy
, {});
660 LT
.addStandardOpcode(DW_LNS_const_add_pc
, {});
661 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
662 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
663 // Set the total length to 1 higher than the actual length.
664 ++Prologue
.TotalLength
;
665 LT
.setPrologue(Prologue
);
669 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 1, *Context
,
670 nullptr, RecordRecoverable
);
672 std::move(Recoverable
),
673 FailedWithMessage("line table program with offset 0x00000001 has length "
674 "0x00000034 but only 0x00000033 bytes are available"));
675 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
676 EXPECT_EQ((*ExpectedLineTable
)->Rows
.size(), 2u);
677 EXPECT_EQ((*ExpectedLineTable
)->Sequences
.size(), 1u);
680 TEST_F(DebugLineBasicFixture
, ErrorForMismatchedAddressSize
) {
681 if (!setupGenerator(4, 8))
684 LineTable
<
= Gen
->addLineTable();
685 // The line data extractor expects size 8 (Quad) addresses.
686 uint64_t Addr1
= 0x11223344;
687 LT
.addExtendedOpcode(5, DW_LNE_set_address
, {{Addr1
, LineTable::Long
}});
688 LT
.addStandardOpcode(DW_LNS_copy
, {});
689 // Show that the expected address size is unchanged, so later valid lines
690 // don't cause a problem.
691 uint64_t Addr2
= 0x1122334455667788;
692 LT
.addExtendedOpcode(9, DW_LNE_set_address
, {{Addr2
, LineTable::Quad
}});
693 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
697 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
698 nullptr, RecordRecoverable
);
699 EXPECT_THAT_ERROR(std::move(Recoverable
),
700 FailedWithMessage("mismatching address size at offset "
701 "0x00000030 expected 0x08 found 0x04"));
702 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
703 ASSERT_EQ((*ExpectedLineTable
)->Rows
.size(), 2u);
704 EXPECT_EQ((*ExpectedLineTable
)->Sequences
.size(), 1u);
705 EXPECT_EQ((*ExpectedLineTable
)->Rows
[0].Address
.Address
, Addr1
);
706 EXPECT_EQ((*ExpectedLineTable
)->Rows
[1].Address
.Address
, Addr2
);
709 TEST_F(DebugLineBasicFixture
,
710 ErrorForMismatchedAddressSizeUnsetInitialAddress
) {
711 if (!setupGenerator(4, 0))
714 LineTable
<
= Gen
->addLineTable();
715 uint64_t Addr1
= 0x11223344;
716 LT
.addExtendedOpcode(5, DW_LNE_set_address
, {{Addr1
, LineTable::Long
}});
717 LT
.addStandardOpcode(DW_LNS_copy
, {});
718 uint64_t Addr2
= 0x1122334455667788;
719 LT
.addExtendedOpcode(9, DW_LNE_set_address
, {{Addr2
, LineTable::Quad
}});
720 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
724 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
725 nullptr, RecordRecoverable
);
726 EXPECT_THAT_ERROR(std::move(Recoverable
),
727 FailedWithMessage("mismatching address size at offset "
728 "0x00000038 expected 0x04 found 0x08"));
729 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
730 ASSERT_EQ((*ExpectedLineTable
)->Rows
.size(), 2u);
731 EXPECT_EQ((*ExpectedLineTable
)->Sequences
.size(), 1u);
732 EXPECT_EQ((*ExpectedLineTable
)->Rows
[0].Address
.Address
, Addr1
);
733 EXPECT_EQ((*ExpectedLineTable
)->Rows
[1].Address
.Address
, Addr2
);
736 TEST_F(DebugLineBasicFixture
,
737 ErrorForUnsupportedAddressSizeInSetAddressLength
) {
738 // Use DWARF v4, and 0 for data extractor address size so that the address
739 // size is derived from the opcode length.
740 if (!setupGenerator(4, 0))
743 LineTable
<
= Gen
->addLineTable();
744 // 4 == length of the extended opcode, i.e. 1 for the opcode itself and 3 for
745 // the Half (2) + Byte (1) operand, representing the unsupported address size.
746 LT
.addExtendedOpcode(4, DW_LNE_set_address
,
747 {{0x1234, LineTable::Half
}, {0x56, LineTable::Byte
}});
748 LT
.addStandardOpcode(DW_LNS_copy
, {});
749 // Special opcode to ensure the address has changed between the first and last
750 // row in the sequence. Without this, the sequence will not be recorded.
752 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
756 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
757 nullptr, RecordRecoverable
);
759 std::move(Recoverable
),
760 FailedWithMessage("address size 0x03 of DW_LNE_set_address opcode at "
761 "offset 0x00000030 is unsupported"));
762 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
763 ASSERT_EQ((*ExpectedLineTable
)->Rows
.size(), 3u);
764 EXPECT_EQ((*ExpectedLineTable
)->Sequences
.size(), 1u);
765 // Show that the set address opcode is ignored in this case.
766 EXPECT_EQ((*ExpectedLineTable
)->Rows
[0].Address
.Address
, 0u);
769 TEST_F(DebugLineBasicFixture
, ErrorForAddressSizeGreaterThanByteSize
) {
770 // Use DWARF v4, and 0 for data extractor address size so that the address
771 // size is derived from the opcode length.
772 if (!setupGenerator(4, 0))
775 LineTable
<
= Gen
->addLineTable();
776 // Specifically use an operand size that has a trailing byte of a supported
777 // size (8), so that any potential truncation would result in a valid size.
778 std::vector
<LineTable::ValueAndLength
> Operands(0x108);
779 LT
.addExtendedOpcode(Operands
.size() + 1, DW_LNE_set_address
, Operands
);
780 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
784 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
785 nullptr, RecordRecoverable
);
787 std::move(Recoverable
),
788 FailedWithMessage("address size 0x108 of DW_LNE_set_address opcode at "
789 "offset 0x00000031 is unsupported"));
790 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
793 #ifdef NO_SUPPORT_DEBUG_ADDR
794 TEST_F(DebugLineBasicFixture
,
795 DISABLED_ErrorForUnsupportedAddressSizeDefinedInHeader
) {
797 TEST_F(DebugLineBasicFixture
, ErrorForUnsupportedAddressSizeDefinedInHeader
) {
799 // Use 0 for data extractor address size so that it does not clash with the
800 // header address size.
801 if (!setupGenerator(5, 0))
804 LineTable
<
= Gen
->addLineTable();
805 // AddressSize + 1 == length of the extended opcode, i.e. 1 for the opcode
806 // itself and 9 for the Quad (8) + Byte (1) operand representing the
807 // unsupported address size.
808 uint8_t AddressSize
= 9;
809 LT
.addExtendedOpcode(AddressSize
+ 1, DW_LNE_set_address
,
810 {{0x12345678, LineTable::Quad
}, {0, LineTable::Byte
}});
811 LT
.addStandardOpcode(DW_LNS_copy
, {});
812 // Special opcode to ensure the address has changed between the first and last
813 // row in the sequence. Without this, the sequence will not be recorded.
815 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
816 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
817 Prologue
.FormParams
.AddrSize
= AddressSize
;
818 LT
.setPrologue(Prologue
);
822 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
823 nullptr, RecordRecoverable
);
825 std::move(Recoverable
),
826 FailedWithMessage("parsing line table prologue at offset 0x00000000: "
827 "invalid address size 9",
828 "address size 0x09 of DW_LNE_set_address opcode at "
829 "offset 0x00000038 is unsupported"));
830 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
831 ASSERT_EQ((*ExpectedLineTable
)->Rows
.size(), 3u);
832 EXPECT_EQ((*ExpectedLineTable
)->Sequences
.size(), 1u);
833 // Show that the set address opcode is ignored in this case.
834 EXPECT_EQ((*ExpectedLineTable
)->Rows
[0].Address
.Address
, 0u);
837 TEST_F(DebugLineBasicFixture
, CallbackUsedForUnterminatedSequence
) {
838 if (!setupGenerator())
841 LineTable
<
= Gen
->addLineTable();
842 LT
.addExtendedOpcode(9, DW_LNE_set_address
,
843 {{0x1122334455667788, LineTable::Quad
}});
844 LT
.addStandardOpcode(DW_LNS_copy
, {});
846 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
847 LT
.addExtendedOpcode(9, DW_LNE_set_address
,
848 {{0x99aabbccddeeff00, LineTable::Quad
}});
849 LT
.addStandardOpcode(DW_LNS_copy
, {});
855 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
856 nullptr, RecordRecoverable
);
857 EXPECT_THAT_ERROR(std::move(Recoverable
),
858 FailedWithMessage("last sequence in debug line table at "
859 "offset 0x00000000 is not terminated"));
860 ASSERT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
861 EXPECT_EQ((*ExpectedLineTable
)->Rows
.size(), 6u);
862 // The unterminated sequence is not added to the sequence list.
863 EXPECT_EQ((*ExpectedLineTable
)->Sequences
.size(), 1u);
866 struct AdjustAddressFixtureBase
: public CommonFixture
{
867 virtual ~AdjustAddressFixtureBase() {}
869 // Create and update the prologue as specified by the subclass, then return
870 // the length of the table.
871 virtual uint64_t editPrologue(LineTable
<
) = 0;
873 virtual uint64_t getAdjustedAddr(uint64_t Base
, uint64_t ConstIncrs
,
874 uint64_t SpecialIncrs
,
875 uint64_t AdvanceIncrs
) {
876 return Base
+ ConstIncrs
+ SpecialIncrs
+ AdvanceIncrs
;
879 virtual uint64_t getAdjustedLine(uint64_t Base
, uint64_t Incr
) {
883 uint64_t setupNoProblemTable() {
884 LineTable
&NoProblem
= Gen
->addLineTable();
885 NoProblem
.addExtendedOpcode(9, DW_LNE_set_address
,
886 {{0xabcd, LineTable::Quad
}});
887 NoProblem
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
888 return editPrologue(NoProblem
);
891 uint64_t setupConstAddPcFirstTable() {
892 LineTable
&ConstAddPCFirst
= Gen
->addLineTable();
893 ConstAddPCFirst
.addExtendedOpcode(9, DW_LNE_set_address
,
894 {{ConstAddPCAddr
, LineTable::Quad
}});
895 ConstAddPCFirst
.addStandardOpcode(DW_LNS_const_add_pc
, {});
896 ConstAddPCFirst
.addStandardOpcode(DW_LNS_const_add_pc
, {});
897 ConstAddPCFirst
.addStandardOpcode(DW_LNS_advance_pc
,
898 {{0x10, LineTable::ULEB
}});
899 ConstAddPCFirst
.addByte(0x21); // Special opcode, +1 op, +1 line.
900 ConstAddPCFirst
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
901 return editPrologue(ConstAddPCFirst
);
904 uint64_t setupSpecialFirstTable() {
905 LineTable
&SpecialFirst
= Gen
->addLineTable();
906 SpecialFirst
.addExtendedOpcode(9, DW_LNE_set_address
,
907 {{SpecialAddr
, LineTable::Quad
}});
908 SpecialFirst
.addByte(0x22); // Special opcode, +1 op, +2 line.
909 SpecialFirst
.addStandardOpcode(DW_LNS_const_add_pc
, {});
910 SpecialFirst
.addStandardOpcode(DW_LNS_advance_pc
,
911 {{0x20, LineTable::ULEB
}});
912 SpecialFirst
.addByte(0x23); // Special opcode, +1 op, +3 line.
913 SpecialFirst
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
914 return editPrologue(SpecialFirst
);
917 uint64_t setupAdvancePcFirstTable() {
918 LineTable
&AdvancePCFirst
= Gen
->addLineTable();
919 AdvancePCFirst
.addExtendedOpcode(9, DW_LNE_set_address
,
920 {{AdvancePCAddr
, LineTable::Quad
}});
921 AdvancePCFirst
.addStandardOpcode(DW_LNS_advance_pc
,
922 {{0x30, LineTable::ULEB
}});
923 AdvancePCFirst
.addStandardOpcode(DW_LNS_const_add_pc
, {});
924 AdvancePCFirst
.addStandardOpcode(DW_LNS_advance_pc
,
925 {{0x40, LineTable::ULEB
}});
926 AdvancePCFirst
.addByte(0x24); // Special opcode, +1 op, +4 line.
927 AdvancePCFirst
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
928 return editPrologue(AdvancePCFirst
);
931 void setupTables(bool AddAdvancePCFirstTable
) {
932 LineTable
&Padding
= Gen
->addLineTable();
933 Padding
.setCustomPrologue({{0, LineTable::Byte
}});
936 // Show that no warning is generated for the case where no
937 // DW_LNS_const_add_pc or special opcode is used.
938 ConstAddPCOffset
= setupNoProblemTable() + NoProblemOffset
;
940 // Show that the warning is emitted for the first DW_LNS_const_add_pc opcode
941 // and then not again.
942 SpecialOffset
= setupConstAddPcFirstTable() + ConstAddPCOffset
;
944 // Show that the warning is emitted for the first special opcode and then
946 AdvancePCOffset
= setupSpecialFirstTable() + SpecialOffset
;
948 // Show that the warning is emitted for the first DW_LNS_advance_pc opcode
949 // (if requested) and then not again.
950 if (AddAdvancePCFirstTable
)
951 setupAdvancePcFirstTable();
954 Expected
<const DWARFDebugLine::LineTable
*>
955 checkTable(uint64_t Offset
, StringRef OpcodeType
, const Twine
&MsgSuffix
) {
956 auto ExpectedTable
= Line
.getOrParseLineTable(LineData
, Offset
, *Context
,
957 nullptr, RecordRecoverable
);
958 EXPECT_THAT_ERROR(std::move(Unrecoverable
), Succeeded());
959 if (!IsErrorExpected
) {
960 EXPECT_THAT_ERROR(std::move(Recoverable
), Succeeded());
963 return ExpectedTable
;
964 uint64_t ExpectedOffset
= Offset
+
965 (*ExpectedTable
)->Prologue
.getLength() +
966 11; // 11 == size of DW_LNE_set_address.
967 std::string OffsetHex
= Twine::utohexstr(Offset
).str();
968 std::string OffsetZeroes
= std::string(8 - OffsetHex
.size(), '0');
969 std::string ExpectedHex
= Twine::utohexstr(ExpectedOffset
).str();
970 std::string ExpectedZeroes
= std::string(8 - ExpectedHex
.size(), '0');
972 std::move(Recoverable
),
973 FailedWithMessage(("line table program at offset 0x" + OffsetZeroes
+
974 OffsetHex
+ " contains a " + OpcodeType
+
975 " opcode at offset 0x" + ExpectedZeroes
+
976 ExpectedHex
+ ", " + MsgSuffix
)
979 return ExpectedTable
;
982 void runTest(bool CheckAdvancePC
, Twine MsgSuffix
) {
983 if (!setupGenerator(Version
))
986 setupTables(/*AddAdvancePCFirstTable=*/CheckAdvancePC
);
990 auto ExpectedNoProblem
= Line
.getOrParseLineTable(
991 LineData
, NoProblemOffset
, *Context
, nullptr, RecordRecoverable
);
992 EXPECT_THAT_ERROR(std::move(Recoverable
), Succeeded());
993 EXPECT_THAT_ERROR(std::move(Unrecoverable
), Succeeded());
994 ASSERT_THAT_EXPECTED(ExpectedNoProblem
, Succeeded());
996 auto ExpectedConstAddPC
=
997 checkTable(ConstAddPCOffset
, "DW_LNS_const_add_pc", MsgSuffix
);
998 ASSERT_THAT_EXPECTED(ExpectedConstAddPC
, Succeeded());
999 ASSERT_EQ((*ExpectedConstAddPC
)->Rows
.size(), 2u);
1000 EXPECT_EQ((*ExpectedConstAddPC
)->Rows
[0].Address
.Address
,
1001 getAdjustedAddr(ConstAddPCAddr
, ConstIncr
* 2, 0x1, 0x10));
1002 EXPECT_EQ((*ExpectedConstAddPC
)->Rows
[0].Line
, getAdjustedLine(1, 1));
1003 EXPECT_THAT_ERROR(std::move(Unrecoverable
), Succeeded());
1005 auto ExpectedSpecial
= checkTable(SpecialOffset
, "special", MsgSuffix
);
1006 ASSERT_THAT_EXPECTED(ExpectedSpecial
, Succeeded());
1007 ASSERT_EQ((*ExpectedSpecial
)->Rows
.size(), 3u);
1008 EXPECT_EQ((*ExpectedSpecial
)->Rows
[0].Address
.Address
,
1009 getAdjustedAddr(SpecialAddr
, 0, 1, 0));
1010 EXPECT_EQ((*ExpectedSpecial
)->Rows
[0].Line
, getAdjustedLine(1, 2));
1011 EXPECT_EQ((*ExpectedSpecial
)->Rows
[1].Address
.Address
,
1012 getAdjustedAddr(SpecialAddr
, ConstIncr
, 0x2, 0x20));
1013 EXPECT_EQ((*ExpectedSpecial
)->Rows
[1].Line
, getAdjustedLine(1, 5));
1014 EXPECT_THAT_ERROR(std::move(Unrecoverable
), Succeeded());
1016 if (!CheckAdvancePC
)
1019 auto ExpectedAdvancePC
=
1020 checkTable(AdvancePCOffset
, "DW_LNS_advance_pc", MsgSuffix
);
1021 ASSERT_THAT_EXPECTED(ExpectedAdvancePC
, Succeeded());
1022 ASSERT_EQ((*ExpectedAdvancePC
)->Rows
.size(), 2u);
1023 EXPECT_EQ((*ExpectedAdvancePC
)->Rows
[0].Address
.Address
,
1024 getAdjustedAddr(AdvancePCAddr
, ConstIncr
, 0x1, 0x70));
1025 EXPECT_EQ((*ExpectedAdvancePC
)->Rows
[0].Line
, getAdjustedLine(1, 4));
1028 uint64_t ConstIncr
= 0x11;
1029 uint64_t ConstAddPCAddr
= 0x1234;
1030 uint64_t SpecialAddr
= 0x5678;
1031 uint64_t AdvancePCAddr
= 0xabcd;
1032 uint64_t NoProblemOffset
;
1033 uint64_t ConstAddPCOffset
;
1034 uint64_t SpecialOffset
;
1035 uint64_t AdvancePCOffset
;
1037 uint16_t Version
= 4;
1038 bool IsErrorExpected
;
1041 struct OpIndexFixture
: Test
, CommonFixture
{
1042 void createPrologue(LineTable
<
, uint8_t MaxOpsPerInst
,
1043 uint8_t MinInstLength
) {
1044 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
1045 Prologue
.MaxOpsPerInst
= MaxOpsPerInst
;
1046 Prologue
.MinInstLength
= MinInstLength
;
1047 LT
.setPrologue(Prologue
);
1051 TEST_F(OpIndexFixture
, OpIndexAdvance
) {
1052 if (!setupGenerator(4, 4))
1055 uint8_t MaxOpsPerInst
= 13;
1056 uint8_t MinInstLength
= 4;
1058 LineTable
<
= Gen
->addLineTable();
1060 // Row 0-2: Different locations for one bundle set up using special opcodes.
1061 LT
.addExtendedOpcode(5, DW_LNE_set_address
, {{0x20, LineTable::Long
}});
1062 LT
.addByte(0x13); // Special opcode, +1 line.
1063 LT
.addByte(0x23); // Special opcode, +3 line, +1 op-index.
1064 LT
.addByte(0x3a); // Special opcode, -2 line, +3 op-index.
1066 // Row 3: New bundle, set up using DW_LNS_advance pc.
1067 // Operation advance 0x84, which gives +40 addr, +2 op-index
1068 LT
.addStandardOpcode(DW_LNS_advance_line
, {{100, LineTable::SLEB
}});
1069 LT
.addStandardOpcode(DW_LNS_advance_pc
, {{0x84, LineTable::ULEB
}});
1070 LT
.addStandardOpcode(DW_LNS_copy
, {}); // Create new row.
1072 // Row 4: New bundle, set up using a single special opcode.
1073 LT
.addByte(0x71); // Special opcode, +4 addr, -3 line, -6 op-index.
1075 // Row 5: New bundle, set up using using DW_LNS_const_add_pc.
1076 // Corresponds to advancing address and op-index using special opcode 255,
1077 // which gives +4 addr, +4 op-index.
1078 LT
.addStandardOpcode(DW_LNS_advance_line
, {{10, LineTable::SLEB
}});
1079 LT
.addStandardOpcode(DW_LNS_const_add_pc
, {});
1080 LT
.addStandardOpcode(DW_LNS_copy
, {}); // Create new row.
1082 // Row 6: End sequence to have the input well-formed.
1083 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
1085 createPrologue(LT
, MaxOpsPerInst
, MinInstLength
);
1089 auto VerifyRow
= [](const DWARFDebugLine::Row
&Row
, uint64_t Address
,
1090 uint8_t OpIndex
, uint32_t Line
) {
1091 EXPECT_EQ(Row
.Address
.Address
, Address
);
1092 EXPECT_EQ(Row
.OpIndex
, OpIndex
);
1093 EXPECT_EQ(Row
.Line
, Line
);
1096 auto Table
= Line
.getOrParseLineTable(LineData
, 0, *Context
, nullptr,
1099 std::move(Recoverable
),
1100 FailedWithMessage("line table program at offset 0x00000000 contains a "
1101 "special opcode at offset 0x00000035, but the prologue "
1102 "maximum_operations_per_instruction value is 13, which "
1103 "is experimentally supported, so line number "
1104 "information may be incorrect"));
1105 EXPECT_THAT_ERROR(std::move(Unrecoverable
), Succeeded());
1106 ASSERT_THAT_EXPECTED(Table
, Succeeded());
1108 ASSERT_EQ((*Table
)->Rows
.size(), 7u);
1110 VerifyRow((*Table
)->Rows
[0], 0x20, 0, 2);
1111 VerifyRow((*Table
)->Rows
[1], 0x20, 1, 5);
1112 VerifyRow((*Table
)->Rows
[2], 0x20, 4, 3);
1113 VerifyRow((*Table
)->Rows
[3], 0x48, 6, 103);
1114 VerifyRow((*Table
)->Rows
[4], 0x4c, 0, 100);
1115 VerifyRow((*Table
)->Rows
[5], 0x50, 4, 110);
1118 TEST_F(OpIndexFixture
, OpIndexReset
) {
1119 if (!setupGenerator(4, 4))
1122 uint8_t MaxOpsPerInst
= 13;
1123 uint8_t MinInstLength
= 4;
1125 LineTable
<
= Gen
->addLineTable();
1127 // Row 0: Just set op-index to some value > 0.
1128 LT
.addExtendedOpcode(5, DW_LNE_set_address
, {{0, LineTable::Long
}});
1129 LT
.addByte(0x20); // Special opcode, +1 op-index
1131 // Row 1: DW_LNE_fixed_advance_pc should set op-index to 0.
1132 LT
.addStandardOpcode(DW_LNS_fixed_advance_pc
, {{10, LineTable::Half
}});
1133 LT
.addStandardOpcode(DW_LNS_copy
, {}); // Create new row.
1135 // Row 2: Just set op-index to some value > 0.
1136 LT
.addByte(0x66); // Special opcode, +6 op-index
1138 // Row 3: DW_LNE_set_address should set op-index to 0.
1139 LT
.addExtendedOpcode(5, DW_LNE_set_address
, {{20, LineTable::Long
}});
1140 LT
.addStandardOpcode(DW_LNS_copy
, {}); // Create new row.
1142 // Row 4: Just set op-index to some value > 0.
1143 LT
.addByte(0xba); // Special opcode, +12 op-index
1145 // Row 5: End sequence (op-index unchanged for this row)...
1146 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
1148 // Row 6: ... but shall be reset after the DW_LNE_end_sequence row.
1149 LT
.addStandardOpcode(DW_LNS_copy
, {}); // Create new row.
1151 // Row 7: End sequence to have the input well-formed.
1152 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
1154 createPrologue(LT
, MaxOpsPerInst
, MinInstLength
);
1158 auto Table
= Line
.getOrParseLineTable(LineData
, 0, *Context
, nullptr,
1161 std::move(Recoverable
),
1162 FailedWithMessage("line table program at offset 0x00000000 contains a "
1163 "special opcode at offset 0x00000035, but the prologue "
1164 "maximum_operations_per_instruction value is 13, which "
1165 "is experimentally supported, so line number "
1166 "information may be incorrect"));
1167 EXPECT_THAT_ERROR(std::move(Unrecoverable
), Succeeded());
1168 ASSERT_THAT_EXPECTED(Table
, Succeeded());
1170 ASSERT_EQ((*Table
)->Rows
.size(), 8u);
1171 EXPECT_EQ((*Table
)->Rows
[0].OpIndex
, 1u);
1172 EXPECT_EQ((*Table
)->Rows
[1].OpIndex
, 0u); // DW_LNS_fixed_advance_pc.
1173 EXPECT_EQ((*Table
)->Rows
[2].OpIndex
, 6u);
1174 EXPECT_EQ((*Table
)->Rows
[3].OpIndex
, 0u); // DW_LNE_set_address.
1175 EXPECT_EQ((*Table
)->Rows
[4].OpIndex
, 12u);
1176 EXPECT_EQ((*Table
)->Rows
[5].OpIndex
, 12u);
1177 EXPECT_EQ((*Table
)->Rows
[6].OpIndex
, 0u); // row after DW_LNE_end_sequence.
1178 EXPECT_EQ((*Table
)->Rows
[7].OpIndex
, 0u);
1181 TEST_F(OpIndexFixture
, MaxOpsZeroDwarf3
) {
1182 if (!setupGenerator(3, 4))
1185 LineTable
<
= Gen
->addLineTable();
1186 LT
.addStandardOpcode(DW_LNS_const_add_pc
, {}); // Just some opcode to advance.
1187 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {}); //
1188 createPrologue(LT
, /*MaxOpsPerInst=*/0, /*MinInstLength=*/1);
1191 auto Table
= Line
.getOrParseLineTable(LineData
, 0, *Context
, nullptr,
1193 EXPECT_THAT_ERROR(std::move(Recoverable
), Succeeded());
1194 EXPECT_THAT_ERROR(std::move(Unrecoverable
), Succeeded());
1195 ASSERT_THAT_EXPECTED(Table
, Succeeded());
1198 TEST_F(OpIndexFixture
, MaxOpsZeroDwarf4
) {
1199 if (!setupGenerator(4, 4))
1202 LineTable
<
= Gen
->addLineTable();
1203 LT
.addStandardOpcode(DW_LNS_const_add_pc
, {}); // Just some opcode to advance.
1204 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {}); //
1205 createPrologue(LT
, /*MaxOpsPerInst=*/0, /*MinInstLength=*/1);
1208 auto Table
= Line
.getOrParseLineTable(LineData
, 0, *Context
, nullptr,
1211 std::move(Recoverable
),
1213 "line table program at offset 0x00000000 contains a "
1214 "DW_LNS_const_add_pc opcode at offset 0x0000002e, but "
1215 "the prologue maximum_operations_per_instruction value "
1216 "is 0, which is invalid. Assuming a value of 1 instead"));
1217 EXPECT_THAT_ERROR(std::move(Unrecoverable
), Succeeded());
1218 ASSERT_THAT_EXPECTED(Table
, Succeeded());
1221 struct LineRangeFixture
: TestWithParam
<std::tuple
<uint8_t, bool>>,
1222 AdjustAddressFixtureBase
{
1223 void SetUp() override
{ std::tie(LineRange
, IsErrorExpected
) = GetParam(); }
1225 uint64_t editPrologue(LineTable
<
) override
{
1226 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
1227 Prologue
.LineRange
= LineRange
;
1228 LT
.setPrologue(Prologue
);
1229 return Prologue
.TotalLength
+ Prologue
.sizeofTotalLength();
1232 uint64_t getAdjustedAddr(uint64_t Base
, uint64_t ConstIncr
,
1233 uint64_t SpecialIncr
,
1234 uint64_t AdvanceIncr
) override
{
1236 return Base
+ AdvanceIncr
;
1237 return AdjustAddressFixtureBase::getAdjustedAddr(Base
, ConstIncr
,
1238 SpecialIncr
, AdvanceIncr
);
1241 uint64_t getAdjustedLine(uint64_t Base
, uint64_t Incr
) override
{
1242 return LineRange
!= 0
1243 ? AdjustAddressFixtureBase::getAdjustedLine(Base
, Incr
)
1250 TEST_P(LineRangeFixture
, LineRangeProblemsReportedCorrectly
) {
1251 runTest(/*CheckAdvancePC=*/false,
1252 "but the prologue line_range value is 0. The address and line will "
1256 INSTANTIATE_TEST_SUITE_P(
1257 LineRangeParams
, LineRangeFixture
,
1258 Values(std::make_tuple(0, true), // Test zero value (error).
1259 std::make_tuple(14, false))); // Test non-zero value (no error).
1261 struct BadMinInstLenFixture
: TestWithParam
<std::tuple
<uint8_t, bool>>,
1262 AdjustAddressFixtureBase
{
1263 void SetUp() override
{
1264 std::tie(MinInstLength
, IsErrorExpected
) = GetParam();
1267 uint64_t editPrologue(LineTable
<
) override
{
1268 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
1269 Prologue
.MinInstLength
= MinInstLength
;
1270 LT
.setPrologue(Prologue
);
1271 return Prologue
.TotalLength
+ Prologue
.sizeofTotalLength();
1274 uint64_t getAdjustedAddr(uint64_t Base
, uint64_t ConstIncr
,
1275 uint64_t SpecialIncr
,
1276 uint64_t AdvanceIncr
) override
{
1277 return MinInstLength
!= 0 ? AdjustAddressFixtureBase::getAdjustedAddr(
1278 Base
, ConstIncr
, SpecialIncr
, AdvanceIncr
)
1282 uint8_t MinInstLength
;
1285 TEST_P(BadMinInstLenFixture
, MinInstLengthProblemsReportedCorrectly
) {
1286 runTest(/*CheckAdvancePC=*/true,
1287 "but the prologue minimum_instruction_length value is 0, which "
1288 "prevents any address advancing");
1291 INSTANTIATE_TEST_SUITE_P(
1292 BadMinInstLenParams
, BadMinInstLenFixture
,
1293 Values(std::make_tuple(0, true), // Test zero value (error).
1294 std::make_tuple(1, false))); // Test non-zero value (no error).
1296 TEST_F(DebugLineBasicFixture
, ParserParsesCorrectly
) {
1297 if (!setupGenerator())
1300 DWARFDebugLine::SectionParser Parser
= setupParser();
1302 EXPECT_EQ(Parser
.getOffset(), 0u);
1303 ASSERT_FALSE(Parser
.done());
1305 DWARFDebugLine::LineTable Parsed
=
1306 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
);
1307 checkDefaultPrologue(4, DWARF32
, Parsed
.Prologue
, 16);
1308 EXPECT_EQ(Parsed
.Sequences
.size(), 1u);
1309 EXPECT_EQ(Parser
.getOffset(), 62u);
1310 ASSERT_FALSE(Parser
.done());
1312 DWARFDebugLine::LineTable Parsed2
=
1313 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
);
1314 checkDefaultPrologue(4, DWARF64
, Parsed2
.Prologue
, 16);
1315 EXPECT_EQ(Parsed2
.Sequences
.size(), 1u);
1316 EXPECT_EQ(Parser
.getOffset(), 136u);
1317 EXPECT_TRUE(Parser
.done());
1319 EXPECT_FALSE(Recoverable
);
1320 EXPECT_FALSE(Unrecoverable
);
1323 TEST_F(DebugLineBasicFixture
, ParserSkipsCorrectly
) {
1324 if (!setupGenerator())
1327 DWARFDebugLine::SectionParser Parser
= setupParser();
1329 EXPECT_EQ(Parser
.getOffset(), 0u);
1330 ASSERT_FALSE(Parser
.done());
1332 Parser
.skip(RecordRecoverable
, RecordUnrecoverable
);
1333 EXPECT_EQ(Parser
.getOffset(), 62u);
1334 ASSERT_FALSE(Parser
.done());
1336 Parser
.skip(RecordRecoverable
, RecordUnrecoverable
);
1337 EXPECT_EQ(Parser
.getOffset(), 136u);
1338 EXPECT_TRUE(Parser
.done());
1340 EXPECT_FALSE(Recoverable
);
1341 EXPECT_FALSE(Unrecoverable
);
1344 TEST_F(DebugLineBasicFixture
, ParserAlwaysDoneForEmptySection
) {
1345 if (!setupGenerator())
1349 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1351 EXPECT_TRUE(Parser
.done());
1354 TEST_F(DebugLineBasicFixture
, ParserMarkedAsDoneForBadLengthWhenParsing
) {
1355 if (!setupGenerator())
1358 LineTable
<
= Gen
->addLineTable();
1359 LT
.setCustomPrologue({{0xfffffff0, LineTable::Long
}});
1360 Gen
->addLineTable();
1363 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1364 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
);
1366 EXPECT_EQ(Parser
.getOffset(), 0u);
1367 EXPECT_TRUE(Parser
.done());
1368 EXPECT_FALSE(Recoverable
);
1371 std::move(Unrecoverable
),
1373 "parsing line table prologue at offset 0x00000000: unsupported "
1374 "reserved unit length of value 0xfffffff0"));
1377 TEST_F(DebugLineBasicFixture
, ParserMarkedAsDoneForBadLengthWhenSkipping
) {
1378 if (!setupGenerator())
1381 LineTable
<
= Gen
->addLineTable();
1382 LT
.setCustomPrologue({{0xfffffff0, LineTable::Long
}});
1383 Gen
->addLineTable();
1386 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1387 Parser
.skip(RecordRecoverable
, RecordUnrecoverable
);
1389 EXPECT_EQ(Parser
.getOffset(), 0u);
1390 EXPECT_TRUE(Parser
.done());
1391 EXPECT_FALSE(Recoverable
);
1394 std::move(Unrecoverable
),
1396 "parsing line table prologue at offset 0x00000000: unsupported "
1397 "reserved unit length of value 0xfffffff0"));
1400 TEST_F(DebugLineBasicFixture
, ParserReportsFirstErrorInEachTableWhenParsing
) {
1401 if (!setupGenerator())
1404 LineTable
<
= Gen
->addLineTable(DWARF32
);
1405 LT
.setCustomPrologue({{2, LineTable::Long
}, {0, LineTable::Half
}});
1406 LineTable
<2
= Gen
->addLineTable(DWARF32
);
1407 LT2
.setCustomPrologue({{2, LineTable::Long
}, {1, LineTable::Half
}});
1410 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1411 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
);
1412 ASSERT_FALSE(Parser
.done());
1413 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
);
1415 EXPECT_TRUE(Parser
.done());
1416 EXPECT_THAT_ERROR(std::move(Recoverable
), Succeeded());
1419 std::move(Unrecoverable
),
1420 FailedWithMessage("parsing line table prologue at offset 0x00000000: "
1421 "unsupported version 0",
1422 "parsing line table prologue at offset 0x00000006: "
1423 "unsupported version 1"));
1426 TEST_F(DebugLineBasicFixture
, ParserReportsNonPrologueProblemsWhenParsing
) {
1427 if (!setupGenerator())
1430 LineTable
<
= Gen
->addLineTable(DWARF32
);
1431 LT
.addExtendedOpcode(0x42, DW_LNE_end_sequence
, {});
1432 LineTable
<2
= Gen
->addLineTable(DWARF32
);
1433 LT2
.addExtendedOpcode(9, DW_LNE_set_address
,
1434 {{0x1234567890abcdef, LineTable::Quad
}});
1435 LT2
.addStandardOpcode(DW_LNS_copy
, {});
1439 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1440 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
);
1441 EXPECT_FALSE(Unrecoverable
);
1442 ASSERT_FALSE(Parser
.done());
1443 EXPECT_THAT_ERROR(std::move(Recoverable
),
1444 FailedWithMessage("unexpected line op length at offset "
1445 "0x00000030 expected 0x42 found 0x01"));
1447 // Reset the error state so that it does not confuse the next set of checks.
1448 Unrecoverable
= Error::success();
1449 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
);
1451 EXPECT_TRUE(Parser
.done());
1452 EXPECT_THAT_ERROR(std::move(Recoverable
),
1453 FailedWithMessage("last sequence in debug line table at "
1454 "offset 0x00000031 is not terminated"));
1455 EXPECT_FALSE(Unrecoverable
);
1458 TEST_F(DebugLineBasicFixture
,
1459 ParserReportsPrologueErrorsInEachTableWhenSkipping
) {
1460 if (!setupGenerator())
1463 LineTable
<
= Gen
->addLineTable(DWARF32
);
1464 LT
.setCustomPrologue({{2, LineTable::Long
}, {0, LineTable::Half
}});
1465 LineTable
<2
= Gen
->addLineTable(DWARF32
);
1466 LT2
.setCustomPrologue({{2, LineTable::Long
}, {1, LineTable::Half
}});
1469 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1470 Parser
.skip(RecordRecoverable
, RecordUnrecoverable
);
1471 ASSERT_FALSE(Parser
.done());
1472 Parser
.skip(RecordRecoverable
, RecordUnrecoverable
);
1474 EXPECT_TRUE(Parser
.done());
1475 EXPECT_FALSE(Recoverable
);
1478 std::move(Unrecoverable
),
1479 FailedWithMessage("parsing line table prologue at offset 0x00000000: "
1480 "unsupported version 0",
1481 "parsing line table prologue at offset 0x00000006: "
1482 "unsupported version 1"));
1485 TEST_F(DebugLineBasicFixture
, ParserIgnoresNonPrologueErrorsWhenSkipping
) {
1486 if (!setupGenerator())
1489 LineTable
<
= Gen
->addLineTable(DWARF32
);
1490 LT
.addExtendedOpcode(42, DW_LNE_end_sequence
, {});
1493 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1494 Parser
.skip(RecordRecoverable
, RecordUnrecoverable
);
1496 EXPECT_TRUE(Parser
.done());
1497 EXPECT_FALSE(Recoverable
);
1498 EXPECT_FALSE(Unrecoverable
);
1501 #ifdef NO_SUPPORT_DEBUG_ADDR
1502 TEST_F(DebugLineBasicFixture
, DISABLED_VerboseOutput
) {
1504 TEST_F(DebugLineBasicFixture
, VerboseOutput
) {
1506 if (!setupGenerator(5))
1509 LineTable
<
= Gen
->addLineTable();
1510 LT
.addByte(0); // Extended opcode with zero length.
1512 // Zero-value extended opcode.
1513 LT
.addExtendedOpcode(2, 0, {{1, LineTable::Byte
}});
1514 // Unknown extended opcode.
1515 LT
.addExtendedOpcode(2, 0x42, {{1, LineTable::Byte
}});
1516 LT
.addExtendedOpcode(9, DW_LNE_set_address
,
1517 {{0x123456789abcdef, LineTable::Quad
}});
1518 LT
.addExtendedOpcode(6, DW_LNE_define_file
,
1519 {{'a', LineTable::Byte
},
1520 {'\0', LineTable::Byte
},
1521 {2, LineTable::ULEB
},
1522 {3, LineTable::ULEB
},
1523 {4, LineTable::ULEB
}});
1524 LT
.addExtendedOpcode(2, DW_LNE_set_discriminator
, {{0x7f, LineTable::ULEB
}});
1525 LT
.addStandardOpcode(DW_LNS_copy
, {});
1526 LT
.addStandardOpcode(DW_LNS_advance_pc
, {{11, LineTable::ULEB
}});
1527 LT
.addStandardOpcode(DW_LNS_advance_line
, {{22, LineTable::SLEB
}});
1528 LT
.addStandardOpcode(DW_LNS_set_file
, {{33, LineTable::ULEB
}});
1529 LT
.addStandardOpcode(DW_LNS_set_column
, {{44, LineTable::ULEB
}});
1530 LT
.addStandardOpcode(DW_LNS_negate_stmt
, {});
1531 LT
.addStandardOpcode(DW_LNS_set_basic_block
, {});
1532 LT
.addStandardOpcode(DW_LNS_const_add_pc
, {});
1533 LT
.addStandardOpcode(DW_LNS_fixed_advance_pc
, {{55, LineTable::Half
}});
1534 LT
.addStandardOpcode(DW_LNS_set_prologue_end
, {});
1535 LT
.addStandardOpcode(DW_LNS_set_epilogue_begin
, {});
1536 LT
.addStandardOpcode(DW_LNS_set_isa
, {{66, LineTable::ULEB
}});
1537 // Add unknown standard opcode with operands.
1538 LT
.addStandardOpcode(
1539 0xd, {{1, LineTable::ULEB
}, {0x123456789abcdef, LineTable::ULEB
}});
1540 // Add unknown standard opcode without operands.
1541 LT
.addStandardOpcode(0xe, {});
1542 LT
.addByte(0xff); // Special opcode.
1543 LT
.addExtendedOpcode(1, DW_LNE_end_sequence
, {});
1545 // Adjust the prologue to account for the extra standard opcode.
1546 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
1547 Prologue
.TotalLength
+= 2;
1548 Prologue
.PrologueLength
+= 2;
1549 Prologue
.OpcodeBase
+= 2;
1550 Prologue
.StandardOpcodeLengths
.push_back(2);
1551 Prologue
.StandardOpcodeLengths
.push_back(0);
1552 LT
.setPrologue(Prologue
);
1556 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1558 raw_string_ostream
OS(Output
);
1559 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
, &OS
,
1561 StringRef
OutputRef(Output
);
1564 auto NextLine
= [&Pos
, &OutputRef
]() {
1565 size_t EOL
= OutputRef
.find_first_of('\n', Pos
);
1566 StringRef Line
= OutputRef
.substr(Pos
, EOL
- Pos
);
1570 EXPECT_EQ(NextLine(), "Line table prologue:");
1571 EXPECT_EQ(NextLine(), " total_length: 0x00000078");
1572 EXPECT_EQ(NextLine(), " format: DWARF32");
1573 EXPECT_EQ(NextLine(), " version: 5");
1574 EXPECT_EQ(NextLine(), " address_size: 8");
1575 EXPECT_EQ(NextLine(), " seg_select_size: 0");
1576 EXPECT_EQ(NextLine(), " prologue_length: 0x0000002c");
1577 EXPECT_EQ(NextLine(), " min_inst_length: 1");
1578 EXPECT_EQ(NextLine(), "max_ops_per_inst: 1");
1579 EXPECT_EQ(NextLine(), " default_is_stmt: 1");
1580 EXPECT_EQ(NextLine(), " line_base: -5");
1581 EXPECT_EQ(NextLine(), " line_range: 14");
1582 EXPECT_EQ(NextLine(), " opcode_base: 15");
1583 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_copy] = 0");
1584 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_advance_pc] = 1");
1585 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_advance_line] = 1");
1586 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_set_file] = 1");
1587 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_set_column] = 1");
1588 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_negate_stmt] = 0");
1589 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_set_basic_block] = 0");
1590 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_const_add_pc] = 0");
1591 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1");
1592 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_set_prologue_end] = 0");
1593 EXPECT_EQ(NextLine(),
1594 "standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0");
1595 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_set_isa] = 1");
1596 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_unknown_d] = 2");
1597 EXPECT_EQ(NextLine(), "standard_opcode_lengths[DW_LNS_unknown_e] = 0");
1598 EXPECT_EQ(NextLine(), "include_directories[ 0] = \"a dir\"");
1599 EXPECT_EQ(NextLine(), "file_names[ 0]:");
1600 EXPECT_EQ(NextLine(), " name: \"a file\"");
1601 EXPECT_EQ(NextLine(), " dir_index: 0");
1602 EXPECT_EQ(NextLine(), "");
1603 EXPECT_EQ(NextLine(), " Address Line Column File "
1604 "ISA Discriminator OpIndex Flags");
1605 EXPECT_EQ(NextLine(), " ------------------ ------ ------ ------ "
1606 "--- ------------- ------- -------------");
1607 EXPECT_EQ(NextLine(),
1608 "0x00000038: 00 Badly formed extended line op (length 0)");
1609 EXPECT_EQ(NextLine(),
1610 "0x0000003a: 00 Unrecognized extended op 0x00 length 2");
1611 EXPECT_EQ(NextLine(),
1612 "0x0000003e: 00 Unrecognized extended op 0x42 length 2");
1613 EXPECT_EQ(NextLine(),
1614 "0x00000042: 00 DW_LNE_set_address (0x0123456789abcdef)");
1615 EXPECT_EQ(NextLine(), "0x0000004d: 00 DW_LNE_define_file (a, dir=2, "
1616 "mod_time=(0x0000000000000003), length=4)");
1617 EXPECT_EQ(NextLine(), "0x00000055: 00 DW_LNE_set_discriminator (127)");
1618 EXPECT_EQ(NextLine(), "0x00000059: 01 DW_LNS_copy");
1619 EXPECT_EQ(NextLine(), " 0x0123456789abcdef 1 0 1 "
1621 EXPECT_EQ(NextLine(), "0x0000005a: 02 DW_LNS_advance_pc (addr += 11, "
1623 EXPECT_EQ(NextLine(), "0x0000005c: 03 DW_LNS_advance_line (23)");
1624 EXPECT_EQ(NextLine(), "0x0000005e: 04 DW_LNS_set_file (33)");
1625 EXPECT_EQ(NextLine(), "0x00000060: 05 DW_LNS_set_column (44)");
1626 EXPECT_EQ(NextLine(), "0x00000062: 06 DW_LNS_negate_stmt");
1627 EXPECT_EQ(NextLine(), "0x00000063: 07 DW_LNS_set_basic_block");
1628 EXPECT_EQ(NextLine(),
1629 "0x00000064: 08 DW_LNS_const_add_pc (addr += 0x0000000000000011, "
1631 EXPECT_EQ(NextLine(), "0x00000065: 09 DW_LNS_fixed_advance_pc (addr += 0x0037"
1633 EXPECT_EQ(NextLine(), "0x00000068: 0a DW_LNS_set_prologue_end");
1634 EXPECT_EQ(NextLine(), "0x00000069: 0b DW_LNS_set_epilogue_begin");
1635 EXPECT_EQ(NextLine(), "0x0000006a: 0c DW_LNS_set_isa (66)");
1636 EXPECT_EQ(NextLine(), "0x0000006c: 0d Unrecognized standard opcode "
1637 "(operands: 0x0000000000000001, 0x0123456789abcdef)");
1638 EXPECT_EQ(NextLine(), "0x00000077: 0e Unrecognized standard opcode");
1639 EXPECT_EQ(NextLine(), "0x00000078: ff address += 17, line += -3, "
1641 EXPECT_EQ(NextLine(),
1642 " 0x0123456789abce53 20 44 33 66 "
1643 " 0 0 basic_block prologue_end epilogue_begin");
1644 EXPECT_EQ(NextLine(), "0x00000079: 00 DW_LNE_end_sequence");
1645 EXPECT_EQ(NextLine(), " 0x0123456789abce53 20 44 33 "
1646 "66 0 0 end_sequence");
1647 EXPECT_EQ(NextLine(), "");
1648 EXPECT_EQ(Output
.size(), Pos
);
1651 struct TruncatedPrologueFixture
1652 : public TestWithParam
<
1653 std::tuple
<uint64_t, uint64_t, uint16_t, DwarfFormat
, StringRef
>>,
1654 public CommonFixture
{
1655 void SetUp() override
{
1656 std::tie(Length
, ExpectedOffset
, Version
, Format
, ExpectedErr
) = GetParam();
1660 uint64_t ExpectedOffset
;
1663 StringRef ExpectedErr
;
1666 #ifdef NO_SUPPORT_DEBUG_ADDR
1667 TEST_P(TruncatedPrologueFixture
, DISABLED_ErrorForTruncatedPrologue
) {
1669 TEST_P(TruncatedPrologueFixture
, ErrorForTruncatedPrologue
) {
1671 if (!setupGenerator(Version
))
1674 LineTable
&Padding
= Gen
->addLineTable();
1675 // Add some padding to show that a non-zero offset is handled correctly.
1676 Padding
.setCustomPrologue({{0, LineTable::Byte
}});
1678 // Add a table with only two standard opcodes - we don't need to test the full
1680 LineTable
&Table
= Gen
->addLineTable(Format
);
1681 DWARFDebugLine::Prologue InputPrologue
= Table
.createBasicPrologue();
1682 InputPrologue
.OpcodeBase
= 3;
1683 InputPrologue
.StandardOpcodeLengths
.resize(2);
1684 Table
.setPrologue(InputPrologue
);
1687 // Truncate the data extractor to the specified length.
1688 LineData
= DWARFDataExtractor(LineData
, Length
);
1690 DWARFDebugLine::Prologue Prologue
;
1691 uint64_t Offset
= 1;
1692 Error Err
= Prologue
.parse(LineData
, &Offset
, RecordRecoverable
, *Context
);
1694 EXPECT_THAT_ERROR(std::move(Err
), FailedWithMessage(ExpectedErr
.str()));
1695 EXPECT_EQ(Offset
, ExpectedOffset
);
1698 INSTANTIATE_TEST_SUITE_P(
1699 TruncatedPrologueParams
, TruncatedPrologueFixture
,
1701 // Truncated length:
1704 "parsing line table prologue at offset 0x00000001: unexpected end "
1705 "of data at offset 0x4 while reading [0x1, 0x5)"),
1708 "parsing line table prologue at offset 0x00000001: unexpected end "
1709 "of data at offset 0x4 while reading [0x1, 0x5)"),
1712 "parsing line table prologue at offset 0x00000001: unexpected end "
1713 "of data at offset 0xc while reading [0x5, 0xd)"),
1714 // Truncated version:
1717 "parsing line table prologue at offset 0x00000001: unexpected end "
1718 "of data at offset 0x6 while reading [0x5, 0x7)"),
1719 // Truncated address size:
1722 "parsing line table prologue at offset 0x00000001: unexpected end "
1723 "of data at offset 0x7 while reading [0x7, 0x8)"),
1724 // Truncated segment selector size:
1727 "parsing line table prologue at offset 0x00000001: unexpected end "
1728 "of data at offset 0x8 while reading [0x8, 0x9)"),
1729 // Truncated prologue length:
1732 "parsing line table prologue at offset 0x00000001: unexpected end "
1733 "of data at offset 0xa while reading [0x7, 0xb)"),
1735 0x16, 0xf, 4, DWARF64
,
1736 "parsing line table prologue at offset 0x00000001: unexpected end "
1737 "of data at offset 0x16 while reading [0xf, 0x17)"),
1738 // Truncated min instruction length:
1740 0xb, 0xb, 4, DWARF32
,
1741 "parsing line table prologue at offset 0x00000001: unexpected end "
1742 "of data at offset 0xb while reading [0xb, 0xc)"),
1743 // Truncated max ops per inst:
1745 0xc, 0xc, 4, DWARF32
,
1746 "parsing line table prologue at offset 0x00000001: unexpected end "
1747 "of data at offset 0xc while reading [0xc, 0xd)"),
1748 // Truncated default is stmt:
1750 0xd, 0xd, 4, DWARF32
,
1751 "parsing line table prologue at offset 0x00000001: unexpected end "
1752 "of data at offset 0xd while reading [0xd, 0xe)"),
1753 // Truncated line base:
1755 0xe, 0xe, 4, DWARF32
,
1756 "parsing line table prologue at offset 0x00000001: unexpected end "
1757 "of data at offset 0xe while reading [0xe, 0xf)"),
1758 // Truncated line range:
1760 0xf, 0xf, 4, DWARF32
,
1761 "parsing line table prologue at offset 0x00000001: unexpected end "
1762 "of data at offset 0xf while reading [0xf, 0x10)"),
1763 // Truncated opcode base:
1765 0x10, 0x10, 4, DWARF32
,
1766 "parsing line table prologue at offset 0x00000001: unexpected end "
1767 "of data at offset 0x10 while reading [0x10, 0x11)"),
1768 // Truncated first standard opcode:
1770 0x11, 0x11, 4, DWARF32
,
1771 "parsing line table prologue at offset 0x00000001: unexpected end "
1772 "of data at offset 0x11 while reading [0x11, 0x12)"),
1773 // Truncated second standard opcode:
1775 0x12, 0x12, 4, DWARF32
,
1776 "parsing line table prologue at offset 0x00000001: unexpected end "
1777 "of data at offset 0x12 while reading [0x12, 0x13)")));
1779 using ValueAndLengths
= std::vector
<LineTable::ValueAndLength
>;
1781 struct TruncatedOpcodeFixtureBase
: public CommonFixture
{
1782 LineTable
&setupTable() {
1783 LineTable
<
= Gen
->addLineTable();
1785 // Creating the prologue before adding any opcodes ensures that the unit
1786 // length does not include the table body.
1787 DWARFDebugLine::Prologue Prologue
= LT
.createBasicPrologue();
1789 // Add an unrecognised standard opcode, and adjust prologue properties
1791 Prologue
.TotalLength
+= BodyLength
+ 1;
1792 ++Prologue
.PrologueLength
;
1793 ++Prologue
.OpcodeBase
;
1794 Prologue
.StandardOpcodeLengths
.push_back(2);
1795 LT
.setPrologue(Prologue
);
1800 void runTest(uint8_t OpcodeValue
) {
1802 DWARFDebugLine::SectionParser
Parser(LineData
, *Context
, Units
);
1804 raw_string_ostream
OS(Output
);
1805 Parser
.parseNext(RecordRecoverable
, RecordUnrecoverable
, &OS
,
1808 std::string LinePrefix
=
1809 ("0x0000002f: 0" + Twine::utohexstr(OpcodeValue
) + " ").str();
1810 StringRef
OutputRef(Output
);
1811 StringRef OutputToCheck
= OutputRef
.split(LinePrefix
).second
;
1812 // Each extended opcode ends with a new line and then the table ends with an
1813 // additional blank line.
1814 EXPECT_EQ((ExpectedOutput
+ "\n\n").str(), OutputToCheck
);
1817 uint64_t BodyLength
;
1819 ValueAndLengths Operands
;
1820 StringRef ExpectedOutput
;
1821 StringRef ExpectedErr
;
1824 struct TruncatedStandardOpcodeFixture
1825 : public TestWithParam
<
1826 std::tuple
<uint64_t, uint8_t, ValueAndLengths
, StringRef
, StringRef
>>,
1827 public TruncatedOpcodeFixtureBase
{
1828 void SetUp() override
{
1829 std::tie(BodyLength
, Opcode
, Operands
, ExpectedOutput
, ExpectedErr
) =
1834 struct TruncatedExtendedOpcodeFixture
1835 : public TestWithParam
<std::tuple
<uint64_t, uint64_t, uint8_t,
1836 ValueAndLengths
, StringRef
, StringRef
>>,
1837 public TruncatedOpcodeFixtureBase
{
1838 void SetUp() override
{
1839 std::tie(BodyLength
, OpcodeLength
, Opcode
, Operands
, ExpectedOutput
,
1840 ExpectedErr
) = GetParam();
1843 uint64_t OpcodeLength
;
1846 TEST_P(TruncatedExtendedOpcodeFixture
, ErrorForTruncatedExtendedOpcode
) {
1847 if (!setupGenerator())
1849 LineTable
<
= setupTable();
1850 LT
.addExtendedOpcode(OpcodeLength
, Opcode
, Operands
);
1852 EXPECT_THAT_ERROR(std::move(Recoverable
),
1853 FailedWithMessage(ExpectedErr
.str()));
1856 INSTANTIATE_TEST_SUITE_P(
1857 TruncatedExtendedOpcodeParams
, TruncatedExtendedOpcodeFixture
,
1859 // Truncated length:
1860 std::make_tuple(1, 1, /*ArbitraryOpcode=*/0x7f, ValueAndLengths(), "",
1861 "unable to decode LEB128 at offset 0x00000030: "
1862 "malformed uleb128, extends past end"),
1863 // Truncated opcode:
1865 2, 9, /*ArbitraryOpcode=*/0x7f, ValueAndLengths(), "",
1866 "unexpected end of data at offset 0x31 while reading [0x31, 0x32)"),
1867 // Truncated operands:
1869 3, 9, DW_LNE_set_address
,
1870 ValueAndLengths
{{0x1234567890abcdef, LineTable::Quad
}},
1871 "DW_LNE_set_address",
1872 "unexpected end of data at offset 0x32 while reading [0x32, 0x3a)"),
1874 10, 9, DW_LNE_set_address
,
1875 ValueAndLengths
{{0x1234567878563412, LineTable::Quad
}},
1876 "DW_LNE_set_address (<parsing error> 12 34 56 78 78 56 34)",
1877 "unexpected end of data at offset 0x39 while reading [0x32, 0x3a)"),
1878 std::make_tuple(3, 6, DW_LNE_define_file
,
1879 ValueAndLengths
{{'a', LineTable::Byte
},
1880 {'\0', LineTable::Byte
},
1881 {1, LineTable::ULEB
},
1882 {1, LineTable::ULEB
},
1883 {1, LineTable::ULEB
}},
1884 "DW_LNE_define_file",
1885 "no null terminated string at offset 0x32"),
1886 std::make_tuple(5, 6, DW_LNE_define_file
,
1887 ValueAndLengths
{{'a', LineTable::Byte
},
1888 {'\0', LineTable::Byte
},
1889 {1, LineTable::ULEB
},
1890 {1, LineTable::ULEB
},
1891 {1, LineTable::ULEB
}},
1892 "DW_LNE_define_file (<parsing error> 61 00)",
1893 "unable to decode LEB128 at offset 0x00000034: "
1894 "malformed uleb128, extends past end"),
1895 std::make_tuple(6, 6, DW_LNE_define_file
,
1896 ValueAndLengths
{{'a', LineTable::Byte
},
1897 {'\0', LineTable::Byte
},
1898 {1, LineTable::ULEB
},
1899 {1, LineTable::ULEB
},
1900 {1, LineTable::ULEB
}},
1901 "DW_LNE_define_file (<parsing error> 61 00 01)",
1902 "unable to decode LEB128 at offset 0x00000035: "
1903 "malformed uleb128, extends past end"),
1904 std::make_tuple(7, 6, DW_LNE_define_file
,
1905 ValueAndLengths
{{'a', LineTable::Byte
},
1906 {'\0', LineTable::Byte
},
1907 {1, LineTable::ULEB
},
1908 {1, LineTable::ULEB
},
1909 {1, LineTable::ULEB
}},
1910 "DW_LNE_define_file (<parsing error> 61 00 01 01)",
1911 "unable to decode LEB128 at offset 0x00000036: "
1912 "malformed uleb128, extends past end"),
1913 std::make_tuple(3, 2, DW_LNE_set_discriminator
,
1914 ValueAndLengths
{{1, LineTable::ULEB
}},
1915 "DW_LNE_set_discriminator",
1916 "unable to decode LEB128 at offset 0x00000032: "
1917 "malformed uleb128, extends past end"),
1919 6, 5, /*Unknown=*/0x7f,
1920 ValueAndLengths
{{0x12343412, LineTable::Long
}},
1921 "Unrecognized extended op 0x7f length 5 (<parsing error> 12 34 34)",
1922 "unexpected end of data at offset 0x35 while reading [0x32, "
1925 TEST_P(TruncatedStandardOpcodeFixture
, ErrorForTruncatedStandardOpcode
) {
1926 if (!setupGenerator())
1928 LineTable
<
= setupTable();
1929 LT
.addStandardOpcode(Opcode
, Operands
);
1931 EXPECT_THAT_ERROR(std::move(Unrecoverable
),
1932 FailedWithMessage(ExpectedErr
.str()));
1935 INSTANTIATE_TEST_SUITE_P(
1936 TruncatedStandardOpcodeParams
, TruncatedStandardOpcodeFixture
,
1938 std::make_tuple(2, DW_LNS_advance_pc
,
1939 ValueAndLengths
{{0x100, LineTable::ULEB
}},
1940 "DW_LNS_advance_pc",
1941 "unable to decode LEB128 at offset 0x00000030: "
1942 "malformed uleb128, extends past end"),
1943 std::make_tuple(2, DW_LNS_advance_line
,
1944 ValueAndLengths
{{0x200, LineTable::SLEB
}},
1945 "DW_LNS_advance_line",
1946 "unable to decode LEB128 at offset 0x00000030: "
1947 "malformed sleb128, extends past end"),
1948 std::make_tuple(2, DW_LNS_set_file
,
1949 ValueAndLengths
{{0x300, LineTable::ULEB
}},
1951 "unable to decode LEB128 at offset 0x00000030: "
1952 "malformed uleb128, extends past end"),
1953 std::make_tuple(2, DW_LNS_set_column
,
1954 ValueAndLengths
{{0x400, LineTable::ULEB
}},
1955 "DW_LNS_set_column",
1956 "unable to decode LEB128 at offset 0x00000030: "
1957 "malformed uleb128, extends past end"),
1959 2, DW_LNS_fixed_advance_pc
,
1960 ValueAndLengths
{{0x500, LineTable::Half
}},
1961 "DW_LNS_fixed_advance_pc",
1962 "unexpected end of data at offset 0x31 while reading [0x30, 0x32)"),
1963 std::make_tuple(2, DW_LNS_set_isa
,
1964 ValueAndLengths
{{0x600, LineTable::ULEB
}},
1966 "unable to decode LEB128 at offset 0x00000030: "
1967 "malformed uleb128, extends past end"),
1968 std::make_tuple(2, 0xd,
1969 ValueAndLengths
{{0x700, LineTable::ULEB
},
1970 {0x800, LineTable::ULEB
}},
1971 "Unrecognized standard opcode",
1972 "unable to decode LEB128 at offset 0x00000030: "
1973 "malformed uleb128, extends past end"),
1976 ValueAndLengths
{{0x900, LineTable::ULEB
}, {0xa00, LineTable::ULEB
}},
1977 "Unrecognized standard opcode (operands: 0x0000000000000900)",
1978 "unable to decode LEB128 at offset 0x00000032: "
1979 "malformed uleb128, extends past end")));
1981 #ifdef NO_SUPPORT_DEBUG_ADDR
1982 TEST_F(DebugLineBasicFixture
, DISABLED_PrintPathsProperly
) {
1984 TEST_F(DebugLineBasicFixture
, PrintPathsProperly
) {
1986 if (!setupGenerator(5))
1989 LineTable
<
= Gen
->addLineTable();
1990 DWARFDebugLine::Prologue P
= LT
.createBasicPrologue();
1991 P
.IncludeDirectories
.push_back(
1992 DWARFFormValue::createFromPValue(DW_FORM_string
, "b dir"));
1993 P
.FileNames
.push_back(DWARFDebugLine::FileNameEntry());
1994 P
.FileNames
.back().Name
=
1995 DWARFFormValue::createFromPValue(DW_FORM_string
, "b file");
1996 P
.FileNames
.back().DirIdx
= 1;
1997 P
.TotalLength
+= 14;
1998 P
.PrologueLength
+= 14;
2002 auto ExpectedLineTable
= Line
.getOrParseLineTable(LineData
, 0, *Context
,
2003 nullptr, RecordRecoverable
);
2004 EXPECT_THAT_EXPECTED(ExpectedLineTable
, Succeeded());
2006 // DWARF 5 stores the compilation directory in two places: the Compilation
2007 // Unit and the directory table entry 0, and implementations are free to use
2008 // one or the other. This copy serves as the one stored in the CU.
2009 StringRef CompDir
= "a dir";
2011 (*ExpectedLineTable
)
2012 ->Prologue
.getFileNameByIndex(
2013 1, CompDir
, DILineInfoSpecifier::FileLineInfoKind::None
, Result
));
2014 EXPECT_TRUE((*ExpectedLineTable
)
2015 ->Prologue
.getFileNameByIndex(
2017 DILineInfoSpecifier::FileLineInfoKind::RawValue
, Result
));
2018 EXPECT_TRUE((*ExpectedLineTable
)
2019 ->Prologue
.getFileNameByIndex(
2021 DILineInfoSpecifier::FileLineInfoKind::BaseNameOnly
,
2023 EXPECT_STREQ(Result
.c_str(), "b file");
2024 EXPECT_TRUE((*ExpectedLineTable
)
2025 ->Prologue
.getFileNameByIndex(
2027 DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath
,
2029 EXPECT_THAT(Result
.c_str(), MatchesRegex("b dir.b file"));
2030 EXPECT_TRUE((*ExpectedLineTable
)
2031 ->Prologue
.getFileNameByIndex(
2033 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
,
2035 EXPECT_THAT(Result
.c_str(), MatchesRegex("a dir.b dir.b file"));
2038 } // end anonymous namespace