//===- llvm/unittest/CodeGen/AsmPrinterDwarfTest.cpp ----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "TestAsmPrinter.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Testing/Support/Error.h" using namespace llvm; using testing::_; using testing::InSequence; using testing::SaveArg; namespace { class AsmPrinterFixtureBase : public testing::Test { void setupTestPrinter(const std::string &TripleStr, unsigned DwarfVersion, dwarf::DwarfFormat DwarfFormat) { auto ExpectedTestPrinter = TestAsmPrinter::create(TripleStr, DwarfVersion, DwarfFormat); ASSERT_THAT_EXPECTED(ExpectedTestPrinter, Succeeded()); TestPrinter = std::move(ExpectedTestPrinter.get()); } protected: bool init(const std::string &TripleStr, unsigned DwarfVersion, dwarf::DwarfFormat DwarfFormat) { setupTestPrinter(TripleStr, DwarfVersion, DwarfFormat); return TestPrinter != nullptr; } std::unique_ptr TestPrinter; }; class AsmPrinterEmitDwarfSymbolReferenceTest : public AsmPrinterFixtureBase { protected: bool init(const std::string &TripleStr, unsigned DwarfVersion, dwarf::DwarfFormat DwarfFormat) { if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat)) return false; // Create a symbol which will be emitted in the tests and associate it // with a section because that is required in some code paths. Val = TestPrinter->getCtx().createTempSymbol(); Sec = TestPrinter->getCtx().getELFSection(".tst", ELF::SHT_PROGBITS, 0); SecBeginSymbol = Sec->getBeginSymbol(); TestPrinter->getMS().SwitchSection(Sec); TestPrinter->getMS().emitLabel(Val); return true; } MCSymbol *Val = nullptr; MCSection *Sec = nullptr; MCSymbol *SecBeginSymbol = nullptr; }; TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFF) { if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32)) return; EXPECT_CALL(TestPrinter->getMS(), EmitCOFFSecRel32(Val, 0)); TestPrinter->getAP()->emitDwarfSymbolReference(Val, false); } TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFFForceOffset) { if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32)) return; EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4)); TestPrinter->getAP()->emitDwarfSymbolReference(Val, true); } TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; const MCExpr *Arg0 = nullptr; EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _)) .WillOnce(SaveArg<0>(&Arg0)); TestPrinter->getAP()->emitDwarfSymbolReference(Val, false); const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null(Arg0); ASSERT_NE(ActualArg0, nullptr); EXPECT_EQ(&(ActualArg0->getSymbol()), Val); } TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32ForceOffset) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4)); TestPrinter->getAP()->emitDwarfSymbolReference(Val, true); } TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; const MCExpr *Arg0 = nullptr; EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _)) .WillOnce(SaveArg<0>(&Arg0)); TestPrinter->getAP()->emitDwarfSymbolReference(Val, false); const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null(Arg0); ASSERT_NE(ActualArg0, nullptr); EXPECT_EQ(&(ActualArg0->getSymbol()), Val); } TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64ForceOffset) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 8)); TestPrinter->getAP()->emitDwarfSymbolReference(Val, true); } class AsmPrinterEmitDwarfStringOffsetTest : public AsmPrinterFixtureBase { protected: bool init(const std::string &TripleStr, unsigned DwarfVersion, dwarf::DwarfFormat DwarfFormat) { if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat)) return false; Val.Index = DwarfStringPoolEntry::NotIndexed; Val.Symbol = TestPrinter->getCtx().createTempSymbol(); Val.Offset = 42; return true; } DwarfStringPoolEntry Val; }; TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF32) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; const MCExpr *Arg0 = nullptr; EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _)) .WillOnce(SaveArg<0>(&Arg0)); TestPrinter->getAP()->emitDwarfStringOffset(Val); const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null(Arg0); ASSERT_NE(ActualArg0, nullptr); EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol); } TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF32NoRelocationsAcrossSections) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; TestPrinter->setDwarfUsesRelocationsAcrossSections(false); EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 4)); TestPrinter->getAP()->emitDwarfStringOffset(Val); } TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF64) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; const MCExpr *Arg0 = nullptr; EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _)) .WillOnce(SaveArg<0>(&Arg0)); TestPrinter->getAP()->emitDwarfStringOffset(Val); const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null(Arg0); ASSERT_NE(ActualArg0, nullptr); EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol); } TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF64NoRelocationsAcrossSections) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; TestPrinter->setDwarfUsesRelocationsAcrossSections(false); EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 8)); TestPrinter->getAP()->emitDwarfStringOffset(Val); } class AsmPrinterEmitDwarfOffsetTest : public AsmPrinterFixtureBase { protected: bool init(const std::string &TripleStr, unsigned DwarfVersion, dwarf::DwarfFormat DwarfFormat) { if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat)) return false; Label = TestPrinter->getCtx().createTempSymbol(); return true; } MCSymbol *Label = nullptr; uint64_t Offset = 42; }; TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF32) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; const MCExpr *Arg0 = nullptr; EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _)) .WillOnce(SaveArg<0>(&Arg0)); TestPrinter->getAP()->emitDwarfOffset(Label, Offset); const MCBinaryExpr *ActualArg0 = dyn_cast_or_null(Arg0); ASSERT_NE(ActualArg0, nullptr); EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add); const MCSymbolRefExpr *ActualLHS = dyn_cast_or_null(ActualArg0->getLHS()); ASSERT_NE(ActualLHS, nullptr); EXPECT_EQ(&(ActualLHS->getSymbol()), Label); const MCConstantExpr *ActualRHS = dyn_cast_or_null(ActualArg0->getRHS()); ASSERT_NE(ActualRHS, nullptr); EXPECT_EQ(static_cast(ActualRHS->getValue()), Offset); } TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF64) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; const MCExpr *Arg0 = nullptr; EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _)) .WillOnce(SaveArg<0>(&Arg0)); TestPrinter->getAP()->emitDwarfOffset(Label, Offset); const MCBinaryExpr *ActualArg0 = dyn_cast_or_null(Arg0); ASSERT_NE(ActualArg0, nullptr); EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add); const MCSymbolRefExpr *ActualLHS = dyn_cast_or_null(ActualArg0->getLHS()); ASSERT_NE(ActualLHS, nullptr); EXPECT_EQ(&(ActualLHS->getSymbol()), Label); const MCConstantExpr *ActualRHS = dyn_cast_or_null(ActualArg0->getRHS()); ASSERT_NE(ActualRHS, nullptr); EXPECT_EQ(static_cast(ActualRHS->getValue()), Offset); } class AsmPrinterEmitDwarfLengthOrOffsetTest : public AsmPrinterFixtureBase { protected: uint64_t Val = 42; }; TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF32) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4)); TestPrinter->getAP()->emitDwarfLengthOrOffset(Val); } TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF64) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8)); TestPrinter->getAP()->emitDwarfLengthOrOffset(Val); } class AsmPrinterGetUnitLengthFieldByteSizeTest : public AsmPrinterFixtureBase { }; TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF32) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 4u); } TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF64) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 12u); } class AsmPrinterMaybeEmitDwarf64MarkTest : public AsmPrinterFixtureBase {}; TEST_F(AsmPrinterMaybeEmitDwarf64MarkTest, DWARF32) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; EXPECT_CALL(TestPrinter->getMS(), emitIntValue(_, _)).Times(0); TestPrinter->getAP()->maybeEmitDwarf64Mark(); } TEST_F(AsmPrinterMaybeEmitDwarf64MarkTest, DWARF64) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4)); TestPrinter->getAP()->maybeEmitDwarf64Mark(); } class AsmPrinterEmitDwarfUnitLengthAsIntTest : public AsmPrinterFixtureBase { protected: uint64_t Val = 42; }; TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF32) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4)); TestPrinter->getAP()->emitDwarfUnitLength(Val, ""); } TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF64) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; InSequence S; EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4)); EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8)); TestPrinter->getAP()->emitDwarfUnitLength(Val, ""); } class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest : public AsmPrinterFixtureBase { protected: bool init(const std::string &TripleStr, unsigned DwarfVersion, dwarf::DwarfFormat DwarfFormat) { if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat)) return false; Hi = TestPrinter->getCtx().createTempSymbol(); Lo = TestPrinter->getCtx().createTempSymbol(); return true; } MCSymbol *Hi = nullptr; MCSymbol *Lo = nullptr; }; TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF32) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 4)); TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, ""); } TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF64) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64)) return; InSequence S; EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4)); EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 8)); TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, ""); } class AsmPrinterHandlerTest : public AsmPrinterFixtureBase { class TestHandler : public AsmPrinterHandler { AsmPrinterHandlerTest &Test; public: TestHandler(AsmPrinterHandlerTest &Test) : Test(Test) {} virtual ~TestHandler() {} virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} virtual void beginModule(Module *M) override { Test.BeginCount++; } virtual void endModule() override { Test.EndCount++; } virtual void beginFunction(const MachineFunction *MF) override {} virtual void endFunction(const MachineFunction *MF) override {} virtual void beginInstruction(const MachineInstr *MI) override {} virtual void endInstruction() override {} }; protected: bool init(const std::string &TripleStr, unsigned DwarfVersion, dwarf::DwarfFormat DwarfFormat) { if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat)) return false; auto *AP = TestPrinter->getAP(); AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo( std::unique_ptr(new TestHandler(*this)), "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc")); LLVMTargetMachine *LLVMTM = static_cast(&AP->TM); legacy::PassManager PM; PM.add(new MachineModuleInfoWrapperPass(LLVMTM)); PM.add(TestPrinter->releaseAP()); // Takes ownership of destroying AP LLVMContext Context; std::unique_ptr M(new Module("TestModule", Context)); M->setDataLayout(LLVMTM->createDataLayout()); PM.run(*M); // Now check that we can run it twice. AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo( std::unique_ptr(new TestHandler(*this)), "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc")); PM.run(*M); return true; } int BeginCount = 0; int EndCount = 0; }; TEST_F(AsmPrinterHandlerTest, Basic) { if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32)) return; ASSERT_EQ(BeginCount, 3); ASSERT_EQ(EndCount, 3); } } // end namespace