1 //===-- TestPPC64InstEmulation.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 "gtest/gtest.h"
10 
11 #include <vector>
12 
13 #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
14 
15 #include "lldb/Core/Address.h"
16 #include "lldb/Core/AddressRange.h"
17 #include "lldb/Symbol/UnwindPlan.h"
18 #include "lldb/Target/UnwindAssembly.h"
19 #include "lldb/Utility/ArchSpec.h"
20 
21 #include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
22 #include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
23 #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
24 #include "llvm/Support/TargetSelect.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 class TestPPC64InstEmulation : public testing::Test {
30 public:
31   static void SetUpTestCase();
32   static void TearDownTestCase();
33 
34   //  virtual void SetUp() override { }
35   //  virtual void TearDown() override { }
36 
37 protected:
38 };
39 
SetUpTestCase()40 void TestPPC64InstEmulation::SetUpTestCase() {
41   llvm::InitializeAllTargets();
42   llvm::InitializeAllAsmPrinters();
43   llvm::InitializeAllTargetMCs();
44   llvm::InitializeAllDisassemblers();
45   DisassemblerLLVMC::Initialize();
46   EmulateInstructionPPC64::Initialize();
47 }
48 
TearDownTestCase()49 void TestPPC64InstEmulation::TearDownTestCase() {
50   DisassemblerLLVMC::Terminate();
51   EmulateInstructionPPC64::Terminate();
52 }
53 
TEST_F(TestPPC64InstEmulation,TestSimpleFunction)54 TEST_F(TestPPC64InstEmulation, TestSimpleFunction) {
55   ArchSpec arch("powerpc64le-linux-gnu");
56   std::unique_ptr<UnwindAssemblyInstEmulation> engine(
57       static_cast<UnwindAssemblyInstEmulation *>(
58           UnwindAssemblyInstEmulation::CreateInstance(arch)));
59   ASSERT_NE(nullptr, engine);
60 
61   UnwindPlan::RowSP row_sp;
62   AddressRange sample_range;
63   UnwindPlan unwind_plan(eRegisterKindLLDB);
64   UnwindPlan::Row::RegisterLocation regloc;
65 
66   // prologue and epilogue of:
67   // int main() {
68   //   int i = test();
69   //   return i;
70   // }
71   //
72   // compiled with clang -O0 -g
73   uint8_t data[] = {
74       // prologue
75       0x02, 0x10, 0x40, 0x3c, //  0: lis r2, 4098
76       0x00, 0x7f, 0x42, 0x38, //  4: addi r2, r2, 32512
77       0xa6, 0x02, 0x08, 0x7c, //  8: mflr r0
78       0xf8, 0xff, 0xe1, 0xfb, // 12: std r31, -8(r1)
79       0x10, 0x00, 0x01, 0xf8, // 16: std r0, 16(r1)
80       0x91, 0xff, 0x21, 0xf8, // 20: stdu r1, -112(r1)
81       0x78, 0x0b, 0x3f, 0x7c, // 24: mr r31, r1
82       0x00, 0x00, 0x60, 0x38, // 28: li r3, 0
83       0x64, 0x00, 0x7f, 0x90, // 32: stw r3, 100(r31)
84 
85       // epilogue
86       0x70, 0x00, 0x21, 0x38, // 36: addi r1, r1, 112
87       0x10, 0x00, 0x01, 0xe8, // 40: ld r0, 16(r1)
88       0xf8, 0xff, 0xe1, 0xeb, // 44: ld r31, -8(r1)
89       0xa6, 0x03, 0x08, 0x7c, // 48: mtlr r0
90       0x20, 0x00, 0x80, 0x4e  // 52: blr
91   };
92 
93   sample_range = AddressRange(0x1000, sizeof(data));
94 
95   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
96       sample_range, data, sizeof(data), unwind_plan));
97 
98   // 0: CFA=sp+0
99   row_sp = unwind_plan.GetRowForFunctionOffset(0);
100   EXPECT_EQ(0ull, row_sp->GetOffset());
101   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
102   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
103   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
104 
105   // 1: CFA=sp+0 => fp=[CFA-8]
106   row_sp = unwind_plan.GetRowForFunctionOffset(16);
107   EXPECT_EQ(16ull, row_sp->GetOffset());
108   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
109   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
110   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
111 
112   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
113   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
114   EXPECT_EQ(-8, regloc.GetOffset());
115 
116   // 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
117   row_sp = unwind_plan.GetRowForFunctionOffset(20);
118   EXPECT_EQ(20ull, row_sp->GetOffset());
119   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
120   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
121   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
122 
123   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
124   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
125   EXPECT_EQ(16, regloc.GetOffset());
126 
127   // 3: CFA=sp+112 => fp=[CFA-8] lr=[CFA+16]
128   row_sp = unwind_plan.GetRowForFunctionOffset(24);
129   EXPECT_EQ(24ull, row_sp->GetOffset());
130   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
131   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
132   EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset());
133 
134   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
135   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
136   EXPECT_EQ(-8, regloc.GetOffset());
137 
138   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
139   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
140   EXPECT_EQ(16, regloc.GetOffset());
141 
142   // 4: CFA=r31+112 => fp=[CFA-8] lr=[CFA+16]
143   row_sp = unwind_plan.GetRowForFunctionOffset(28);
144   EXPECT_EQ(28ull, row_sp->GetOffset());
145   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r31_ppc64le);
146   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
147   EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset());
148 
149   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
150   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
151   EXPECT_EQ(-8, regloc.GetOffset());
152 
153   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
154   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
155   EXPECT_EQ(16, regloc.GetOffset());
156 
157   // 5: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
158   row_sp = unwind_plan.GetRowForFunctionOffset(40);
159   EXPECT_EQ(40ull, row_sp->GetOffset());
160   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
161   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
162   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
163 
164   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
165   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
166   EXPECT_EQ(-8, regloc.GetOffset());
167 
168   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
169   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
170   EXPECT_EQ(16, regloc.GetOffset());
171 }
172 
TEST_F(TestPPC64InstEmulation,TestMediumFunction)173 TEST_F(TestPPC64InstEmulation, TestMediumFunction) {
174   ArchSpec arch("powerpc64le-linux-gnu");
175   std::unique_ptr<UnwindAssemblyInstEmulation> engine(
176       static_cast<UnwindAssemblyInstEmulation *>(
177           UnwindAssemblyInstEmulation::CreateInstance(arch)));
178   ASSERT_NE(nullptr, engine);
179 
180   UnwindPlan::RowSP row_sp;
181   AddressRange sample_range;
182   UnwindPlan unwind_plan(eRegisterKindLLDB);
183   UnwindPlan::Row::RegisterLocation regloc;
184 
185   // prologue and epilogue of main() (call-func.c),
186   // with several calls and stack variables.
187   //
188   // compiled with clang -O0 -g
189   uint8_t data[] = {
190       // prologue
191       0xa6, 0x02, 0x08, 0x7c, //  0: mflr r0
192       0xf8, 0xff, 0xe1, 0xfb, //  4: std r31, -8(r1)
193       0x10, 0x00, 0x01, 0xf8, //  8: std r0, 16(r1)
194       0x78, 0x0b, 0x3e, 0x7c, // 12: mr r30, r1
195       0xe0, 0x06, 0x20, 0x78, // 16: clrldi r0, r1, 59
196       0xa0, 0xfa, 0x00, 0x20, // 20: subfic r0, r0, -1376
197       0x6a, 0x01, 0x21, 0x7c, // 24: stdux r1, r1, r0
198       0x78, 0x0b, 0x3f, 0x7c, // 28: mr r31, r1
199 
200       // epilogue
201       0x00, 0x00, 0x21, 0xe8, // 32: ld r1, 0(r1)
202       0x20, 0x00, 0x80, 0x4e  // 36: blr
203   };
204 
205   sample_range = AddressRange(0x1000, sizeof(data));
206 
207   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
208       sample_range, data, sizeof(data), unwind_plan));
209 
210   // 0: CFA=sp+0
211   row_sp = unwind_plan.GetRowForFunctionOffset(0);
212   EXPECT_EQ(0ull, row_sp->GetOffset());
213   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
214   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
215   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
216 
217   // 1: CFA=sp+0 => fp=[CFA-8]
218   row_sp = unwind_plan.GetRowForFunctionOffset(8);
219   EXPECT_EQ(8ull, row_sp->GetOffset());
220   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
221   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
222   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
223 
224   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
225   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
226   EXPECT_EQ(-8, regloc.GetOffset());
227 
228   // 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
229   row_sp = unwind_plan.GetRowForFunctionOffset(12);
230   EXPECT_EQ(12ull, row_sp->GetOffset());
231   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
232   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
233   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
234 
235   EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
236   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
237   EXPECT_EQ(16, regloc.GetOffset());
238 
239   // 3: CFA=r30
240   row_sp = unwind_plan.GetRowForFunctionOffset(16);
241   EXPECT_EQ(16ull, row_sp->GetOffset());
242   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le);
243   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
244   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
245 
246   row_sp = unwind_plan.GetRowForFunctionOffset(32);
247   EXPECT_EQ(16ull, row_sp->GetOffset());
248   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le);
249   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
250   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
251 
252   // 4: CFA=sp+0
253   row_sp = unwind_plan.GetRowForFunctionOffset(36);
254   EXPECT_EQ(36ull, row_sp->GetOffset());
255   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
256   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
257   EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
258 }
259