1050edef8SMaksim Panchenko //===- llvm/unittest/MC/DwarfLineTableHeaders.cpp -------------------------===// 2050edef8SMaksim Panchenko // 3050edef8SMaksim Panchenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4050edef8SMaksim Panchenko // See https://llvm.org/LICENSE.txt for license information. 5050edef8SMaksim Panchenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6050edef8SMaksim Panchenko // 7050edef8SMaksim Panchenko //===----------------------------------------------------------------------===// 8050edef8SMaksim Panchenko 9050edef8SMaksim Panchenko #include "llvm/ADT/STLExtras.h" 10050edef8SMaksim Panchenko #include "llvm/BinaryFormat/Dwarf.h" 11050edef8SMaksim Panchenko #include "llvm/MC/MCAsmBackend.h" 12050edef8SMaksim Panchenko #include "llvm/MC/MCAsmInfo.h" 13ef736a1cSserge-sans-paille #include "llvm/MC/MCAssembler.h" 14050edef8SMaksim Panchenko #include "llvm/MC/MCCodeEmitter.h" 15050edef8SMaksim Panchenko #include "llvm/MC/MCContext.h" 16050edef8SMaksim Panchenko #include "llvm/MC/MCDwarf.h" 17050edef8SMaksim Panchenko #include "llvm/MC/MCInstrInfo.h" 18050edef8SMaksim Panchenko #include "llvm/MC/MCObjectStreamer.h" 19050edef8SMaksim Panchenko #include "llvm/MC/MCObjectWriter.h" 20050edef8SMaksim Panchenko #include "llvm/MC/MCRegisterInfo.h" 21050edef8SMaksim Panchenko #include "llvm/MC/MCStreamer.h" 22ef736a1cSserge-sans-paille #include "llvm/MC/MCSubtargetInfo.h" 23050edef8SMaksim Panchenko #include "llvm/MC/MCTargetOptions.h" 2489b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h" 25050edef8SMaksim Panchenko #include "llvm/Object/Binary.h" 26050edef8SMaksim Panchenko #include "llvm/Object/ELFObjectFile.h" 27050edef8SMaksim Panchenko #include "llvm/Support/FileSystem.h" 28e72c195fSserge-sans-paille #include "llvm/Support/MemoryBuffer.h" 29050edef8SMaksim Panchenko #include "llvm/Support/TargetSelect.h" 30050edef8SMaksim Panchenko #include "llvm/Support/ToolOutputFile.h" 31050edef8SMaksim Panchenko #include "gtest/gtest.h" 32050edef8SMaksim Panchenko 33050edef8SMaksim Panchenko using namespace llvm; 34050edef8SMaksim Panchenko 35050edef8SMaksim Panchenko namespace { 36050edef8SMaksim Panchenko 37050edef8SMaksim Panchenko class DwarfLineTableHeaders : public ::testing::Test { 38050edef8SMaksim Panchenko public: 39050edef8SMaksim Panchenko const char *TripleName = "x86_64-pc-linux"; 40050edef8SMaksim Panchenko std::unique_ptr<MCRegisterInfo> MRI; 41050edef8SMaksim Panchenko std::unique_ptr<MCAsmInfo> MAI; 42050edef8SMaksim Panchenko std::unique_ptr<const MCSubtargetInfo> STI; 43050edef8SMaksim Panchenko const Target *TheTarget; 44050edef8SMaksim Panchenko 45050edef8SMaksim Panchenko struct StreamerContext { 46050edef8SMaksim Panchenko std::unique_ptr<MCObjectFileInfo> MOFI; 47050edef8SMaksim Panchenko std::unique_ptr<MCContext> Ctx; 48050edef8SMaksim Panchenko std::unique_ptr<const MCInstrInfo> MII; 49050edef8SMaksim Panchenko std::unique_ptr<MCStreamer> Streamer; 50050edef8SMaksim Panchenko }; 51050edef8SMaksim Panchenko 52050edef8SMaksim Panchenko DwarfLineTableHeaders() { 53050edef8SMaksim Panchenko llvm::InitializeAllTargetInfos(); 54050edef8SMaksim Panchenko llvm::InitializeAllTargetMCs(); 55050edef8SMaksim Panchenko llvm::InitializeAllDisassemblers(); 56050edef8SMaksim Panchenko 57050edef8SMaksim Panchenko // If we didn't build x86, do not run the test. 58050edef8SMaksim Panchenko std::string Error; 59050edef8SMaksim Panchenko TheTarget = TargetRegistry::lookupTarget(TripleName, Error); 60050edef8SMaksim Panchenko if (!TheTarget) 61050edef8SMaksim Panchenko return; 62050edef8SMaksim Panchenko 63050edef8SMaksim Panchenko MRI.reset(TheTarget->createMCRegInfo(TripleName)); 64050edef8SMaksim Panchenko MCTargetOptions MCOptions; 65050edef8SMaksim Panchenko MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 66050edef8SMaksim Panchenko STI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); 67050edef8SMaksim Panchenko } 68050edef8SMaksim Panchenko 69050edef8SMaksim Panchenko /// Create all data structures necessary to operate an assembler 70050edef8SMaksim Panchenko StreamerContext createStreamer(raw_pwrite_stream &OS) { 71050edef8SMaksim Panchenko StreamerContext Res; 72050edef8SMaksim Panchenko Res.Ctx = 73050edef8SMaksim Panchenko std::make_unique<MCContext>(Triple(TripleName), MAI.get(), MRI.get(), 74050edef8SMaksim Panchenko /*MSTI=*/nullptr); 7575bc20ffSKazu Hirata Res.MOFI.reset(TheTarget->createMCObjectFileInfo(*Res.Ctx, 76050edef8SMaksim Panchenko /*PIC=*/false)); 77050edef8SMaksim Panchenko Res.Ctx->setObjectFileInfo(Res.MOFI.get()); 78050edef8SMaksim Panchenko 79050edef8SMaksim Panchenko Res.MII.reset(TheTarget->createMCInstrInfo()); 802aed07e9SShao-Ce SUN MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*Res.MII, *Res.Ctx); 81050edef8SMaksim Panchenko MCAsmBackend *MAB = 82050edef8SMaksim Panchenko TheTarget->createMCAsmBackend(*STI, *MRI, MCTargetOptions()); 83050edef8SMaksim Panchenko std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(OS); 84050edef8SMaksim Panchenko Res.Streamer.reset(TheTarget->createMCObjectStreamer( 85050edef8SMaksim Panchenko Triple(TripleName), *Res.Ctx, std::unique_ptr<MCAsmBackend>(MAB), 86*b8220b98SFangrui Song std::move(OW), std::unique_ptr<MCCodeEmitter>(MCE), *STI)); 87050edef8SMaksim Panchenko return Res; 88050edef8SMaksim Panchenko } 89050edef8SMaksim Panchenko 90050edef8SMaksim Panchenko /// Emit a .debug_line section with the given context parameters 91050edef8SMaksim Panchenko void emitDebugLineSection(StreamerContext &C) { 92050edef8SMaksim Panchenko MCContext &Ctx = *C.Ctx; 93050edef8SMaksim Panchenko MCStreamer *TheStreamer = C.Streamer.get(); 94050edef8SMaksim Panchenko MCAssembler &Assembler = 95050edef8SMaksim Panchenko static_cast<MCObjectStreamer *>(TheStreamer)->getAssembler(); 96050edef8SMaksim Panchenko TheStreamer->initSections(false, *STI); 97050edef8SMaksim Panchenko 98050edef8SMaksim Panchenko // Create a mock function 99050edef8SMaksim Panchenko MCSection *Section = C.MOFI->getTextSection(); 100050edef8SMaksim Panchenko Section->setHasInstructions(true); 101adf4142fSFangrui Song TheStreamer->switchSection(Section); 102050edef8SMaksim Panchenko TheStreamer->emitCFIStartProc(true); 103050edef8SMaksim Panchenko 104050edef8SMaksim Panchenko // Create a mock dwarfloc 105050edef8SMaksim Panchenko Ctx.setCurrentDwarfLoc(/*FileNo=*/0, /*Line=*/1, /*Column=*/1, /*Flags=*/0, 106050edef8SMaksim Panchenko /*Isa=*/0, /*Discriminator=*/0); 107050edef8SMaksim Panchenko MCDwarfLoc Loc = Ctx.getCurrentDwarfLoc(); 108050edef8SMaksim Panchenko MCSymbol *LineSym = Ctx.createTempSymbol(); 109050edef8SMaksim Panchenko // Set the value of the symbol to use for the MCDwarfLineEntry. 110050edef8SMaksim Panchenko TheStreamer->emitLabel(LineSym); 111050edef8SMaksim Panchenko TheStreamer->emitNops(4, 1, SMLoc(), *STI); 112050edef8SMaksim Panchenko TheStreamer->emitCFIEndProc(); 113050edef8SMaksim Panchenko 114050edef8SMaksim Panchenko // Start emission of .debug_line 115adf4142fSFangrui Song TheStreamer->switchSection(C.MOFI->getDwarfLineSection()); 116050edef8SMaksim Panchenko MCDwarfLineTableHeader Header; 117050edef8SMaksim Panchenko MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams(); 118f4c16c44SFangrui Song std::optional<MCDwarfLineStr> LineStr(std::nullopt); 119050edef8SMaksim Panchenko if (Ctx.getDwarfVersion() >= 5) { 120b0c4cd35SFangrui Song LineStr.emplace(Ctx); 121b6a01caaSKazu Hirata Header.setRootFile("dir", "file", std::nullopt, std::nullopt); 122050edef8SMaksim Panchenko } 123050edef8SMaksim Panchenko MCSymbol *LineEndSym = Header.Emit(TheStreamer, Params, LineStr).second; 124050edef8SMaksim Panchenko 125050edef8SMaksim Panchenko // Put out the line tables. 126050edef8SMaksim Panchenko MCLineSection::MCDwarfLineEntryCollection LineEntries; 127050edef8SMaksim Panchenko MCDwarfLineEntry LineEntry(LineSym, Loc); 128050edef8SMaksim Panchenko LineEntries.push_back(LineEntry); 129050edef8SMaksim Panchenko MCDwarfLineTable::emitOne(TheStreamer, Section, LineEntries); 130050edef8SMaksim Panchenko TheStreamer->emitLabel(LineEndSym); 131c87d405bSAlexander Yermolovich if (LineStr) { 132c87d405bSAlexander Yermolovich SmallString<0> Data = LineStr->getFinalizedData(); 133adf4142fSFangrui Song TheStreamer->switchSection(TheStreamer->getContext() 134c87d405bSAlexander Yermolovich .getObjectFileInfo() 135c87d405bSAlexander Yermolovich ->getDwarfLineStrSection()); 136c87d405bSAlexander Yermolovich TheStreamer->emitBinaryData(Data.str()); 137c87d405bSAlexander Yermolovich } 138050edef8SMaksim Panchenko } 139050edef8SMaksim Panchenko 140050edef8SMaksim Panchenko /// Check contents of .debug_line section 141050edef8SMaksim Panchenko void verifyDebugLineContents(const llvm::object::ObjectFile &E, 142050edef8SMaksim Panchenko ArrayRef<uint8_t> ExpectedEncoding) { 143050edef8SMaksim Panchenko for (const llvm::object::SectionRef &Section : E.sections()) { 144050edef8SMaksim Panchenko Expected<StringRef> SectionNameOrErr = Section.getName(); 145050edef8SMaksim Panchenko ASSERT_TRUE(static_cast<bool>(SectionNameOrErr)); 146050edef8SMaksim Panchenko StringRef SectionName = *SectionNameOrErr; 147050edef8SMaksim Panchenko if (SectionName.empty() || SectionName != ".debug_line") 148050edef8SMaksim Panchenko continue; 149050edef8SMaksim Panchenko Expected<StringRef> ContentsOrErr = Section.getContents(); 150050edef8SMaksim Panchenko ASSERT_TRUE(static_cast<bool>(ContentsOrErr)); 151050edef8SMaksim Panchenko StringRef Contents = *ContentsOrErr; 152050edef8SMaksim Panchenko ASSERT_TRUE(Contents.size() > ExpectedEncoding.size()); 153050edef8SMaksim Panchenko EXPECT_EQ( 154050edef8SMaksim Panchenko arrayRefFromStringRef(Contents.slice(0, ExpectedEncoding.size())), 155050edef8SMaksim Panchenko ExpectedEncoding); 156050edef8SMaksim Panchenko return; 157050edef8SMaksim Panchenko } 158050edef8SMaksim Panchenko llvm_unreachable(".debug_line not found"); 159050edef8SMaksim Panchenko } 160050edef8SMaksim Panchenko 161c87d405bSAlexander Yermolovich /// Check contents of .debug_line_str section 162c87d405bSAlexander Yermolovich void verifyDebugLineStrContents(const llvm::object::ObjectFile &E) { 163c87d405bSAlexander Yermolovich for (const llvm::object::SectionRef &Section : E.sections()) { 164c87d405bSAlexander Yermolovich Expected<StringRef> SectionNameOrErr = Section.getName(); 165c87d405bSAlexander Yermolovich ASSERT_TRUE(static_cast<bool>(SectionNameOrErr)); 166c87d405bSAlexander Yermolovich StringRef SectionName = *SectionNameOrErr; 167c87d405bSAlexander Yermolovich if (SectionName.empty() || SectionName != ".debug_line_str") 168c87d405bSAlexander Yermolovich continue; 169c87d405bSAlexander Yermolovich Expected<StringRef> ContentsOrErr = Section.getContents(); 170c87d405bSAlexander Yermolovich ASSERT_TRUE(static_cast<bool>(ContentsOrErr)); 171c87d405bSAlexander Yermolovich StringRef Contents = *ContentsOrErr; 172b2e487d1SKazu Hirata ASSERT_TRUE(Contents.contains("dir")); 173b2e487d1SKazu Hirata ASSERT_TRUE(Contents.contains("file")); 174c87d405bSAlexander Yermolovich ASSERT_TRUE(Contents.size() == 9); 175c87d405bSAlexander Yermolovich return; 176c87d405bSAlexander Yermolovich } 177c87d405bSAlexander Yermolovich llvm_unreachable(".debug_line_str not found"); 178c87d405bSAlexander Yermolovich } 179c87d405bSAlexander Yermolovich 180050edef8SMaksim Panchenko /// Open ObjFileData as an object file and read its .debug_line section 181c87d405bSAlexander Yermolovich void readAndCheckDebugContents(StringRef ObjFileData, 182c87d405bSAlexander Yermolovich ArrayRef<uint8_t> Expected, uint8_t DwarfVersion) { 183050edef8SMaksim Panchenko std::unique_ptr<MemoryBuffer> MB = 184050edef8SMaksim Panchenko MemoryBuffer::getMemBuffer(ObjFileData, "", false); 185050edef8SMaksim Panchenko std::unique_ptr<object::Binary> Bin = 186050edef8SMaksim Panchenko cantFail(llvm::object::createBinary(MB->getMemBufferRef())); 187050edef8SMaksim Panchenko if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) { 188c87d405bSAlexander Yermolovich verifyDebugLineContents(*E, Expected); 189c87d405bSAlexander Yermolovich if (DwarfVersion >= 5) 190c87d405bSAlexander Yermolovich verifyDebugLineStrContents(*E); 191c87d405bSAlexander Yermolovich return; 192050edef8SMaksim Panchenko } 193050edef8SMaksim Panchenko llvm_unreachable("ELF object file not found"); 194050edef8SMaksim Panchenko } 195050edef8SMaksim Panchenko }; 196050edef8SMaksim Panchenko } // namespace 197050edef8SMaksim Panchenko 198050edef8SMaksim Panchenko TEST_F(DwarfLineTableHeaders, TestDWARF4HeaderEmission) { 199050edef8SMaksim Panchenko if (!MRI) 2007fc87159SPaul Robinson GTEST_SKIP(); 201050edef8SMaksim Panchenko 202050edef8SMaksim Panchenko SmallString<0> EmittedBinContents; 203050edef8SMaksim Panchenko raw_svector_ostream VecOS(EmittedBinContents); 204050edef8SMaksim Panchenko StreamerContext C = createStreamer(VecOS); 205c87d405bSAlexander Yermolovich constexpr uint8_t DwarfVersion = 4; 206c87d405bSAlexander Yermolovich C.Ctx->setDwarfVersion(DwarfVersion); 207050edef8SMaksim Panchenko emitDebugLineSection(C); 20815d82c62SFangrui Song C.Streamer->finish(); 209c87d405bSAlexander Yermolovich readAndCheckDebugContents( 210050edef8SMaksim Panchenko EmittedBinContents.str(), 211050edef8SMaksim Panchenko {/* Total length=*/0x30, 0, 0, 0, 212c87d405bSAlexander Yermolovich /* DWARF version=*/DwarfVersion, 0, 213050edef8SMaksim Panchenko /* Prologue length=*/0x14, 0, 0, 0, 214050edef8SMaksim Panchenko /* min_inst_length=*/1, 215050edef8SMaksim Panchenko /*max_ops_per_inst=*/1, 216050edef8SMaksim Panchenko /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT, 217050edef8SMaksim Panchenko /* line_base=*/static_cast<uint8_t>(-5), 218050edef8SMaksim Panchenko /* line_range=*/14, 219c87d405bSAlexander Yermolovich /* opcode_base=*/13}, DwarfVersion); 220050edef8SMaksim Panchenko } 221050edef8SMaksim Panchenko 222050edef8SMaksim Panchenko TEST_F(DwarfLineTableHeaders, TestDWARF5HeaderEmission) { 223050edef8SMaksim Panchenko if (!MRI) 2247fc87159SPaul Robinson GTEST_SKIP(); 225050edef8SMaksim Panchenko 226050edef8SMaksim Panchenko SmallString<0> EmittedBinContents; 227050edef8SMaksim Panchenko raw_svector_ostream VecOS(EmittedBinContents); 228050edef8SMaksim Panchenko StreamerContext C = createStreamer(VecOS); 229c87d405bSAlexander Yermolovich constexpr uint8_t DwarfVersion = 5; 230c87d405bSAlexander Yermolovich C.Ctx->setDwarfVersion(DwarfVersion); 231050edef8SMaksim Panchenko emitDebugLineSection(C); 23215d82c62SFangrui Song C.Streamer->finish(); 233c87d405bSAlexander Yermolovich readAndCheckDebugContents( 234050edef8SMaksim Panchenko EmittedBinContents.str(), 235050edef8SMaksim Panchenko {/* Total length=*/0x43, 0, 0, 0, 236c87d405bSAlexander Yermolovich /* DWARF version=*/DwarfVersion, 0, 237050edef8SMaksim Panchenko /* ptr size=*/8, 238050edef8SMaksim Panchenko /* segment=*/0, 239050edef8SMaksim Panchenko /* Prologue length=*/0x25, 0, 0, 0, 240050edef8SMaksim Panchenko /* min_inst_length=*/1, 241050edef8SMaksim Panchenko /*max_ops_per_inst=*/1, 242050edef8SMaksim Panchenko /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT, 243050edef8SMaksim Panchenko /* line_base=*/static_cast<uint8_t>(-5), 244050edef8SMaksim Panchenko /* line_range=*/14, 245c87d405bSAlexander Yermolovich /* opcode_base=*/13}, DwarfVersion); 246050edef8SMaksim Panchenko } 247