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