1 //===- llvm/unittest/DebugInfo/DWARFExpressionRawDataTest.cpp -------------===//
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
7 //===----------------------------------------------------------------------===//
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/Object/ELFObjectFile.h"
29 #include "llvm/Support/DataExtractor.h"
30 #include "llvm/Support/LEB128.h"
31 #include "llvm/Support/MemoryBuffer.h"
32 #include "llvm/Support/TargetSelect.h"
33 #include "llvm/Testing/Support/Error.h"
34 #include "gtest/gtest.h"
37 using namespace dwarf
;
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
{
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
;
54 DWARFExpressionCopyBytesTest() {
55 InitializeAllTargets();
56 InitializeAllTargetMCs();
57 InitializeAllAsmPrinters();
60 TheTarget
= TargetRegistry::lookupTarget(TripleName
, ErrorStr
);
64 MRI
.reset(TheTarget
->createMCRegInfo(TripleName
));
65 MAI
.reset(TheTarget
->createMCAsmInfo(*MRI
, TripleName
, MCTargetOptions()));
66 STI
.reset(TheTarget
->createMCSubtargetInfo(TripleName
, "", ""));
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
;
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
93 void testExpr(ArrayRef
<uint8_t> ExprData
);
98 DWARFExpressionCopyBytesTest::StreamerContext
99 DWARFExpressionCopyBytesTest::createStreamer(raw_pwrite_stream
&OS
) {
102 std::make_unique
<MCContext
>(Triple(TripleName
), MAI
.get(), MRI
.get(),
104 Res
.MOFI
.reset(TheTarget
->createMCObjectFileInfo(*Res
.Ctx
.get(),
106 Res
.Ctx
->setObjectFileInfo(Res
.MOFI
.get());
108 Res
.MII
.reset(TheTarget
->createMCInstrInfo());
109 MCCodeEmitter
*MCE
= TheTarget
->createMCCodeEmitter(*Res
.MII
, *Res
.Ctx
);
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));
122 SmallString
<0> DWARFExpressionCopyBytesTest::emitObjFile(StringRef ExprBytes
) {
123 auto EncodeDefCfaExpr
= [&](StringRef Bytes
) {
125 raw_string_ostream
OS(Str
);
126 OS
<< static_cast<uint8_t>(dwarf::DW_CFA_def_cfa_expression
);
127 encodeULEB128(Bytes
.size(), OS
);
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();
148 void DWARFExpressionCopyBytesTest::parseCFIsAndCheckExpression(
149 const llvm::object::ObjectFile
&E
, ArrayRef
<uint8_t> Expected
) {
150 auto FetchFirstCfaExpression
=
151 [](const DWARFDebugFrame
&EHFrame
) -> Optional
<CFIProgram::Instruction
> {
152 for (const dwarf::FrameEntry
&Entry
: EHFrame
.entries()) {
153 const auto *CurFDE
= dyn_cast
<dwarf::FDE
>(&Entry
);
156 for (const CFIProgram::Instruction
&Instr
: CurFDE
->cfis()) {
157 if (Instr
.Opcode
!= dwarf::DW_CFA_def_cfa_expression
)
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
]);
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
);
189 void DWARFExpressionCopyBytesTest::testExpr(ArrayRef
<uint8_t> ExprData
) {
190 // If we didn't build x86, do not run the test.
194 DataExtractor
DE(ExprData
, true, 8);
195 DWARFExpression
Expr(DE
, 8);
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
);
203 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_reg0
) { testExpr({DW_OP_reg0
}); }
205 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_reg10
) { testExpr({DW_OP_reg10
}); }
207 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_regx
) {
208 testExpr({DW_OP_regx
, 0x80, 0x02});
211 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_breg0
) {
212 testExpr({DW_OP_breg0
, 0x04});
215 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_breg0_large_offset
) {
216 testExpr({DW_OP_breg0
, 0x80, 0x02});
219 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_breg13
) {
220 testExpr({DW_OP_breg13
, 0x10});
223 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_breg13_zero_offset
) {
224 testExpr({DW_OP_breg13
, 0x00});
227 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_breg0_negative
) {
228 testExpr({DW_OP_breg0
, 0x70});
231 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_bregx
) {
232 testExpr({DW_OP_bregx
, 0x0d, 0x28});
235 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_stack_value
) {
236 testExpr({DW_OP_breg13
, 0x04, DW_OP_stack_value
});
239 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_entry_value
) {
240 testExpr({DW_OP_entry_value
, 0x01, DW_OP_reg0
, DW_OP_stack_value
});
243 TEST_F(DWARFExpressionCopyBytesTest
, Test_OP_entry_value_mem
) {
244 testExpr({DW_OP_entry_value
, 0x02, DW_OP_breg13
, 0x10, DW_OP_stack_value
});