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