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