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 AsmPrinterEmitDwarfUnitLengthAsIntTest : public AsmPrinterFixtureBase { 298 protected: 299 uint64_t Val = 42; 300 }; 301 302 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF32) { 303 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) 304 return; 305 306 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4)); 307 TestPrinter->getAP()->emitDwarfUnitLength(Val, ""); 308 } 309 310 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF64) { 311 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) 312 return; 313 314 InSequence S; 315 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4)); 316 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8)); 317 318 TestPrinter->getAP()->emitDwarfUnitLength(Val, ""); 319 } 320 321 class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest 322 : public AsmPrinterFixtureBase { 323 protected: 324 bool init(const std::string &TripleStr, unsigned DwarfVersion, 325 dwarf::DwarfFormat DwarfFormat) { 326 if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat)) 327 return false; 328 329 Hi = TestPrinter->getCtx().createTempSymbol(); 330 Lo = TestPrinter->getCtx().createTempSymbol(); 331 return true; 332 } 333 334 MCSymbol *Hi = nullptr; 335 MCSymbol *Lo = nullptr; 336 }; 337 338 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF32) { 339 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) 340 return; 341 342 EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 4)); 343 TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, ""); 344 } 345 346 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF64) { 347 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) 348 return; 349 350 InSequence S; 351 EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4)); 352 EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 8)); 353 354 TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, ""); 355 } 356 357 class AsmPrinterHandlerTest : public AsmPrinterFixtureBase { 358 class TestHandler : public AsmPrinterHandler { 359 AsmPrinterHandlerTest &Test; 360 361 public: 362 TestHandler(AsmPrinterHandlerTest &Test) : Test(Test) {} 363 virtual ~TestHandler() {} 364 virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} 365 virtual void beginModule(Module *M) override { Test.BeginCount++; } 366 virtual void endModule() override { Test.EndCount++; } 367 virtual void beginFunction(const MachineFunction *MF) override {} 368 virtual void endFunction(const MachineFunction *MF) override {} 369 virtual void beginInstruction(const MachineInstr *MI) override {} 370 virtual void endInstruction() override {} 371 }; 372 373 protected: 374 bool init(const std::string &TripleStr, unsigned DwarfVersion, 375 dwarf::DwarfFormat DwarfFormat) { 376 if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat)) 377 return false; 378 379 auto *AP = TestPrinter->getAP(); 380 AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo( 381 std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)), 382 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc")); 383 LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(&AP->TM); 384 legacy::PassManager PM; 385 PM.add(new MachineModuleInfoWrapperPass(LLVMTM)); 386 PM.add(TestPrinter->releaseAP()); // Takes ownership of destroying AP 387 LLVMContext Context; 388 std::unique_ptr<Module> M(new Module("TestModule", Context)); 389 M->setDataLayout(LLVMTM->createDataLayout()); 390 PM.run(*M); 391 // Now check that we can run it twice. 392 AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo( 393 std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)), 394 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc")); 395 PM.run(*M); 396 return true; 397 } 398 399 int BeginCount = 0; 400 int EndCount = 0; 401 }; 402 403 TEST_F(AsmPrinterHandlerTest, Basic) { 404 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) 405 return; 406 407 ASSERT_EQ(BeginCount, 3); 408 ASSERT_EQ(EndCount, 3); 409 } 410 411 } // end namespace 412