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>(<mp)); 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>(<mp)); 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