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