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