1 //===- llvm/unittest/CodeGen/AsmPrinterDwarfTest.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 //===----------------------------------------------------------------------===//
8
9 #include "TestAsmPrinter.h"
10 #include "llvm/CodeGen/AsmPrinter.h"
11 #include "llvm/CodeGen/MachineModuleInfo.h"
12 #include "llvm/IR/LegacyPassManager.h"
13 #include "llvm/IR/Module.h"
14 #include "llvm/IR/PassManager.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCSectionELF.h"
17 #include "llvm/Target/TargetMachine.h"
18 #include "llvm/Testing/Support/Error.h"
19
20 using namespace llvm;
21 using testing::_;
22 using testing::InSequence;
23 using testing::SaveArg;
24
25 namespace {
26
27 class AsmPrinterFixtureBase : public testing::Test {
setupTestPrinter(const std::string & TripleStr,unsigned DwarfVersion,dwarf::DwarfFormat DwarfFormat)28 void setupTestPrinter(const std::string &TripleStr, unsigned DwarfVersion,
29 dwarf::DwarfFormat DwarfFormat) {
30 auto ExpectedTestPrinter =
31 TestAsmPrinter::create(TripleStr, DwarfVersion, DwarfFormat);
32 ASSERT_THAT_EXPECTED(ExpectedTestPrinter, Succeeded());
33 TestPrinter = std::move(ExpectedTestPrinter.get());
34 }
35
36 protected:
init(const std::string & TripleStr,unsigned DwarfVersion,dwarf::DwarfFormat DwarfFormat)37 bool init(const std::string &TripleStr, unsigned DwarfVersion,
38 dwarf::DwarfFormat DwarfFormat) {
39 setupTestPrinter(TripleStr, DwarfVersion, DwarfFormat);
40 return TestPrinter != nullptr;
41 }
42
43 std::unique_ptr<TestAsmPrinter> TestPrinter;
44 };
45
46 class AsmPrinterEmitDwarfSymbolReferenceTest : public AsmPrinterFixtureBase {
47 protected:
init(const std::string & TripleStr,unsigned DwarfVersion,dwarf::DwarfFormat DwarfFormat)48 bool init(const std::string &TripleStr, unsigned DwarfVersion,
49 dwarf::DwarfFormat DwarfFormat) {
50 if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
51 return false;
52
53 // Create a symbol which will be emitted in the tests and associate it
54 // with a section because that is required in some code paths.
55
56 Val = TestPrinter->getCtx().createTempSymbol();
57 Sec = TestPrinter->getCtx().getELFSection(".tst", ELF::SHT_PROGBITS, 0);
58 SecBeginSymbol = Sec->getBeginSymbol();
59 TestPrinter->getMS().SwitchSection(Sec);
60 TestPrinter->getMS().emitLabel(Val);
61 return true;
62 }
63
64 MCSymbol *Val = nullptr;
65 MCSection *Sec = nullptr;
66 MCSymbol *SecBeginSymbol = nullptr;
67 };
68
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest,COFF)69 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFF) {
70 if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32))
71 return;
72
73 EXPECT_CALL(TestPrinter->getMS(), EmitCOFFSecRel32(Val, 0));
74 TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
75 }
76
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest,COFFForceOffset)77 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFFForceOffset) {
78 if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32))
79 return;
80
81 EXPECT_CALL(TestPrinter->getMS(),
82 emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
83 TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
84 }
85
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest,ELFDWARF32)86 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32) {
87 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
88 return;
89
90 const MCExpr *Arg0 = nullptr;
91 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
92 .WillOnce(SaveArg<0>(&Arg0));
93 TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
94
95 const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
96 ASSERT_NE(ActualArg0, nullptr);
97 EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
98 }
99
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest,ELFDWARF32ForceOffset)100 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32ForceOffset) {
101 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
102 return;
103
104 EXPECT_CALL(TestPrinter->getMS(),
105 emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
106 TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
107 }
108
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest,ELFDWARF64)109 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64) {
110 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
111 return;
112
113 const MCExpr *Arg0 = nullptr;
114 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
115 .WillOnce(SaveArg<0>(&Arg0));
116 TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
117
118 const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
119 ASSERT_NE(ActualArg0, nullptr);
120 EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
121 }
122
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest,ELFDWARF64ForceOffset)123 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64ForceOffset) {
124 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
125 return;
126
127 EXPECT_CALL(TestPrinter->getMS(),
128 emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 8));
129 TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
130 }
131
132 class AsmPrinterEmitDwarfStringOffsetTest : public AsmPrinterFixtureBase {
133 protected:
init(const std::string & TripleStr,unsigned DwarfVersion,dwarf::DwarfFormat DwarfFormat)134 bool init(const std::string &TripleStr, unsigned DwarfVersion,
135 dwarf::DwarfFormat DwarfFormat) {
136 if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
137 return false;
138
139 Val.Index = DwarfStringPoolEntry::NotIndexed;
140 Val.Symbol = TestPrinter->getCtx().createTempSymbol();
141 Val.Offset = 42;
142 return true;
143 }
144
145 DwarfStringPoolEntry Val;
146 };
147
TEST_F(AsmPrinterEmitDwarfStringOffsetTest,DWARF32)148 TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF32) {
149 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
150 return;
151
152 const MCExpr *Arg0 = nullptr;
153 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
154 .WillOnce(SaveArg<0>(&Arg0));
155 TestPrinter->getAP()->emitDwarfStringOffset(Val);
156
157 const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
158 ASSERT_NE(ActualArg0, nullptr);
159 EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
160 }
161
TEST_F(AsmPrinterEmitDwarfStringOffsetTest,DWARF32NoRelocationsAcrossSections)162 TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
163 DWARF32NoRelocationsAcrossSections) {
164 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
165 return;
166
167 TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
168 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 4));
169 TestPrinter->getAP()->emitDwarfStringOffset(Val);
170 }
171
TEST_F(AsmPrinterEmitDwarfStringOffsetTest,DWARF64)172 TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF64) {
173 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
174 return;
175
176 const MCExpr *Arg0 = nullptr;
177 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
178 .WillOnce(SaveArg<0>(&Arg0));
179 TestPrinter->getAP()->emitDwarfStringOffset(Val);
180
181 const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
182 ASSERT_NE(ActualArg0, nullptr);
183 EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
184 }
185
TEST_F(AsmPrinterEmitDwarfStringOffsetTest,DWARF64NoRelocationsAcrossSections)186 TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
187 DWARF64NoRelocationsAcrossSections) {
188 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
189 return;
190
191 TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
192 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 8));
193 TestPrinter->getAP()->emitDwarfStringOffset(Val);
194 }
195
196 class AsmPrinterEmitDwarfOffsetTest : public AsmPrinterFixtureBase {
197 protected:
init(const std::string & TripleStr,unsigned DwarfVersion,dwarf::DwarfFormat DwarfFormat)198 bool init(const std::string &TripleStr, unsigned DwarfVersion,
199 dwarf::DwarfFormat DwarfFormat) {
200 if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
201 return false;
202
203 Label = TestPrinter->getCtx().createTempSymbol();
204 return true;
205 }
206
207 MCSymbol *Label = nullptr;
208 uint64_t Offset = 42;
209 };
210
TEST_F(AsmPrinterEmitDwarfOffsetTest,DWARF32)211 TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF32) {
212 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
213 return;
214
215 const MCExpr *Arg0 = nullptr;
216 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
217 .WillOnce(SaveArg<0>(&Arg0));
218 TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
219
220 const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Arg0);
221 ASSERT_NE(ActualArg0, nullptr);
222 EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
223
224 const MCSymbolRefExpr *ActualLHS =
225 dyn_cast_or_null<MCSymbolRefExpr>(ActualArg0->getLHS());
226 ASSERT_NE(ActualLHS, nullptr);
227 EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
228
229 const MCConstantExpr *ActualRHS =
230 dyn_cast_or_null<MCConstantExpr>(ActualArg0->getRHS());
231 ASSERT_NE(ActualRHS, nullptr);
232 EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
233 }
234
TEST_F(AsmPrinterEmitDwarfOffsetTest,DWARF64)235 TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF64) {
236 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
237 return;
238
239 const MCExpr *Arg0 = nullptr;
240 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
241 .WillOnce(SaveArg<0>(&Arg0));
242 TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
243
244 const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Arg0);
245 ASSERT_NE(ActualArg0, nullptr);
246 EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
247
248 const MCSymbolRefExpr *ActualLHS =
249 dyn_cast_or_null<MCSymbolRefExpr>(ActualArg0->getLHS());
250 ASSERT_NE(ActualLHS, nullptr);
251 EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
252
253 const MCConstantExpr *ActualRHS =
254 dyn_cast_or_null<MCConstantExpr>(ActualArg0->getRHS());
255 ASSERT_NE(ActualRHS, nullptr);
256 EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
257 }
258
259 class AsmPrinterEmitDwarfLengthOrOffsetTest : public AsmPrinterFixtureBase {
260 protected:
261 uint64_t Val = 42;
262 };
263
TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest,DWARF32)264 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF32) {
265 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
266 return;
267
268 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
269 TestPrinter->getAP()->emitDwarfLengthOrOffset(Val);
270 }
271
TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest,DWARF64)272 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF64) {
273 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
274 return;
275
276 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
277 TestPrinter->getAP()->emitDwarfLengthOrOffset(Val);
278 }
279
280 class AsmPrinterGetUnitLengthFieldByteSizeTest : public AsmPrinterFixtureBase {
281 };
282
TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest,DWARF32)283 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF32) {
284 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
285 return;
286
287 EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 4u);
288 }
289
TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest,DWARF64)290 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF64) {
291 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
292 return;
293
294 EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 12u);
295 }
296
297 class AsmPrinterMaybeEmitDwarf64MarkTest : public AsmPrinterFixtureBase {};
298
TEST_F(AsmPrinterMaybeEmitDwarf64MarkTest,DWARF32)299 TEST_F(AsmPrinterMaybeEmitDwarf64MarkTest, DWARF32) {
300 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
301 return;
302
303 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(_, _)).Times(0);
304 TestPrinter->getAP()->maybeEmitDwarf64Mark();
305 }
306
TEST_F(AsmPrinterMaybeEmitDwarf64MarkTest,DWARF64)307 TEST_F(AsmPrinterMaybeEmitDwarf64MarkTest, DWARF64) {
308 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
309 return;
310
311 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
312 TestPrinter->getAP()->maybeEmitDwarf64Mark();
313 }
314
315 class AsmPrinterEmitDwarfUnitLengthAsIntTest : public AsmPrinterFixtureBase {
316 protected:
317 uint64_t Val = 42;
318 };
319
TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest,DWARF32)320 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF32) {
321 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
322 return;
323
324 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
325 TestPrinter->getAP()->emitDwarfUnitLength(Val, "");
326 }
327
TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest,DWARF64)328 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF64) {
329 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
330 return;
331
332 InSequence S;
333 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
334 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
335
336 TestPrinter->getAP()->emitDwarfUnitLength(Val, "");
337 }
338
339 class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
340 : public AsmPrinterFixtureBase {
341 protected:
init(const std::string & TripleStr,unsigned DwarfVersion,dwarf::DwarfFormat DwarfFormat)342 bool init(const std::string &TripleStr, unsigned DwarfVersion,
343 dwarf::DwarfFormat DwarfFormat) {
344 if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
345 return false;
346
347 Hi = TestPrinter->getCtx().createTempSymbol();
348 Lo = TestPrinter->getCtx().createTempSymbol();
349 return true;
350 }
351
352 MCSymbol *Hi = nullptr;
353 MCSymbol *Lo = nullptr;
354 };
355
TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest,DWARF32)356 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF32) {
357 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
358 return;
359
360 EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 4));
361 TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, "");
362 }
363
TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest,DWARF64)364 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF64) {
365 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
366 return;
367
368 InSequence S;
369 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
370 EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 8));
371
372 TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, "");
373 }
374
375 class AsmPrinterHandlerTest : public AsmPrinterFixtureBase {
376 class TestHandler : public AsmPrinterHandler {
377 AsmPrinterHandlerTest &Test;
378
379 public:
TestHandler(AsmPrinterHandlerTest & Test)380 TestHandler(AsmPrinterHandlerTest &Test) : Test(Test) {}
~TestHandler()381 virtual ~TestHandler() {}
setSymbolSize(const MCSymbol * Sym,uint64_t Size)382 virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {}
beginModule(Module * M)383 virtual void beginModule(Module *M) override { Test.BeginCount++; }
endModule()384 virtual void endModule() override { Test.EndCount++; }
beginFunction(const MachineFunction * MF)385 virtual void beginFunction(const MachineFunction *MF) override {}
endFunction(const MachineFunction * MF)386 virtual void endFunction(const MachineFunction *MF) override {}
beginInstruction(const MachineInstr * MI)387 virtual void beginInstruction(const MachineInstr *MI) override {}
endInstruction()388 virtual void endInstruction() override {}
389 };
390
391 protected:
init(const std::string & TripleStr,unsigned DwarfVersion,dwarf::DwarfFormat DwarfFormat)392 bool init(const std::string &TripleStr, unsigned DwarfVersion,
393 dwarf::DwarfFormat DwarfFormat) {
394 if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
395 return false;
396
397 auto *AP = TestPrinter->getAP();
398 AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
399 std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
400 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
401 LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(&AP->TM);
402 legacy::PassManager PM;
403 PM.add(new MachineModuleInfoWrapperPass(LLVMTM));
404 PM.add(TestPrinter->releaseAP()); // Takes ownership of destroying AP
405 LLVMContext Context;
406 std::unique_ptr<Module> M(new Module("TestModule", Context));
407 M->setDataLayout(LLVMTM->createDataLayout());
408 PM.run(*M);
409 // Now check that we can run it twice.
410 AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
411 std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
412 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
413 PM.run(*M);
414 return true;
415 }
416
417 int BeginCount = 0;
418 int EndCount = 0;
419 };
420
TEST_F(AsmPrinterHandlerTest,Basic)421 TEST_F(AsmPrinterHandlerTest, Basic) {
422 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
423 return;
424
425 ASSERT_EQ(BeginCount, 3);
426 ASSERT_EQ(EndCount, 3);
427 }
428
429 } // end namespace
430