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 /* RelaxAll */ false, 117 /* IncrementalLinkerCompatible */ false, 118 /* DWARFMustBeAtTheEnd */ false)); 119 return Res; 120 } 121 122 SmallString<0> DWARFExpressionCopyBytesTest::emitObjFile(StringRef ExprBytes) { 123 auto EncodeDefCfaExpr = [&](StringRef Bytes) { 124 std::string Str; 125 raw_string_ostream OS(Str); 126 OS << static_cast<uint8_t>(dwarf::DW_CFA_def_cfa_expression); 127 encodeULEB128(Bytes.size(), OS); 128 OS << Bytes; 129 return Str; 130 }; 131 132 SmallString<0> Storage; 133 raw_svector_ostream VecOS(Storage); 134 StreamerContext C = createStreamer(VecOS); 135 C.Streamer->initSections(false, *STI); 136 MCSection *Section = C.MOFI->getTextSection(); 137 Section->setHasInstructions(true); 138 C.Streamer->switchSection(Section); 139 C.Streamer->emitCFIStartProc(true); 140 auto Str = EncodeDefCfaExpr(ExprBytes); 141 C.Streamer->emitCFIEscape(Str); 142 C.Streamer->emitNops(4, 1, SMLoc(), *STI); 143 C.Streamer->emitCFIEndProc(); 144 C.Streamer->finish(); 145 return Storage; 146 } 147 148 void DWARFExpressionCopyBytesTest::parseCFIsAndCheckExpression( 149 const llvm::object::ObjectFile &E, ArrayRef<uint8_t> Expected) { 150 auto FetchFirstCfaExpression = [](const DWARFDebugFrame &EHFrame) 151 -> std::optional<CFIProgram::Instruction> { 152 for (const dwarf::FrameEntry &Entry : EHFrame.entries()) { 153 const auto *CurFDE = dyn_cast<dwarf::FDE>(&Entry); 154 if (!CurFDE) 155 continue; 156 for (const CFIProgram::Instruction &Instr : CurFDE->cfis()) { 157 if (Instr.Opcode != dwarf::DW_CFA_def_cfa_expression) 158 continue; 159 return Instr; 160 } 161 } 162 return std::nullopt; 163 }; 164 165 std::unique_ptr<DWARFContext> Ctx = DWARFContext::create(E); 166 const DWARFDebugFrame *EHFrame = cantFail(Ctx->getEHFrame()); 167 ASSERT_NE(nullptr, EHFrame); 168 auto CfiInstr = FetchFirstCfaExpression(*EHFrame); 169 ASSERT_TRUE(CfiInstr); 170 DWARFExpression Expr = *(CfiInstr->Expression); 171 StringRef ExprData = Expr.getData(); 172 EXPECT_EQ(ExprData.size(), Expected.size()); 173 for (unsigned I = 0, E = ExprData.size(); I != E; ++I) { 174 EXPECT_EQ(static_cast<uint8_t>(ExprData[I]), Expected[I]); 175 } 176 } 177 178 void DWARFExpressionCopyBytesTest::readAndCheckObjFile( 179 StringRef ObjFileData, ArrayRef<uint8_t> Expected) { 180 std::unique_ptr<MemoryBuffer> MB = 181 MemoryBuffer::getMemBuffer(ObjFileData, "", false); 182 std::unique_ptr<object::Binary> Bin = 183 cantFail(llvm::object::createBinary(MB->getMemBufferRef())); 184 if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) { 185 parseCFIsAndCheckExpression(*E, Expected); 186 } 187 } 188 189 void DWARFExpressionCopyBytesTest::testExpr(ArrayRef<uint8_t> ExprData) { 190 // If we didn't build x86, do not run the test. 191 if (!MRI) 192 GTEST_SKIP(); 193 194 DataExtractor DE(ExprData, true, 8); 195 DWARFExpression Expr(DE, 8); 196 197 // Copy this expression into the CFI of a binary and check that we are able to 198 // get it back correctly from this binary. 199 const SmallString<0> EmittedBinContents = emitObjFile(Expr.getData()); 200 readAndCheckObjFile(EmittedBinContents.str(), ExprData); 201 } 202 203 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_reg0) { testExpr({DW_OP_reg0}); } 204 205 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_reg10) { testExpr({DW_OP_reg10}); } 206 207 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_regx) { 208 testExpr({DW_OP_regx, 0x80, 0x02}); 209 } 210 211 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0) { 212 testExpr({DW_OP_breg0, 0x04}); 213 } 214 215 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0_large_offset) { 216 testExpr({DW_OP_breg0, 0x80, 0x02}); 217 } 218 219 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg13) { 220 testExpr({DW_OP_breg13, 0x10}); 221 } 222 223 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg13_zero_offset) { 224 testExpr({DW_OP_breg13, 0x00}); 225 } 226 227 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0_negative) { 228 testExpr({DW_OP_breg0, 0x70}); 229 } 230 231 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_bregx) { 232 testExpr({DW_OP_bregx, 0x0d, 0x28}); 233 } 234 235 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_stack_value) { 236 testExpr({DW_OP_breg13, 0x04, DW_OP_stack_value}); 237 } 238 239 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_entry_value) { 240 testExpr({DW_OP_entry_value, 0x01, DW_OP_reg0, DW_OP_stack_value}); 241 } 242 243 TEST_F(DWARFExpressionCopyBytesTest, Test_OP_entry_value_mem) { 244 testExpr({DW_OP_entry_value, 0x02, DW_OP_breg13, 0x10, DW_OP_stack_value}); 245 } 246