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