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