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