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