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