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
21using namespace llvm;
22using testing::_;
23using testing::DoAll;
24using testing::InSequence;
25using testing::SaveArg;
26
27namespace {
28
29class 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
38protected:
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
48class AsmPrinterEmitDwarfSymbolReferenceTest : public AsmPrinterFixtureBase {
49protected:
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(Section: ".tst", Type: ELF::SHT_PROGBITS, Flags: 0);
62 SecBeginSymbol = Sec->getBeginSymbol();
63 TestPrinter->getMS().switchSection(Section: Sec);
64 Val->setFragment(&Sec->getDummyFragment());
65
66 return true;
67 }
68
69 MCSymbol *Val = nullptr;
70 MCSymbol *SecBeginSymbol = nullptr;
71};
72
73TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFF) {
74 if (!init(TripleStr: "x86_64-pc-windows", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
75 GTEST_SKIP();
76
77 EXPECT_CALL(TestPrinter->getMS(), emitCOFFSecRel32(Val, 0));
78 TestPrinter->getAP()->emitDwarfSymbolReference(Label: Val, ForceOffset: false);
79}
80
81TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFFForceOffset) {
82 if (!init(TripleStr: "x86_64-pc-windows", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
83 GTEST_SKIP();
84
85 EXPECT_CALL(TestPrinter->getMS(),
86 emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
87 TestPrinter->getAP()->emitDwarfSymbolReference(Label: Val, ForceOffset: true);
88}
89
90TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32) {
91 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
92 GTEST_SKIP();
93
94 const MCExpr *Arg0 = nullptr;
95 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
96 .WillOnce(once_action: SaveArg<0>(pointer: &Arg0));
97 TestPrinter->getAP()->emitDwarfSymbolReference(Label: Val, ForceOffset: false);
98
99 const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Val: Arg0);
100 ASSERT_NE(ActualArg0, nullptr);
101 EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
102}
103
104TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32ForceOffset) {
105 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
106 GTEST_SKIP();
107
108 EXPECT_CALL(TestPrinter->getMS(),
109 emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
110 TestPrinter->getAP()->emitDwarfSymbolReference(Label: Val, ForceOffset: true);
111}
112
113TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64) {
114 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF64))
115 GTEST_SKIP();
116
117 const MCExpr *Arg0 = nullptr;
118 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
119 .WillOnce(once_action: SaveArg<0>(pointer: &Arg0));
120 TestPrinter->getAP()->emitDwarfSymbolReference(Label: Val, ForceOffset: false);
121
122 const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Val: Arg0);
123 ASSERT_NE(ActualArg0, nullptr);
124 EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
125}
126
127TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64ForceOffset) {
128 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF64))
129 GTEST_SKIP();
130
131 EXPECT_CALL(TestPrinter->getMS(),
132 emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 8));
133 TestPrinter->getAP()->emitDwarfSymbolReference(Label: Val, ForceOffset: true);
134}
135
136class AsmPrinterEmitDwarfStringOffsetTest : public AsmPrinterFixtureBase {
137protected:
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
152TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF32) {
153 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
154 GTEST_SKIP();
155
156 const MCExpr *Arg0 = nullptr;
157 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
158 .WillOnce(once_action: SaveArg<0>(pointer: &Arg0));
159 TestPrinter->getAP()->emitDwarfStringOffset(S: Val);
160
161 const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Val: Arg0);
162 ASSERT_NE(ActualArg0, nullptr);
163 EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
164}
165
166TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
167 DWARF32NoRelocationsAcrossSections) {
168 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
169 GTEST_SKIP();
170
171 TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
172 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 4));
173 TestPrinter->getAP()->emitDwarfStringOffset(S: Val);
174}
175
176TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF64) {
177 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF64))
178 GTEST_SKIP();
179
180 const MCExpr *Arg0 = nullptr;
181 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
182 .WillOnce(once_action: SaveArg<0>(pointer: &Arg0));
183 TestPrinter->getAP()->emitDwarfStringOffset(S: Val);
184
185 const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Val: Arg0);
186 ASSERT_NE(ActualArg0, nullptr);
187 EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
188}
189
190TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
191 DWARF64NoRelocationsAcrossSections) {
192 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF64))
193 GTEST_SKIP();
194
195 TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
196 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 8));
197 TestPrinter->getAP()->emitDwarfStringOffset(S: Val);
198}
199
200class AsmPrinterEmitDwarfOffsetTest : public AsmPrinterFixtureBase {
201protected:
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
215TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF32) {
216 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
217 GTEST_SKIP();
218
219 const MCExpr *Arg0 = nullptr;
220 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
221 .WillOnce(once_action: SaveArg<0>(pointer: &Arg0));
222 TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
223
224 const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Val: Arg0);
225 ASSERT_NE(ActualArg0, nullptr);
226 EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
227
228 const MCSymbolRefExpr *ActualLHS =
229 dyn_cast_or_null<MCSymbolRefExpr>(Val: ActualArg0->getLHS());
230 ASSERT_NE(ActualLHS, nullptr);
231 EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
232
233 const MCConstantExpr *ActualRHS =
234 dyn_cast_or_null<MCConstantExpr>(Val: ActualArg0->getRHS());
235 ASSERT_NE(ActualRHS, nullptr);
236 EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
237}
238
239TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF64) {
240 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF64))
241 GTEST_SKIP();
242
243 const MCExpr *Arg0 = nullptr;
244 EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
245 .WillOnce(once_action: SaveArg<0>(pointer: &Arg0));
246 TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
247
248 const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Val: Arg0);
249 ASSERT_NE(ActualArg0, nullptr);
250 EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
251
252 const MCSymbolRefExpr *ActualLHS =
253 dyn_cast_or_null<MCSymbolRefExpr>(Val: ActualArg0->getLHS());
254 ASSERT_NE(ActualLHS, nullptr);
255 EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
256
257 const MCConstantExpr *ActualRHS =
258 dyn_cast_or_null<MCConstantExpr>(Val: ActualArg0->getRHS());
259 ASSERT_NE(ActualRHS, nullptr);
260 EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
261}
262
263class AsmPrinterEmitDwarfLengthOrOffsetTest : public AsmPrinterFixtureBase {
264protected:
265 uint64_t Val = 42;
266};
267
268TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF32) {
269 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
270 GTEST_SKIP();
271
272 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
273 TestPrinter->getAP()->emitDwarfLengthOrOffset(Value: Val);
274}
275
276TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF64) {
277 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF64))
278 GTEST_SKIP();
279
280 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
281 TestPrinter->getAP()->emitDwarfLengthOrOffset(Value: Val);
282}
283
284class AsmPrinterGetUnitLengthFieldByteSizeTest : public AsmPrinterFixtureBase {
285};
286
287TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF32) {
288 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
289 GTEST_SKIP();
290
291 EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 4u);
292}
293
294TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF64) {
295 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF64))
296 GTEST_SKIP();
297
298 EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 12u);
299}
300
301class AsmPrinterEmitDwarfUnitLengthAsIntTest : public AsmPrinterFixtureBase {
302protected:
303 uint64_t Val = 42;
304};
305
306TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF32) {
307 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
308 GTEST_SKIP();
309
310 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
311 TestPrinter->getAP()->emitDwarfUnitLength(Length: Val, Comment: "");
312}
313
314TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF64) {
315 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: 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(Length: Val, Comment: "");
323}
324
325class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
326 : public AsmPrinterFixtureBase {
327protected:
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
337TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF32) {
338 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: 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(once_action: DoAll(action: SaveArg<0>(pointer: &Hi), action: SaveArg<1>(pointer: &Lo)));
346 MCSymbol *LTmp = nullptr;
347 EXPECT_CALL(TestPrinter->getMS(), emitLabel(_, _))
348 .WillOnce(once_action: SaveArg<0>(pointer: &LTmp));
349
350 MCSymbol *HTmp = TestPrinter->getAP()->emitDwarfUnitLength(Prefix: "", Comment: "");
351 EXPECT_NE(Lo, nullptr);
352 EXPECT_EQ(Lo, LTmp);
353 EXPECT_NE(Hi, nullptr);
354 EXPECT_EQ(Hi, HTmp);
355}
356
357TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF64) {
358 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: 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(once_action: DoAll(action: SaveArg<0>(pointer: &Hi), action: SaveArg<1>(pointer: &Lo)));
367 MCSymbol *LTmp = nullptr;
368 EXPECT_CALL(TestPrinter->getMS(), emitLabel(_, _))
369 .WillOnce(once_action: SaveArg<0>(pointer: &LTmp));
370
371 MCSymbol *HTmp = TestPrinter->getAP()->emitDwarfUnitLength(Prefix: "", Comment: "");
372 EXPECT_NE(Lo, nullptr);
373 EXPECT_EQ(Lo, LTmp);
374 EXPECT_NE(Hi, nullptr);
375 EXPECT_EQ(Hi, HTmp);
376}
377
378class 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
394protected:
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(Handler: 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(P: new MachineModuleInfoWrapperPass(LLVMTM));
407 PM.add(P: 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&: *M);
412 // Now check that we can run it twice.
413 AP->addAsmPrinterHandler(Handler: AsmPrinter::HandlerInfo(
414 std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
415 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
416 PM.run(M&: *M);
417 return true;
418 }
419
420 int BeginCount = 0;
421 int EndCount = 0;
422};
423
424TEST_F(AsmPrinterHandlerTest, Basic) {
425 if (!init(TripleStr: "x86_64-pc-linux", /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32))
426 GTEST_SKIP();
427
428 ASSERT_EQ(BeginCount, 3);
429 ASSERT_EQ(EndCount, 3);
430}
431
432} // end namespace
433

source code of llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp