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