[docs] Fix build-docs.sh
[llvm-project.git] / llvm / unittests / DebugInfo / DWARF / DWARFExpressionCopyBytesTest.cpp
blob879a925e9cf5fad68d5869408a4cb8ded5e41fd1
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 //===----------------------------------------------------------------------===//
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"
36 using namespace llvm;
37 using namespace dwarf;
39 namespace {
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;
54 DWARFExpressionCopyBytesTest() {
55 InitializeAllTargets();
56 InitializeAllTargetMCs();
57 InitializeAllAsmPrinters();
59 std::string ErrorStr;
60 TheTarget = TargetRegistry::lookupTarget(TripleName, ErrorStr);
61 if (!TheTarget)
62 return;
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
92 /// cfi_escape).
93 void testExpr(ArrayRef<uint8_t> ExprData);
96 } // namespace
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.get(),
105 /*PIC=*/false));
106 Res.Ctx->setObjectFileInfo(Res.MOFI.get());
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;
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;
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;
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);
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;
162 return NoneType();
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.
191 if (!MRI)
192 GTEST_SKIP();
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});