xref: /llvm-project/llvm/unittests/MC/DwarfLineTableHeaders.cpp (revision b8220b986dcc8c5d0c44a125642009d8175fc11d)
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