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