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