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