Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / unittests / MC / DwarfLineTableHeaders.cpp
blob1fad1ba6ce638d3e5cd4fb83683a0bfebba27c19
1 //===- llvm/unittest/MC/DwarfLineTableHeaders.cpp -------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/STLExtras.h"
10 #include "llvm/BinaryFormat/Dwarf.h"
11 #include "llvm/MC/MCAsmBackend.h"
12 #include "llvm/MC/MCAsmInfo.h"
13 #include "llvm/MC/MCAssembler.h"
14 #include "llvm/MC/MCCodeEmitter.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCDwarf.h"
17 #include "llvm/MC/MCInstrInfo.h"
18 #include "llvm/MC/MCObjectStreamer.h"
19 #include "llvm/MC/MCObjectWriter.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/MC/MCStreamer.h"
22 #include "llvm/MC/MCSubtargetInfo.h"
23 #include "llvm/MC/MCTargetOptions.h"
24 #include "llvm/MC/TargetRegistry.h"
25 #include "llvm/Object/Binary.h"
26 #include "llvm/Object/ELFObjectFile.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/MemoryBuffer.h"
29 #include "llvm/Support/TargetSelect.h"
30 #include "llvm/Support/ToolOutputFile.h"
31 #include "gtest/gtest.h"
33 using namespace llvm;
35 namespace {
37 class DwarfLineTableHeaders : public ::testing::Test {
38 public:
39 const char *TripleName = "x86_64-pc-linux";
40 std::unique_ptr<MCRegisterInfo> MRI;
41 std::unique_ptr<MCAsmInfo> MAI;
42 std::unique_ptr<const MCSubtargetInfo> STI;
43 const Target *TheTarget;
45 struct StreamerContext {
46 std::unique_ptr<MCObjectFileInfo> MOFI;
47 std::unique_ptr<MCContext> Ctx;
48 std::unique_ptr<const MCInstrInfo> MII;
49 std::unique_ptr<MCStreamer> Streamer;
52 DwarfLineTableHeaders() {
53 llvm::InitializeAllTargetInfos();
54 llvm::InitializeAllTargetMCs();
55 llvm::InitializeAllDisassemblers();
57 // If we didn't build x86, do not run the test.
58 std::string Error;
59 TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
60 if (!TheTarget)
61 return;
63 MRI.reset(TheTarget->createMCRegInfo(TripleName));
64 MCTargetOptions MCOptions;
65 MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
66 STI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
69 /// Create all data structures necessary to operate an assembler
70 StreamerContext createStreamer(raw_pwrite_stream &OS) {
71 StreamerContext Res;
72 Res.Ctx =
73 std::make_unique<MCContext>(Triple(TripleName), MAI.get(), MRI.get(),
74 /*MSTI=*/nullptr);
75 Res.MOFI.reset(TheTarget->createMCObjectFileInfo(*Res.Ctx,
76 /*PIC=*/false));
77 Res.Ctx->setObjectFileInfo(Res.MOFI.get());
79 Res.MII.reset(TheTarget->createMCInstrInfo());
80 MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*Res.MII, *Res.Ctx);
81 MCAsmBackend *MAB =
82 TheTarget->createMCAsmBackend(*STI, *MRI, MCTargetOptions());
83 std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(OS);
84 Res.Streamer.reset(TheTarget->createMCObjectStreamer(
85 Triple(TripleName), *Res.Ctx, std::unique_ptr<MCAsmBackend>(MAB),
86 std::move(OW), std::unique_ptr<MCCodeEmitter>(MCE), *STI));
87 return Res;
90 /// Emit a .debug_line section with the given context parameters
91 void emitDebugLineSection(StreamerContext &C) {
92 MCContext &Ctx = *C.Ctx;
93 MCStreamer *TheStreamer = C.Streamer.get();
94 MCAssembler &Assembler =
95 static_cast<MCObjectStreamer *>(TheStreamer)->getAssembler();
96 TheStreamer->initSections(false, *STI);
98 // Create a mock function
99 MCSection *Section = C.MOFI->getTextSection();
100 Section->setHasInstructions(true);
101 TheStreamer->switchSection(Section);
102 TheStreamer->emitCFIStartProc(true);
104 // Create a mock dwarfloc
105 Ctx.setCurrentDwarfLoc(/*FileNo=*/0, /*Line=*/1, /*Column=*/1, /*Flags=*/0,
106 /*Isa=*/0, /*Discriminator=*/0);
107 MCDwarfLoc Loc = Ctx.getCurrentDwarfLoc();
108 MCSymbol *LineSym = Ctx.createTempSymbol();
109 // Set the value of the symbol to use for the MCDwarfLineEntry.
110 TheStreamer->emitLabel(LineSym);
111 TheStreamer->emitNops(4, 1, SMLoc(), *STI);
112 TheStreamer->emitCFIEndProc();
114 // Start emission of .debug_line
115 TheStreamer->switchSection(C.MOFI->getDwarfLineSection());
116 MCDwarfLineTableHeader Header;
117 MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams();
118 std::optional<MCDwarfLineStr> LineStr(std::nullopt);
119 if (Ctx.getDwarfVersion() >= 5) {
120 LineStr.emplace(Ctx);
121 Header.setRootFile("dir", "file", std::nullopt, std::nullopt);
123 MCSymbol *LineEndSym = Header.Emit(TheStreamer, Params, LineStr).second;
125 // Put out the line tables.
126 MCLineSection::MCDwarfLineEntryCollection LineEntries;
127 MCDwarfLineEntry LineEntry(LineSym, Loc);
128 LineEntries.push_back(LineEntry);
129 MCDwarfLineTable::emitOne(TheStreamer, Section, LineEntries);
130 TheStreamer->emitLabel(LineEndSym);
131 if (LineStr) {
132 SmallString<0> Data = LineStr->getFinalizedData();
133 TheStreamer->switchSection(TheStreamer->getContext()
134 .getObjectFileInfo()
135 ->getDwarfLineStrSection());
136 TheStreamer->emitBinaryData(Data.str());
140 /// Check contents of .debug_line section
141 void verifyDebugLineContents(const llvm::object::ObjectFile &E,
142 ArrayRef<uint8_t> ExpectedEncoding) {
143 for (const llvm::object::SectionRef &Section : E.sections()) {
144 Expected<StringRef> SectionNameOrErr = Section.getName();
145 ASSERT_TRUE(static_cast<bool>(SectionNameOrErr));
146 StringRef SectionName = *SectionNameOrErr;
147 if (SectionName.empty() || SectionName != ".debug_line")
148 continue;
149 Expected<StringRef> ContentsOrErr = Section.getContents();
150 ASSERT_TRUE(static_cast<bool>(ContentsOrErr));
151 StringRef Contents = *ContentsOrErr;
152 ASSERT_TRUE(Contents.size() > ExpectedEncoding.size());
153 EXPECT_EQ(
154 arrayRefFromStringRef(Contents.slice(0, ExpectedEncoding.size())),
155 ExpectedEncoding);
156 return;
158 llvm_unreachable(".debug_line not found");
161 /// Check contents of .debug_line_str section
162 void verifyDebugLineStrContents(const llvm::object::ObjectFile &E) {
163 for (const llvm::object::SectionRef &Section : E.sections()) {
164 Expected<StringRef> SectionNameOrErr = Section.getName();
165 ASSERT_TRUE(static_cast<bool>(SectionNameOrErr));
166 StringRef SectionName = *SectionNameOrErr;
167 if (SectionName.empty() || SectionName != ".debug_line_str")
168 continue;
169 Expected<StringRef> ContentsOrErr = Section.getContents();
170 ASSERT_TRUE(static_cast<bool>(ContentsOrErr));
171 StringRef Contents = *ContentsOrErr;
172 ASSERT_TRUE(Contents.contains("dir"));
173 ASSERT_TRUE(Contents.contains("file"));
174 ASSERT_TRUE(Contents.size() == 9);
175 return;
177 llvm_unreachable(".debug_line_str not found");
180 /// Open ObjFileData as an object file and read its .debug_line section
181 void readAndCheckDebugContents(StringRef ObjFileData,
182 ArrayRef<uint8_t> Expected, uint8_t DwarfVersion) {
183 std::unique_ptr<MemoryBuffer> MB =
184 MemoryBuffer::getMemBuffer(ObjFileData, "", false);
185 std::unique_ptr<object::Binary> Bin =
186 cantFail(llvm::object::createBinary(MB->getMemBufferRef()));
187 if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) {
188 verifyDebugLineContents(*E, Expected);
189 if (DwarfVersion >= 5)
190 verifyDebugLineStrContents(*E);
191 return;
193 llvm_unreachable("ELF object file not found");
196 } // namespace
198 TEST_F(DwarfLineTableHeaders, TestDWARF4HeaderEmission) {
199 if (!MRI)
200 GTEST_SKIP();
202 SmallString<0> EmittedBinContents;
203 raw_svector_ostream VecOS(EmittedBinContents);
204 StreamerContext C = createStreamer(VecOS);
205 constexpr uint8_t DwarfVersion = 4;
206 C.Ctx->setDwarfVersion(DwarfVersion);
207 emitDebugLineSection(C);
208 C.Streamer->finish();
209 readAndCheckDebugContents(
210 EmittedBinContents.str(),
211 {/* Total length=*/0x30, 0, 0, 0,
212 /* DWARF version=*/DwarfVersion, 0,
213 /* Prologue length=*/0x14, 0, 0, 0,
214 /* min_inst_length=*/1,
215 /*max_ops_per_inst=*/1,
216 /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT,
217 /* line_base=*/static_cast<uint8_t>(-5),
218 /* line_range=*/14,
219 /* opcode_base=*/13}, DwarfVersion);
222 TEST_F(DwarfLineTableHeaders, TestDWARF5HeaderEmission) {
223 if (!MRI)
224 GTEST_SKIP();
226 SmallString<0> EmittedBinContents;
227 raw_svector_ostream VecOS(EmittedBinContents);
228 StreamerContext C = createStreamer(VecOS);
229 constexpr uint8_t DwarfVersion = 5;
230 C.Ctx->setDwarfVersion(DwarfVersion);
231 emitDebugLineSection(C);
232 C.Streamer->finish();
233 readAndCheckDebugContents(
234 EmittedBinContents.str(),
235 {/* Total length=*/0x43, 0, 0, 0,
236 /* DWARF version=*/DwarfVersion, 0,
237 /* ptr size=*/8,
238 /* segment=*/0,
239 /* Prologue length=*/0x25, 0, 0, 0,
240 /* min_inst_length=*/1,
241 /*max_ops_per_inst=*/1,
242 /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT,
243 /* line_base=*/static_cast<uint8_t>(-5),
244 /* line_range=*/14,
245 /* opcode_base=*/13}, DwarfVersion);