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/BinaryFormat/Dwarf.h" 11d8bbfe8aSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFContext.h" 12d8bbfe8aSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" 13d8bbfe8aSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFDie.h" 14d8bbfe8aSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 15d8bbfe8aSRafael Auler #include "llvm/MC/MCAsmBackend.h" 16d8bbfe8aSRafael Auler #include "llvm/MC/MCAsmInfo.h" 17d8bbfe8aSRafael Auler #include "llvm/MC/MCCodeEmitter.h" 18d8bbfe8aSRafael Auler #include "llvm/MC/MCContext.h" 19d8bbfe8aSRafael Auler #include "llvm/MC/MCInstrInfo.h" 20d8bbfe8aSRafael Auler #include "llvm/MC/MCObjectWriter.h" 21ef736a1cSserge-sans-paille #include "llvm/MC/MCRegisterInfo.h" 22d8bbfe8aSRafael Auler #include "llvm/MC/MCStreamer.h" 23ef736a1cSserge-sans-paille #include "llvm/MC/MCSubtargetInfo.h" 24d8bbfe8aSRafael Auler #include "llvm/MC/MCTargetOptions.h" 2589b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h" 26d8bbfe8aSRafael Auler #include "llvm/Object/Binary.h" 27e72c195fSserge-sans-paille #include "llvm/Object/ELFObjectFile.h" 28d8bbfe8aSRafael Auler #include "llvm/Support/DataExtractor.h" 29d8bbfe8aSRafael Auler #include "llvm/Support/LEB128.h" 30e72c195fSserge-sans-paille #include "llvm/Support/MemoryBuffer.h" 31d8bbfe8aSRafael Auler #include "llvm/Support/TargetSelect.h" 3262c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.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); 10475bc20ffSKazu Hirata Res.MOFI.reset(TheTarget->createMCObjectFileInfo(*Res.Ctx, 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), 115*b8220b98SFangrui Song std::move(OW), std::unique_ptr<MCCodeEmitter>(MCE), *STI)); 116d8bbfe8aSRafael Auler return Res; 117d8bbfe8aSRafael Auler } 118d8bbfe8aSRafael Auler 119d8bbfe8aSRafael Auler SmallString<0> DWARFExpressionCopyBytesTest::emitObjFile(StringRef ExprBytes) { 120d8bbfe8aSRafael Auler auto EncodeDefCfaExpr = [&](StringRef Bytes) { 121d8bbfe8aSRafael Auler std::string Str; 122d8bbfe8aSRafael Auler raw_string_ostream OS(Str); 123d8bbfe8aSRafael Auler OS << static_cast<uint8_t>(dwarf::DW_CFA_def_cfa_expression); 124d8bbfe8aSRafael Auler encodeULEB128(Bytes.size(), OS); 125d8bbfe8aSRafael Auler OS << Bytes; 126d8bbfe8aSRafael Auler return Str; 127d8bbfe8aSRafael Auler }; 128d8bbfe8aSRafael Auler 129d8bbfe8aSRafael Auler SmallString<0> Storage; 130d8bbfe8aSRafael Auler raw_svector_ostream VecOS(Storage); 131d8bbfe8aSRafael Auler StreamerContext C = createStreamer(VecOS); 1325e71839fSPeter Smith C.Streamer->initSections(false, *STI); 133d8bbfe8aSRafael Auler MCSection *Section = C.MOFI->getTextSection(); 134d8bbfe8aSRafael Auler Section->setHasInstructions(true); 135adf4142fSFangrui Song C.Streamer->switchSection(Section); 136d8bbfe8aSRafael Auler C.Streamer->emitCFIStartProc(true); 137d8bbfe8aSRafael Auler auto Str = EncodeDefCfaExpr(ExprBytes); 138d8bbfe8aSRafael Auler C.Streamer->emitCFIEscape(Str); 139e63455d5SPeter Smith C.Streamer->emitNops(4, 1, SMLoc(), *STI); 140d8bbfe8aSRafael Auler C.Streamer->emitCFIEndProc(); 14115d82c62SFangrui Song C.Streamer->finish(); 142d8bbfe8aSRafael Auler return Storage; 143d8bbfe8aSRafael Auler } 144d8bbfe8aSRafael Auler 145d8bbfe8aSRafael Auler void DWARFExpressionCopyBytesTest::parseCFIsAndCheckExpression( 146d8bbfe8aSRafael Auler const llvm::object::ObjectFile &E, ArrayRef<uint8_t> Expected) { 14777c90c8cSKazu Hirata auto FetchFirstCfaExpression = [](const DWARFDebugFrame &EHFrame) 14877c90c8cSKazu Hirata -> std::optional<CFIProgram::Instruction> { 149d8bbfe8aSRafael Auler for (const dwarf::FrameEntry &Entry : EHFrame.entries()) { 150d8bbfe8aSRafael Auler const auto *CurFDE = dyn_cast<dwarf::FDE>(&Entry); 151d8bbfe8aSRafael Auler if (!CurFDE) 152d8bbfe8aSRafael Auler continue; 153d8bbfe8aSRafael Auler for (const CFIProgram::Instruction &Instr : CurFDE->cfis()) { 154d8bbfe8aSRafael Auler if (Instr.Opcode != dwarf::DW_CFA_def_cfa_expression) 155d8bbfe8aSRafael Auler continue; 156d8bbfe8aSRafael Auler return Instr; 157d8bbfe8aSRafael Auler } 158d8bbfe8aSRafael Auler } 159b6a01caaSKazu Hirata return std::nullopt; 160d8bbfe8aSRafael Auler }; 161d8bbfe8aSRafael Auler 162d8bbfe8aSRafael Auler std::unique_ptr<DWARFContext> Ctx = DWARFContext::create(E); 163d8bbfe8aSRafael Auler const DWARFDebugFrame *EHFrame = cantFail(Ctx->getEHFrame()); 164d8bbfe8aSRafael Auler ASSERT_NE(nullptr, EHFrame); 165d8bbfe8aSRafael Auler auto CfiInstr = FetchFirstCfaExpression(*EHFrame); 166d8bbfe8aSRafael Auler ASSERT_TRUE(CfiInstr); 167d8bbfe8aSRafael Auler DWARFExpression Expr = *(CfiInstr->Expression); 168d8bbfe8aSRafael Auler StringRef ExprData = Expr.getData(); 169d8bbfe8aSRafael Auler EXPECT_EQ(ExprData.size(), Expected.size()); 170d8bbfe8aSRafael Auler for (unsigned I = 0, E = ExprData.size(); I != E; ++I) { 171d8bbfe8aSRafael Auler EXPECT_EQ(static_cast<uint8_t>(ExprData[I]), Expected[I]); 172d8bbfe8aSRafael Auler } 173d8bbfe8aSRafael Auler } 174d8bbfe8aSRafael Auler 175d8bbfe8aSRafael Auler void DWARFExpressionCopyBytesTest::readAndCheckObjFile( 176d8bbfe8aSRafael Auler StringRef ObjFileData, ArrayRef<uint8_t> Expected) { 177d8bbfe8aSRafael Auler std::unique_ptr<MemoryBuffer> MB = 178d8bbfe8aSRafael Auler MemoryBuffer::getMemBuffer(ObjFileData, "", false); 179d8bbfe8aSRafael Auler std::unique_ptr<object::Binary> Bin = 180d8bbfe8aSRafael Auler cantFail(llvm::object::createBinary(MB->getMemBufferRef())); 181d8bbfe8aSRafael Auler if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) { 182d8bbfe8aSRafael Auler parseCFIsAndCheckExpression(*E, Expected); 183d8bbfe8aSRafael Auler } 184d8bbfe8aSRafael Auler } 185d8bbfe8aSRafael Auler 186d8bbfe8aSRafael Auler void DWARFExpressionCopyBytesTest::testExpr(ArrayRef<uint8_t> ExprData) { 187d8bbfe8aSRafael Auler // If we didn't build x86, do not run the test. 188d8bbfe8aSRafael Auler if (!MRI) 189f5907ea1SIgor Kudrin GTEST_SKIP(); 190d8bbfe8aSRafael Auler 191d8bbfe8aSRafael Auler DataExtractor DE(ExprData, true, 8); 192d8bbfe8aSRafael Auler DWARFExpression Expr(DE, 8); 193d8bbfe8aSRafael Auler 194d8bbfe8aSRafael Auler // Copy this expression into the CFI of a binary and check that we are able to 195d8bbfe8aSRafael Auler // get it back correctly from this binary. 196d8bbfe8aSRafael Auler const SmallString<0> EmittedBinContents = emitObjFile(Expr.getData()); 197d8bbfe8aSRafael Auler readAndCheckObjFile(EmittedBinContents.str(), ExprData); 198d8bbfe8aSRafael Auler } 199d8bbfe8aSRafael Auler 200d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_reg0) { testExpr({DW_OP_reg0}); } 201d8bbfe8aSRafael Auler 202d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_reg10) { testExpr({DW_OP_reg10}); } 203d8bbfe8aSRafael Auler 204d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_regx) { 205d8bbfe8aSRafael Auler testExpr({DW_OP_regx, 0x80, 0x02}); 206d8bbfe8aSRafael Auler } 207d8bbfe8aSRafael Auler 208d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0) { 209d8bbfe8aSRafael Auler testExpr({DW_OP_breg0, 0x04}); 210d8bbfe8aSRafael Auler } 211d8bbfe8aSRafael Auler 212d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0_large_offset) { 213d8bbfe8aSRafael Auler testExpr({DW_OP_breg0, 0x80, 0x02}); 214d8bbfe8aSRafael Auler } 215d8bbfe8aSRafael Auler 216d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg13) { 217d8bbfe8aSRafael Auler testExpr({DW_OP_breg13, 0x10}); 218d8bbfe8aSRafael Auler } 219d8bbfe8aSRafael Auler 220d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg13_zero_offset) { 221d8bbfe8aSRafael Auler testExpr({DW_OP_breg13, 0x00}); 222d8bbfe8aSRafael Auler } 223d8bbfe8aSRafael Auler 224d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0_negative) { 225d8bbfe8aSRafael Auler testExpr({DW_OP_breg0, 0x70}); 226d8bbfe8aSRafael Auler } 227d8bbfe8aSRafael Auler 228d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_bregx) { 229d8bbfe8aSRafael Auler testExpr({DW_OP_bregx, 0x0d, 0x28}); 230d8bbfe8aSRafael Auler } 231d8bbfe8aSRafael Auler 232d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_stack_value) { 233d8bbfe8aSRafael Auler testExpr({DW_OP_breg13, 0x04, DW_OP_stack_value}); 234d8bbfe8aSRafael Auler } 235d8bbfe8aSRafael Auler 236d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_entry_value) { 237d8bbfe8aSRafael Auler testExpr({DW_OP_entry_value, 0x01, DW_OP_reg0, DW_OP_stack_value}); 238d8bbfe8aSRafael Auler } 239d8bbfe8aSRafael Auler 240d8bbfe8aSRafael Auler TEST_F(DWARFExpressionCopyBytesTest, Test_OP_entry_value_mem) { 241d8bbfe8aSRafael Auler testExpr({DW_OP_entry_value, 0x02, DW_OP_breg13, 0x10, DW_OP_stack_value}); 242d8bbfe8aSRafael Auler } 243