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