xref: /llvm-project/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCopyBytesTest.cpp (revision d8bbfe8a489780bf3536e098aa1220035a0f77bb)
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