1d8bbfe8aSRafael Auler //===- llvm/unittest/DebugInfo/DWARFExpressionRawDataTest.cpp -------------===// 2d8bbfe8aSRafael Auler // 3d8bbfe8aSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4d8bbfe8aSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5d8bbfe8aSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6d8bbfe8aSRafael Auler // 7d8bbfe8aSRafael Auler //===----------------------------------------------------------------------===// 8d8bbfe8aSRafael Auler 9d8bbfe8aSRafael Auler #include "llvm/ADT/ArrayRef.h" 10d8bbfe8aSRafael Auler #include "llvm/ADT/Triple.h" 11d8bbfe8aSRafael Auler #include "llvm/BinaryFormat/Dwarf.h" 12d8bbfe8aSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFContext.h" 13d8bbfe8aSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" 14d8bbfe8aSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFDie.h" 15d8bbfe8aSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 16d8bbfe8aSRafael Auler #include "llvm/MC/MCAsmBackend.h" 17d8bbfe8aSRafael Auler #include "llvm/MC/MCAsmInfo.h" 18d8bbfe8aSRafael Auler #include "llvm/MC/MCCodeEmitter.h" 19d8bbfe8aSRafael Auler #include "llvm/MC/MCContext.h" 20d8bbfe8aSRafael Auler #include "llvm/MC/MCInstrInfo.h" 21d8bbfe8aSRafael Auler #include "llvm/MC/MCObjectWriter.h" 22ef736a1cSserge-sans-paille #include "llvm/MC/MCRegisterInfo.h" 23d8bbfe8aSRafael Auler #include "llvm/MC/MCStreamer.h" 24ef736a1cSserge-sans-paille #include "llvm/MC/MCSubtargetInfo.h" 25d8bbfe8aSRafael Auler #include "llvm/MC/MCTargetOptions.h" 2689b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h" 27d8bbfe8aSRafael Auler #include "llvm/Object/Binary.h" 28e72c195fSserge-sans-paille #include "llvm/Object/ELFObjectFile.h" 29d8bbfe8aSRafael Auler #include "llvm/Support/DataExtractor.h" 30d8bbfe8aSRafael Auler #include "llvm/Support/LEB128.h" 31e72c195fSserge-sans-paille #include "llvm/Support/MemoryBuffer.h" 32d8bbfe8aSRafael Auler #include "llvm/Support/TargetSelect.h" 33d8bbfe8aSRafael Auler #include "llvm/Testing/Support/Error.h" 34d8bbfe8aSRafael Auler #include "gtest/gtest.h" 35d8bbfe8aSRafael Auler 36d8bbfe8aSRafael Auler using namespace llvm; 37d8bbfe8aSRafael Auler using namespace dwarf; 38d8bbfe8aSRafael Auler 39d8bbfe8aSRafael Auler namespace { 40d8bbfe8aSRafael Auler 41d8bbfe8aSRafael Auler /// Tests that a client of DebugInfo/DWARF is able to read raw data bytes of a 42d8bbfe8aSRafael Auler /// DWARFExpression parsed from CFI with the intent of writing them back as is 43d8bbfe8aSRafael Auler /// via MC layer / cfi_escape. 44d8bbfe8aSRafael Auler /// This is relevant for binary tools that need to rewrite/copy unwind and 45d8bbfe8aSRafael Auler /// debug info from input to output binary. 46d8bbfe8aSRafael Auler class DWARFExpressionCopyBytesTest : public ::testing::Test { 47d8bbfe8aSRafael Auler public: 48d8bbfe8aSRafael Auler const char *TripleName = "x86_64-pc-linux"; 49d8bbfe8aSRafael Auler std::unique_ptr<MCRegisterInfo> MRI; 50d8bbfe8aSRafael Auler std::unique_ptr<MCAsmInfo> MAI; 51d8bbfe8aSRafael Auler std::unique_ptr<const MCSubtargetInfo> STI; 52d8bbfe8aSRafael Auler const Target *TheTarget; 53d8bbfe8aSRafael Auler 54d8bbfe8aSRafael Auler DWARFExpressionCopyBytesTest() { 55d8bbfe8aSRafael Auler InitializeAllTargets(); 56d8bbfe8aSRafael Auler InitializeAllTargetMCs(); 57d8bbfe8aSRafael Auler InitializeAllAsmPrinters(); 58d8bbfe8aSRafael Auler 59d8bbfe8aSRafael Auler std::string ErrorStr; 60d8bbfe8aSRafael Auler TheTarget = TargetRegistry::lookupTarget(TripleName, ErrorStr); 61d8bbfe8aSRafael Auler if (!TheTarget) 62d8bbfe8aSRafael Auler return; 63d8bbfe8aSRafael Auler 64d8bbfe8aSRafael Auler MRI.reset(TheTarget->createMCRegInfo(TripleName)); 65d8bbfe8aSRafael Auler MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCTargetOptions())); 66d8bbfe8aSRafael Auler STI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); 67d8bbfe8aSRafael Auler } 68d8bbfe8aSRafael Auler 69d8bbfe8aSRafael Auler struct StreamerContext { 70d8bbfe8aSRafael Auler std::unique_ptr<MCObjectFileInfo> MOFI; 71d8bbfe8aSRafael Auler std::unique_ptr<MCContext> Ctx; 72d8bbfe8aSRafael Auler std::unique_ptr<const MCInstrInfo> MII; 73d8bbfe8aSRafael Auler std::unique_ptr<MCStreamer> Streamer; 74d8bbfe8aSRafael Auler }; 75d8bbfe8aSRafael Auler 76d8bbfe8aSRafael Auler /// Create all data structures necessary to operate an assembler 77d8bbfe8aSRafael Auler StreamerContext createStreamer(raw_pwrite_stream &OS); 78d8bbfe8aSRafael Auler /// Emit a dummy obj file with a single CFI instruction, 79d8bbfe8aSRafael Auler /// DW_CFA_def_cfa_expression, encoding as its operand the DWARF expression 80d8bbfe8aSRafael Auler /// represented by ExprBytes 81d8bbfe8aSRafael Auler SmallString<0> emitObjFile(StringRef ExprBytes); 82d8bbfe8aSRafael Auler /// Peruse the object file looking for the encoded DWARF expression, and check 83d8bbfe8aSRafael Auler /// that its operand was encoded correctly 84d8bbfe8aSRafael Auler void parseCFIsAndCheckExpression(const llvm::object::ObjectFile &E, 85d8bbfe8aSRafael Auler ArrayRef<uint8_t> Expected); 86d8bbfe8aSRafael Auler /// Open the in-memory relocatable object file and verify that it contains 87d8bbfe8aSRafael Auler /// the expected DWARF expression bytes 88d8bbfe8aSRafael Auler void readAndCheckObjFile(StringRef ObjFileData, ArrayRef<uint8_t> Expected); 89d8bbfe8aSRafael Auler /// Run this test on the DWARF expression represented by the bytes in 90d8bbfe8aSRafael Auler /// ExprData. Check that the getData() API retrieves these original bytes and 91d8bbfe8aSRafael Auler /// that we can use them to encode a CFI with those bytes as operands (via 92d8bbfe8aSRafael Auler /// cfi_escape). 93d8bbfe8aSRafael Auler void testExpr(ArrayRef<uint8_t> ExprData); 94d8bbfe8aSRafael Auler }; 95d8bbfe8aSRafael Auler 96d8bbfe8aSRafael Auler } // namespace 97d8bbfe8aSRafael Auler 98d8bbfe8aSRafael Auler DWARFExpressionCopyBytesTest::StreamerContext 99d8bbfe8aSRafael Auler DWARFExpressionCopyBytesTest::createStreamer(raw_pwrite_stream &OS) { 100d8bbfe8aSRafael Auler StreamerContext Res; 101d8bbfe8aSRafael Auler Res.Ctx = 102d8bbfe8aSRafael Auler std::make_unique<MCContext>(Triple(TripleName), MAI.get(), MRI.get(), 103d8bbfe8aSRafael Auler /*MSTI=*/nullptr); 104d8bbfe8aSRafael Auler Res.MOFI.reset(TheTarget->createMCObjectFileInfo(*Res.Ctx.get(), 105d8bbfe8aSRafael Auler /*PIC=*/false)); 106d8bbfe8aSRafael Auler Res.Ctx->setObjectFileInfo(Res.MOFI.get()); 107d8bbfe8aSRafael Auler 108d8bbfe8aSRafael Auler Res.MII.reset(TheTarget->createMCInstrInfo()); 1092aed07e9SShao-Ce SUN MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*Res.MII, *Res.Ctx); 110d8bbfe8aSRafael Auler MCAsmBackend *MAB = 111d8bbfe8aSRafael Auler TheTarget->createMCAsmBackend(*STI, *MRI, MCTargetOptions()); 112d8bbfe8aSRafael Auler std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(OS); 113d8bbfe8aSRafael Auler Res.Streamer.reset(TheTarget->createMCObjectStreamer( 114d8bbfe8aSRafael Auler Triple(TripleName), *Res.Ctx, std::unique_ptr<MCAsmBackend>(MAB), 115d8bbfe8aSRafael Auler std::move(OW), std::unique_ptr<MCCodeEmitter>(MCE), *STI, 116d8bbfe8aSRafael Auler /* RelaxAll */ false, 117d8bbfe8aSRafael Auler /* IncrementalLinkerCompatible */ false, 118d8bbfe8aSRafael Auler /* DWARFMustBeAtTheEnd */ false)); 119d8bbfe8aSRafael Auler return Res; 120d8bbfe8aSRafael Auler } 121d8bbfe8aSRafael Auler 122d8bbfe8aSRafael Auler SmallString<0> DWARFExpressionCopyBytesTest::emitObjFile(StringRef ExprBytes) { 123d8bbfe8aSRafael Auler auto EncodeDefCfaExpr = [&](StringRef Bytes) { 124d8bbfe8aSRafael Auler std::string Str; 125d8bbfe8aSRafael Auler raw_string_ostream OS(Str); 126d8bbfe8aSRafael Auler OS << static_cast<uint8_t>(dwarf::DW_CFA_def_cfa_expression); 127d8bbfe8aSRafael Auler encodeULEB128(Bytes.size(), OS); 128d8bbfe8aSRafael Auler OS << Bytes; 129d8bbfe8aSRafael Auler return Str; 130d8bbfe8aSRafael Auler }; 131d8bbfe8aSRafael Auler 132d8bbfe8aSRafael Auler SmallString<0> Storage; 133d8bbfe8aSRafael Auler raw_svector_ostream VecOS(Storage); 134d8bbfe8aSRafael Auler StreamerContext C = createStreamer(VecOS); 1355e71839fSPeter Smith C.Streamer->initSections(false, *STI); 136d8bbfe8aSRafael Auler MCSection *Section = C.MOFI->getTextSection(); 137d8bbfe8aSRafael Auler Section->setHasInstructions(true); 138d8bbfe8aSRafael Auler C.Streamer->SwitchSection(Section); 139d8bbfe8aSRafael Auler C.Streamer->emitCFIStartProc(true); 140d8bbfe8aSRafael Auler auto Str = EncodeDefCfaExpr(ExprBytes); 141d8bbfe8aSRafael Auler C.Streamer->emitCFIEscape(Str); 142e63455d5SPeter Smith C.Streamer->emitNops(4, 1, SMLoc(), *STI); 143d8bbfe8aSRafael Auler C.Streamer->emitCFIEndProc(); 144*15d82c62SFangrui Song C.Streamer->finish(); 145d8bbfe8aSRafael Auler return Storage; 146d8bbfe8aSRafael Auler } 147d8bbfe8aSRafael Auler 148d8bbfe8aSRafael Auler void DWARFExpressionCopyBytesTest::parseCFIsAndCheckExpression( 149d8bbfe8aSRafael Auler const llvm::object::ObjectFile &E, ArrayRef<uint8_t> Expected) { 150d8bbfe8aSRafael Auler auto FetchFirstCfaExpression = 151d8bbfe8aSRafael Auler [](const DWARFDebugFrame &EHFrame) -> Optional<CFIProgram::Instruction> { 152d8bbfe8aSRafael Auler for (const dwarf::FrameEntry &Entry : EHFrame.entries()) { 153d8bbfe8aSRafael Auler const auto *CurFDE = dyn_cast<dwarf::FDE>(&Entry); 154d8bbfe8aSRafael Auler if (!CurFDE) 155d8bbfe8aSRafael Auler continue; 156d8bbfe8aSRafael Auler for (const CFIProgram::Instruction &Instr : CurFDE->cfis()) { 157d8bbfe8aSRafael Auler if (Instr.Opcode != dwarf::DW_CFA_def_cfa_expression) 158d8bbfe8aSRafael Auler continue; 159d8bbfe8aSRafael Auler return Instr; 160d8bbfe8aSRafael Auler } 161d8bbfe8aSRafael Auler } 162d8bbfe8aSRafael Auler return NoneType(); 163d8bbfe8aSRafael Auler }; 164d8bbfe8aSRafael Auler 165d8bbfe8aSRafael Auler std::unique_ptr<DWARFContext> Ctx = DWARFContext::create(E); 166d8bbfe8aSRafael Auler const DWARFDebugFrame *EHFrame = cantFail(Ctx->getEHFrame()); 167d8bbfe8aSRafael Auler ASSERT_NE(nullptr, EHFrame); 168d8bbfe8aSRafael Auler auto CfiInstr = FetchFirstCfaExpression(*EHFrame); 169d8bbfe8aSRafael Auler ASSERT_TRUE(CfiInstr); 170d8bbfe8aSRafael Auler DWARFExpression Expr = *(CfiInstr->Expression); 171d8bbfe8aSRafael Auler StringRef ExprData = Expr.getData(); 172d8bbfe8aSRafael Auler EXPECT_EQ(ExprData.size(), Expected.size()); 173d8bbfe8aSRafael Auler for (unsigned I = 0, E = ExprData.size(); I != E; ++I) { 174d8bbfe8aSRafael Auler EXPECT_EQ(static_cast<uint8_t>(ExprData[I]), Expected[I]); 175d8bbfe8aSRafael Auler } 176d8bbfe8aSRafael Auler } 177d8bbfe8aSRafael Auler 178d8bbfe8aSRafael Auler void DWARFExpressionCopyBytesTest::readAndCheckObjFile( 179d8bbfe8aSRafael Auler StringRef ObjFileData, ArrayRef<uint8_t> Expected) { 180d8bbfe8aSRafael Auler std::unique_ptr<MemoryBuffer> MB = 181d8bbfe8aSRafael Auler MemoryBuffer::getMemBuffer(ObjFileData, "", false); 182d8bbfe8aSRafael Auler std::unique_ptr<object::Binary> Bin = 183d8bbfe8aSRafael Auler cantFail(llvm::object::createBinary(MB->getMemBufferRef())); 184d8bbfe8aSRafael Auler if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) { 185d8bbfe8aSRafael Auler parseCFIsAndCheckExpression(*E, Expected); 186d8bbfe8aSRafael Auler } 187d8bbfe8aSRafael Auler } 188d8bbfe8aSRafael Auler 189d8bbfe8aSRafael Auler void DWARFExpressionCopyBytesTest::testExpr(ArrayRef<uint8_t> ExprData) { 190d8bbfe8aSRafael Auler // If we didn't build x86, do not run the test. 191d8bbfe8aSRafael Auler if (!MRI) 192f5907ea1SIgor Kudrin GTEST_SKIP(); 193d8bbfe8aSRafael Auler 194d8bbfe8aSRafael Auler DataExtractor DE(ExprData, true, 8); 195d8bbfe8aSRafael Auler DWARFExpression Expr(DE, 8); 196d8bbfe8aSRafael Auler 197d8bbfe8aSRafael Auler // Copy this expression into the CFI of a binary and check that we are able to 198d8bbfe8aSRafael Auler // get it back correctly from this binary. 199d8bbfe8aSRafael Auler const SmallString<0> EmittedBinContents = emitObjFile(Expr.getData()); 200d8bbfe8aSRafael Auler readAndCheckObjFile(EmittedBinContents.str(), ExprData); 201d8bbfe8aSRafael Auler } 202d8bbfe8aSRafael Auler 203d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_reg0) { testExpr({DW_OP_reg0}); } 204d8bbfe8aSRafael Auler 205d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_reg10) { testExpr({DW_OP_reg10}); } 206d8bbfe8aSRafael Auler 207d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_regx) { 208d8bbfe8aSRafael Auler testExpr({DW_OP_regx, 0x80, 0x02}); 209d8bbfe8aSRafael Auler } 210d8bbfe8aSRafael Auler 211d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0) { 212d8bbfe8aSRafael Auler testExpr({DW_OP_breg0, 0x04}); 213d8bbfe8aSRafael Auler } 214d8bbfe8aSRafael Auler 215d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0_large_offset) { 216d8bbfe8aSRafael Auler testExpr({DW_OP_breg0, 0x80, 0x02}); 217d8bbfe8aSRafael Auler } 218d8bbfe8aSRafael Auler 219d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg13) { 220d8bbfe8aSRafael Auler testExpr({DW_OP_breg13, 0x10}); 221d8bbfe8aSRafael Auler } 222d8bbfe8aSRafael Auler 223d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg13_zero_offset) { 224d8bbfe8aSRafael Auler testExpr({DW_OP_breg13, 0x00}); 225d8bbfe8aSRafael Auler } 226d8bbfe8aSRafael Auler 227d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0_negative) { 228d8bbfe8aSRafael Auler testExpr({DW_OP_breg0, 0x70}); 229d8bbfe8aSRafael Auler } 230d8bbfe8aSRafael Auler 231d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_bregx) { 232d8bbfe8aSRafael Auler testExpr({DW_OP_bregx, 0x0d, 0x28}); 233d8bbfe8aSRafael Auler } 234d8bbfe8aSRafael Auler 235d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_stack_value) { 236d8bbfe8aSRafael Auler testExpr({DW_OP_breg13, 0x04, DW_OP_stack_value}); 237d8bbfe8aSRafael Auler } 238d8bbfe8aSRafael Auler 239d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_entry_value) { 240d8bbfe8aSRafael Auler testExpr({DW_OP_entry_value, 0x01, DW_OP_reg0, DW_OP_stack_value}); 241d8bbfe8aSRafael Auler } 242d8bbfe8aSRafael Auler 243d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_entry_value_mem) { 244d8bbfe8aSRafael Auler testExpr({DW_OP_entry_value, 0x02, DW_OP_breg13, 0x10, DW_OP_stack_value}); 245d8bbfe8aSRafael Auler } 246