1 //===-- Testx86AssemblyInspectionEngine.cpp -------------------------------===//
2 
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "gtest/gtest.h"
11 
12 #include <memory>
13 #include <vector>
14 
15 #include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h"
16 #include "lldb/Core/Address.h"
17 #include "lldb/Core/AddressRange.h"
18 #include "lldb/Symbol/UnwindPlan.h"
19 #include "lldb/Utility/ArchSpec.h"
20 #include "lldb/Utility/StreamString.h"
21 
22 #include "llvm/Support/TargetSelect.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 class Testx86AssemblyInspectionEngine : public testing::Test {
28 public:
29   static void SetUpTestCase();
30 
31   //  static void TearDownTestCase() { }
32 
33   //  virtual void SetUp() override { }
34 
35   //  virtual void TearDown() override { }
36 
37 protected:
38 };
39 
SetUpTestCase()40 void Testx86AssemblyInspectionEngine::SetUpTestCase() {
41   llvm::InitializeAllTargets();
42   llvm::InitializeAllAsmPrinters();
43   llvm::InitializeAllTargetMCs();
44   llvm::InitializeAllDisassemblers();
45 }
46 
47 // only defining the register names / numbers that the unwinder is actually
48 // using today
49 
50 // names should match the constants below.  These will be the eRegisterKindLLDB
51 // register numbers.
52 
53 const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",
54                                   "rsi", "rdi", "r8",  "r9",  "r10", "r11",
55                                   "r12", "r13", "r14", "r15", "rip"};
56 
57 enum x86_64_regs {
58   k_rax = 0,
59   k_rbx = 1,
60   k_rcx = 2,
61   k_rdx = 3,
62   k_rsp = 4,
63   k_rbp = 5,
64   k_rsi = 6,
65   k_rdi = 7,
66   k_r8 = 8,
67   k_r9 = 9,
68   k_r10 = 10,
69   k_r11 = 11,
70   k_r12 = 12,
71   k_r13 = 13,
72   k_r14 = 14,
73   k_r15 = 15,
74   k_rip = 16
75 };
76 
77 // names should match the constants below.  These will be the eRegisterKindLLDB
78 // register numbers.
79 
80 const char *i386_reg_names[] = {"eax", "ecx", "edx", "ebx", "esp",
81                                 "ebp", "esi", "edi", "eip"};
82 
83 enum i386_regs {
84   k_eax = 0,
85   k_ecx = 1,
86   k_edx = 2,
87   k_ebx = 3,
88   k_esp = 4,
89   k_ebp = 5,
90   k_esi = 6,
91   k_edi = 7,
92   k_eip = 8
93 };
94 
Getx86_64Inspector()95 std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {
96 
97   ArchSpec arch("x86_64-apple-macosx");
98   std::unique_ptr<x86AssemblyInspectionEngine> engine(
99       new x86AssemblyInspectionEngine(arch));
100 
101   std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
102   int i = 0;
103   for (const auto &name : x86_64_reg_names) {
104     x86AssemblyInspectionEngine::lldb_reg_info ri;
105     ri.name = name;
106     ri.lldb_regnum = i++;
107     lldb_regnums.push_back(ri);
108   }
109 
110   engine->Initialize(lldb_regnums);
111   return engine;
112 }
113 
Geti386Inspector()114 std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {
115 
116   ArchSpec arch("i386-apple-macosx");
117   std::unique_ptr<x86AssemblyInspectionEngine> engine(
118       new x86AssemblyInspectionEngine(arch));
119 
120   std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
121   int i = 0;
122   for (const auto &name : i386_reg_names) {
123     x86AssemblyInspectionEngine::lldb_reg_info ri;
124     ri.name = name;
125     ri.lldb_regnum = i++;
126     lldb_regnums.push_back(ri);
127   }
128 
129   engine->Initialize(lldb_regnums);
130   return engine;
131 }
132 
133 namespace lldb_private {
operator <<(std::ostream & OS,const UnwindPlan::Row::FAValue & CFA)134 static std::ostream &operator<<(std::ostream &OS,
135                                 const UnwindPlan::Row::FAValue &CFA) {
136   StreamString S;
137   CFA.Dump(S, nullptr, nullptr);
138   return OS << S.GetData();
139 }
140 } // namespace lldb_private
141 
TEST_F(Testx86AssemblyInspectionEngine,TestSimple64bitFrameFunction)142 TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
143   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
144 
145   // 'int main() { }' compiled for x86_64-apple-macosx with clang
146   uint8_t data[] = {
147       0x55,             // offset 0 -- pushq %rbp
148       0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
149       0x31, 0xc0,       // offset 4 -- xorl %eax, %eax
150       0x5d,             // offset 6 -- popq %rbp
151       0xc3              // offset 7 -- retq
152   };
153 
154   AddressRange sample_range(0x1000, sizeof(data));
155 
156   UnwindPlan unwind_plan(eRegisterKindLLDB);
157   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
158       data, sizeof(data), sample_range, unwind_plan));
159 
160   // Expect four unwind rows:
161   // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
162   // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
163   // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
164   // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
165 
166   EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
167   EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
168               eLazyBoolYes);
169   EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
170 
171   UnwindPlan::Row::RegisterLocation regloc;
172 
173   // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
174   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
175   EXPECT_EQ(0ull, row_sp->GetOffset());
176   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
177   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
178   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
179 
180   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
181   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
182   EXPECT_EQ(-8, regloc.GetOffset());
183 
184   // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
185   row_sp = unwind_plan.GetRowForFunctionOffset(1);
186   EXPECT_EQ(1ull, row_sp->GetOffset());
187   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
188   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
189   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
190 
191   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
192   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
193   EXPECT_EQ(-8, regloc.GetOffset());
194 
195   // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
196   row_sp = unwind_plan.GetRowForFunctionOffset(4);
197   EXPECT_EQ(4ull, row_sp->GetOffset());
198   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
199   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
200   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
201 
202   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
203   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
204   EXPECT_EQ(-8, regloc.GetOffset());
205 
206   // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
207   row_sp = unwind_plan.GetRowForFunctionOffset(7);
208   EXPECT_EQ(7ull, row_sp->GetOffset());
209   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
210   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
211   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
212 
213   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
214   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
215   EXPECT_EQ(-8, regloc.GetOffset());
216 }
217 
TEST_F(Testx86AssemblyInspectionEngine,TestSimple32bitFrameFunction)218 TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) {
219   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
220 
221   // 'int main() { }' compiled for i386-apple-macosx with clang
222   uint8_t data[] = {
223       0x55,       // offset 0 -- pushl %ebp
224       0x89, 0xe5, // offset 1 -- movl %esp, %ebp
225       0x31, 0xc0, // offset 3 -- xorl %eax, %eax
226       0x5d,       // offset 5 -- popl %ebp
227       0xc3        // offset 6 -- retl
228   };
229 
230   AddressRange sample_range(0x1000, sizeof(data));
231 
232   UnwindPlan unwind_plan(eRegisterKindLLDB);
233   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
234       data, sizeof(data), sample_range, unwind_plan));
235 
236   // Expect four unwind rows:
237   // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
238   // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
239   // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
240   // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
241 
242   EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_esp);
243   EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
244               eLazyBoolYes);
245   EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
246 
247   UnwindPlan::Row::RegisterLocation regloc;
248 
249   // offset 0 -- pushl %ebp
250   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
251   EXPECT_EQ(0ull, row_sp->GetOffset());
252   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
253   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
254   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
255 
256   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
257   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
258   EXPECT_TRUE(regloc.GetOffset() == -4);
259 
260   // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
261   row_sp = unwind_plan.GetRowForFunctionOffset(1);
262   EXPECT_EQ(1ull, row_sp->GetOffset());
263   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
264   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
265   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
266 
267   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
268   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
269   EXPECT_EQ(-4, regloc.GetOffset());
270 
271   // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
272   row_sp = unwind_plan.GetRowForFunctionOffset(3);
273   EXPECT_EQ(3ull, row_sp->GetOffset());
274   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
275   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
276   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
277 
278   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
279   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
280   EXPECT_EQ(-4, regloc.GetOffset());
281 
282   // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
283   row_sp = unwind_plan.GetRowForFunctionOffset(6);
284   EXPECT_EQ(6ull, row_sp->GetOffset());
285   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
286   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
287   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
288 
289   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
290   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
291   EXPECT_EQ(-4, regloc.GetOffset());
292 }
293 
TEST_F(Testx86AssemblyInspectionEngine,Test64bitFramelessBigStackFrame)294 TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) {
295   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
296 
297   // this source file:
298   //
299   // #include <stdio.h>
300   // int main (int argc, char **argv)
301   // {
302   //
303   //     const int arrsize = 60;
304   //     int buf[arrsize * arrsize];
305   //     int accum = argc;
306   //     for (int i = 0; i < arrsize; i++)
307   //         for (int j = 0; j < arrsize; j++)
308   //         {
309   //             if (i > 0 && j > 0)
310   //             {
311   //                 int n = buf[(i-1) * (j-1)] * 2;
312   //                 int m = buf[(i-1) * (j-1)] / 2;
313   //                 int j = buf[(i-1) * (j-1)] + 2;
314   //                 int k = buf[(i-1) * (j-1)] - 2;
315   //                 printf ("%d ", n + m + j + k);
316   //                 buf[(i-1) * (j-1)] += n - m + j - k;
317   //             }
318   //             buf[i*j] = accum++;
319   //         }
320   //
321   //     return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
322   //     arrsize) - 3]);
323   // }
324   //
325   // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx
326 
327   uint8_t data[] = {
328       0x55,       // offset 0  -- pushq %rbp
329       0x41, 0x57, // offset 1  -- pushq %r15
330       0x41, 0x56, // offset 3  -- pushq %r14
331       0x41, 0x55, // offset 5  -- pushq %r13
332       0x41, 0x54, // offset 7  -- pushq %r12
333       0x53,       // offset 9  -- pushq %rbx
334       0x48, 0x81, 0xec, 0x68, 0x38, 0x00,
335       0x00, // offset 10 -- subq $0x3868, %rsp
336 
337       // ....
338 
339       0x48, 0x81, 0xc4, 0x68, 0x38, 0x00,
340       0x00,                        // offset 17 -- addq $0x3868, %rsp
341       0x5b,                        // offset 24 -- popq %rbx
342       0x41, 0x5c,                  // offset 25 -- popq %r12
343       0x41, 0x5d,                  // offset 27 -- popq %r13
344       0x41, 0x5e,                  // offset 29 -- popq %r14
345       0x41, 0x5f,                  // offset 31 -- popq %r15
346       0x5d,                        // offset 33 -- popq %rbp
347       0xc3,                        // offset 34 -- retq
348       0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever
349   };
350 
351   AddressRange sample_range(0x1000, sizeof(data));
352 
353   UnwindPlan unwind_plan(eRegisterKindLLDB);
354   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
355       data, sizeof(data), sample_range, unwind_plan));
356 
357   // Unwind rules should look like
358   // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
359   // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
360   // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
361   // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
362   // rip=[CFA-8
363   // 7: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
364   // r15=[CFA-24] rip=[CFA-8]
365   // 9: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
366   // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
367   // 10: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
368   // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
369   // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
370   // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
371 
372   // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
373   // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
374   // 25: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
375   // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
376   // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
377   // r15=[CFA-24] rip=[CFA-8]
378   // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
379   // rip=[CFA-8]
380   // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
381   // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
382   // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
383 
384   UnwindPlan::Row::RegisterLocation regloc;
385 
386   // grab the Row for when the prologue has finished executing:
387   // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
388   // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
389 
390   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(17);
391 
392   EXPECT_EQ(17ull, row_sp->GetOffset());
393   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
394   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
395   EXPECT_EQ(14496, row_sp->GetCFAValue().GetOffset());
396 
397   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
398   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
399   EXPECT_EQ(-8, regloc.GetOffset());
400 
401   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
402   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
403   EXPECT_EQ(-16, regloc.GetOffset());
404 
405   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
406   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
407   EXPECT_EQ(-24, regloc.GetOffset());
408 
409   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
410   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
411   EXPECT_EQ(-32, regloc.GetOffset());
412 
413   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
414   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
415   EXPECT_EQ(-40, regloc.GetOffset());
416 
417   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
418   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
419   EXPECT_EQ(-48, regloc.GetOffset());
420 
421   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
422   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
423   EXPECT_EQ(-56, regloc.GetOffset());
424 
425   // grab the Row for when the epilogue has finished executing:
426   // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
427 
428   row_sp = unwind_plan.GetRowForFunctionOffset(34);
429 
430   EXPECT_EQ(34ull, row_sp->GetOffset());
431   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
432   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
433   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
434 
435   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
436   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
437   EXPECT_EQ(-8, regloc.GetOffset());
438 
439   // these could be set to IsSame and be valid -- meaning that the
440   // register value is the same as the caller's -- but I'd rather
441   // they not be mentioned at all.
442 
443   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
444   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
445   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
446   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
447   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
448   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
449   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
450   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
451   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
452   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
453   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
454   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
455   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
456   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
457   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
458 }
459 
TEST_F(Testx86AssemblyInspectionEngine,Test32bitFramelessBigStackFrame)460 TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessBigStackFrame) {
461   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
462 
463   // this source file:
464   //
465   // #include <stdio.h>
466   // int main (int argc, char **argv)
467   // {
468   //
469   //     const int arrsize = 60;
470   //     int buf[arrsize * arrsize];
471   //     int accum = argc;
472   //     for (int i = 0; i < arrsize; i++)
473   //         for (int j = 0; j < arrsize; j++)
474   //         {
475   //             if (i > 0 && j > 0)
476   //             {
477   //                 int n = buf[(i-1) * (j-1)] * 2;
478   //                 int m = buf[(i-1) * (j-1)] / 2;
479   //                 int j = buf[(i-1) * (j-1)] + 2;
480   //                 int k = buf[(i-1) * (j-1)] - 2;
481   //                 printf ("%d ", n + m + j + k);
482   //                 buf[(i-1) * (j-1)] += n - m + j - k;
483   //             }
484   //             buf[i*j] = accum++;
485   //         }
486   //
487   //     return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
488   //     arrsize) - 3]);
489   // }
490   //
491   // compiled 'clang -arch i386 -fomit-frame-pointer -Os' for i386-apple-macosx
492 
493   // simplified assembly version of the above function, which is used as the
494   // input
495   // data:
496   //
497   // 	.section	__TEXT,__text,regular,pure_instructions
498   // 	.macosx_version_min 10, 12
499   // 	.globl	_main
500   // 	.align	4, 0x90
501   // _main:                                  ## @main
502   // ## BB#0:
503   // 	pushl %ebp
504   // 	pushl %ebx
505   // 	pushl %edi
506   // 	pushl %esi
507   // L0$pb:
508   // 	subl $0x386c, %esp
509   //     calll L1
510   // L1:
511   //     popl %ecx
512   //     movl %ecx, 0x8(%esp)
513   //     subl $0x8, %esp
514   //     pushl %eax
515   //     pushl 0x20(%esp)
516   //     calll _puts
517   //     addl $0x10, %esp
518   //     incl %ebx
519   //     addl $0x386c, %esp
520   //     popl %esi
521   //     popl %edi
522   //     popl %ebx
523   //     popl %ebp
524   //     retl
525   //
526   // 	.section	__TEXT,__cstring,cstring_literals
527   // L_.str:                                 ## @.str
528   // 	.asciz	"HI"
529   //
530   //
531   // .subsections_via_symbols
532 
533   uint8_t data[] = {
534       0x55,
535       // offset 0 -- pushl %ebp
536 
537       0x53,
538       // offset 1 -- pushl %ebx
539 
540       0x57,
541       // offset 2 -- pushl %edi
542 
543       0x56,
544       // offset 3 -- pushl %esi
545 
546       0x81, 0xec, 0x6c, 0x38, 0x00, 0x00,
547       // offset 4 -- subl $0x386c, %esp
548 
549       0xe8, 0x00, 0x00, 0x00, 0x00,
550       // offset 10 -- calll 0
551       // call the next instruction, to put the pc on the stack
552 
553       0x59,
554       // offset 15 -- popl %ecx
555       // pop the saved pc address into ecx
556 
557       0x89, 0x4c, 0x24, 0x08,
558       // offset 16 -- movl %ecx, 0x8(%esp)
559 
560       // ....
561 
562       0x83, 0xec, 0x08,
563       // offset 20 -- subl $0x8, %esp
564 
565       0x50,
566       // offset 23 -- pushl %eax
567 
568       0xff, 0x74, 0x24, 0x20,
569       // offset 24 -- pushl 0x20(%esp)
570 
571       0xe8, 0x8c, 0x00, 0x00, 0x00,
572       // offset 28 -- calll puts
573 
574       0x83, 0xc4, 0x10,
575       // offset 33 -- addl $0x10, %esp
576       // get esp back to the value it was before the
577       // alignment & argument saves for the puts call
578 
579       0x43,
580       // offset 36 -- incl %ebx
581 
582       // ....
583 
584       0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00,
585       // offset 37 -- addl $0x386c, %esp
586 
587       0x5e,
588       // offset 43 -- popl %esi
589 
590       0x5f,
591       // offset 44 -- popl %edi
592 
593       0x5b,
594       // offset 45 -- popl %ebx
595 
596       0x5d,
597       // offset 46 -- popl %ebp
598 
599       0xc3,
600       // offset 47 -- retl
601 
602       0xe8, 0x12, 0x34, 0x56, 0x78,
603       // offset 48 -- calll __stack_chk_fail
604   };
605 
606   AddressRange sample_range(0x1000, sizeof(data));
607 
608   UnwindPlan unwind_plan(eRegisterKindLLDB);
609   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
610       data, sizeof(data), sample_range, unwind_plan));
611 
612   // Unwind rules should look like
613   //
614   //   0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
615   //   1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
616   //   2: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
617   //   3: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
618   //   eip=[CFA-4]
619   //   4: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
620   //   esp=CFA+0 eip=[CFA-4]
621   //  10: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
622   //  esp=CFA+0 eip=[CFA-4]
623   //  15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
624   //  esp=CFA+0 eip=[CFA-4]
625   //  16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
626   //  esp=CFA+0 eip=[CFA-4]
627   //
628   //  ....
629   //
630   //  23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
631   //  esp=CFA+0 eip=[CFA-4]
632   //  24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
633   //  esp=CFA+0 eip=[CFA-4]
634   //  28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
635   //  esp=CFA+0 eip=[CFA-4]
636   //  36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
637   //  esp=CFA+0 eip=[CFA-4]
638   //
639   //  .....
640   //
641   //  37: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
642   //  esp=CFA+0 eip=[CFA-4]
643   //  43: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
644   //  esp=CFA+0 eip=[CFA-4]
645   //  44: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
646   //  eip=[CFA-4]
647   //  45: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
648   //  46: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
649   //  47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
650   //  48: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
651   //  esp=CFA+0 eip=[CFA-4]
652 
653   UnwindPlan::Row::RegisterLocation regloc;
654   UnwindPlan::RowSP row_sp;
655 
656   // Check that we get the CFA correct for the pic base setup sequence
657 
658   // CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
659   // esp=CFA+0 eip=[CFA-4]
660   row_sp = unwind_plan.GetRowForFunctionOffset(10);
661   EXPECT_EQ(10ull, row_sp->GetOffset());
662   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
663   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
664   EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
665 
666   // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
667   // esp=CFA+0 eip=[CFA-4]
668   row_sp = unwind_plan.GetRowForFunctionOffset(15);
669   EXPECT_EQ(15ull, row_sp->GetOffset());
670   EXPECT_EQ(14468, row_sp->GetCFAValue().GetOffset());
671 
672   // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
673   // esp=CFA+0 eip=[CFA-4]
674   row_sp = unwind_plan.GetRowForFunctionOffset(16);
675   EXPECT_EQ(16ull, row_sp->GetOffset());
676   EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
677 
678   // Check that the row for offset 16 has the registers saved that we expect
679 
680   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
681   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
682   EXPECT_EQ(-4, regloc.GetOffset());
683 
684   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
685   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
686   EXPECT_EQ(-8, regloc.GetOffset());
687 
688   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
689   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
690   EXPECT_EQ(-12, regloc.GetOffset());
691 
692   EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
693   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
694   EXPECT_EQ(-16, regloc.GetOffset());
695 
696   EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
697   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
698   EXPECT_EQ(-20, regloc.GetOffset());
699 
700   //
701   // Check the pushing & popping around the call printf instruction
702 
703   // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
704   // esp=CFA+0 eip=[CFA-4]
705   row_sp = unwind_plan.GetRowForFunctionOffset(23);
706   EXPECT_EQ(23ull, row_sp->GetOffset());
707   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
708   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
709   EXPECT_EQ(14472, row_sp->GetCFAValue().GetOffset());
710 
711   // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
712   // esp=CFA+0 eip=[CFA-4]
713   row_sp = unwind_plan.GetRowForFunctionOffset(24);
714   EXPECT_EQ(24ull, row_sp->GetOffset());
715   EXPECT_EQ(14476, row_sp->GetCFAValue().GetOffset());
716 
717   // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
718   // esp=CFA+0 eip=[CFA-4]
719   row_sp = unwind_plan.GetRowForFunctionOffset(28);
720   EXPECT_EQ(28ull, row_sp->GetOffset());
721   EXPECT_EQ(14480, row_sp->GetCFAValue().GetOffset());
722 
723   // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
724   // esp=CFA+0 eip=[CFA-4]
725   row_sp = unwind_plan.GetRowForFunctionOffset(36);
726   EXPECT_EQ(36ull, row_sp->GetOffset());
727   EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
728 
729   // Check that the epilogue gets us back to the original unwind state
730 
731   //  47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
732   row_sp = unwind_plan.GetRowForFunctionOffset(47);
733   EXPECT_EQ(47ull, row_sp->GetOffset());
734   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
735   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
736   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
737 
738   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
739   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
740   EXPECT_EQ(-4, regloc.GetOffset());
741 
742   EXPECT_TRUE(row_sp->GetRegisterInfo(k_esp, regloc));
743   EXPECT_TRUE(regloc.IsCFAPlusOffset());
744   EXPECT_EQ(0, regloc.GetOffset());
745 
746   // Check that no unexpected registers were saved
747 
748   EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
749   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
750   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
751   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
752   EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
753   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
754   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
755 }
756 
TEST_F(Testx86AssemblyInspectionEngine,Test64bitFramelessSmallStackFrame)757 TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessSmallStackFrame) {
758   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
759 
760   // this source file:
761   // #include <stdio.h>
762   // int main () {
763   //    puts ("HI");
764   // }
765   //
766   // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx
767 
768   uint8_t data[] = {
769       0x50,
770       // offset 0  -- pushq %rax
771 
772       0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00,
773       // offset 1 -- leaq 0x32(%rip), %rdi ; "HI"
774 
775       0xe8, 0x0b, 0x00, 0x00, 0x00,
776       // offset 8 -- callq 0x100000f58 ; puts
777 
778       0x31, 0xc9,
779       // offset 13 -- xorl %ecx, %ecx
780 
781       0x89, 0x44, 0x24, 0x04,
782       // offset 15 -- movl %eax, 0x4(%rsp)
783 
784       0x89, 0xc8,
785       // offset 19 -- movl %ecx, %eax
786 
787       0x59,
788       // offset 21 -- popq %rcx
789 
790       0xc3
791       // offset 22 -- retq
792   };
793 
794   AddressRange sample_range(0x1000, sizeof(data));
795 
796   UnwindPlan unwind_plan(eRegisterKindLLDB);
797   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
798       data, sizeof(data), sample_range, unwind_plan));
799 
800   // Unwind rules should look like
801   //     0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
802   //     1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
803   //    22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
804 
805   UnwindPlan::Row::RegisterLocation regloc;
806 
807   // grab the Row for when the prologue has finished executing:
808   //     1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
809 
810   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(13);
811 
812   EXPECT_EQ(1ull, row_sp->GetOffset());
813   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
814   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
815   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
816 
817   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
818   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
819   EXPECT_EQ(-8, regloc.GetOffset());
820 
821   // none of these were spilled
822 
823   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
824   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
825   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
826   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
827   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
828   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
829   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
830   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
831   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
832   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
833   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
834   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
835   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
836   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
837   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
838 
839   // grab the Row for when the epilogue has finished executing:
840   //     22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
841 
842   row_sp = unwind_plan.GetRowForFunctionOffset(22);
843 
844   EXPECT_EQ(22ull, row_sp->GetOffset());
845   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
846   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
847   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
848 
849   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
850   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
851   EXPECT_EQ(-8, regloc.GetOffset());
852 }
853 
TEST_F(Testx86AssemblyInspectionEngine,Test32bitFramelessSmallStackFrame)854 TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) {
855   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
856 
857   // this source file:
858   // #include <stdio.h>
859   // int main () {
860   //    puts ("HI");
861   // }
862   //
863   // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx
864 
865   uint8_t data[] = {
866       0x83, 0xec, 0x0c,
867       // offset 0 -- subl $0xc, %esp
868 
869       0xe8, 0x00, 0x00, 0x00, 0x00,
870       // offset 3 -- calll 0 {call the next instruction, to put the pc on
871       // the stack}
872 
873       0x58,
874       // offset 8 -- popl %eax {pop the saved pc value off stack, into eax}
875 
876       0x8d, 0x80, 0x3a, 0x00, 0x00, 0x00,
877       // offset 9 -- leal 0x3a(%eax),%eax
878 
879       0x89, 0x04, 0x24,
880       // offset 15 -- movl %eax, (%esp)
881 
882       0xe8, 0x0d, 0x00, 0x00, 0x00,
883       // offset 18 -- calll 0x1f94 (puts)
884 
885       0x31, 0xc9,
886       // offset 23 -- xorl %ecx, %ecx
887 
888       0x89, 0x44, 0x24, 0x08,
889       // offset 25 -- movl %eax, 0x8(%esp)
890 
891       0x89, 0xc8,
892       // offset 29 -- movl %ecx, %eax
893 
894       0x83, 0xc4, 0x0c,
895       // offset 31 -- addl $0xc, %esp
896 
897       0xc3
898       // offset 34 -- retl
899   };
900 
901   AddressRange sample_range(0x1000, sizeof(data));
902 
903   UnwindPlan unwind_plan(eRegisterKindLLDB);
904   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
905       data, sizeof(data), sample_range, unwind_plan));
906 
907   // Unwind rules should look like
908   // row[0]:    0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
909   // row[1]:    3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
910   // row[2]:    8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
911   // row[3]:    9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
912   // row[4]:   34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
913 
914   UnwindPlan::Row::RegisterLocation regloc;
915 
916   // Check unwind state before we set up the picbase register
917   //      3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
918 
919   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(3);
920 
921   EXPECT_EQ(3ull, row_sp->GetOffset());
922   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
923   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
924   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
925 
926   // Check unwind state after we call the next instruction
927   // 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
928 
929   row_sp = unwind_plan.GetRowForFunctionOffset(8);
930   EXPECT_EQ(8ull, row_sp->GetOffset());
931   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
932   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
933   EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
934 
935   // Check unwind state after we pop the pic base value off the stack
936   // row[3]:    9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
937 
938   row_sp = unwind_plan.GetRowForFunctionOffset(9);
939   EXPECT_EQ(9ull, row_sp->GetOffset());
940   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
941   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
942   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
943 
944   // Check that no unexpected registers were saved
945 
946   EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
947   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
948   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
949   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
950   EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
951   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
952   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
953 
954   // verify that we get back to the original unwind state before the ret
955   //  34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
956 
957   row_sp = unwind_plan.GetRowForFunctionOffset(34);
958   EXPECT_EQ(34ull, row_sp->GetOffset());
959   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
960   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
961   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
962 }
963 
TEST_F(Testx86AssemblyInspectionEngine,TestPushRBP)964 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
965   UnwindPlan::Row::RegisterLocation regloc;
966   UnwindPlan::RowSP row_sp;
967 
968   uint8_t data[] = {
969       0x55, // pushq %rbp
970       0x90  // nop
971   };
972 
973   AddressRange sample_range(0x1000, sizeof(data));
974   UnwindPlan unwind_plan(eRegisterKindLLDB);
975 
976   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
977   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
978       data, sizeof(data), sample_range, unwind_plan));
979 
980   row_sp = unwind_plan.GetRowForFunctionOffset(1);
981 
982   EXPECT_EQ(1ull, row_sp->GetOffset());
983   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
984   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
985   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
986 
987   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
988   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
989   EXPECT_EQ(-16, regloc.GetOffset());
990 
991   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
992   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
993       data, sizeof(data), sample_range, unwind_plan));
994 
995   row_sp = unwind_plan.GetRowForFunctionOffset(1);
996 
997   EXPECT_EQ(1ull, row_sp->GetOffset());
998   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
999   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1000   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1001 
1002   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
1003   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1004   EXPECT_EQ(-8, regloc.GetOffset());
1005 }
1006 
TEST_F(Testx86AssemblyInspectionEngine,TestPushImm)1007 TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
1008   UnwindPlan::Row::RegisterLocation regloc;
1009   UnwindPlan::RowSP row_sp;
1010 
1011   uint8_t data[] = {
1012       0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
1013       0x6a, 0x7d,                   // pushl $0x7d
1014       0x90                          // nop
1015   };
1016 
1017   AddressRange sample_range(0x1000, sizeof(data));
1018   UnwindPlan unwind_plan(eRegisterKindLLDB);
1019 
1020   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1021   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1022       data, sizeof(data), sample_range, unwind_plan));
1023 
1024   row_sp = unwind_plan.GetRowForFunctionOffset(5);
1025   EXPECT_EQ(5ull, row_sp->GetOffset());
1026   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1027   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1028   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1029 
1030   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1031   EXPECT_EQ(7ull, row_sp->GetOffset());
1032   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1033   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1034   EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
1035 
1036   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1037   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1038       data, sizeof(data), sample_range, unwind_plan));
1039 
1040   row_sp = unwind_plan.GetRowForFunctionOffset(5);
1041   EXPECT_EQ(5ull, row_sp->GetOffset());
1042   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1043   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1044   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1045 
1046   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1047   EXPECT_EQ(7ull, row_sp->GetOffset());
1048   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1049   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1050   EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
1051 }
1052 
1053 // We treat 'pushq $0' / 'pushl $0' specially - this shows up
1054 // in the first function called in a new thread and it needs to
1055 // put a 0 as the saved pc.  We pretend it didn't change the CFA.
TEST_F(Testx86AssemblyInspectionEngine,TestPush0)1056 TEST_F(Testx86AssemblyInspectionEngine, TestPush0) {
1057   UnwindPlan::Row::RegisterLocation regloc;
1058   UnwindPlan::RowSP row_sp;
1059 
1060   uint8_t data[] = {
1061       0x6a, 0x00, // pushq $0
1062       0x90        // nop
1063   };
1064 
1065   AddressRange sample_range(0x1000, sizeof(data));
1066   UnwindPlan unwind_plan(eRegisterKindLLDB);
1067 
1068   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1069   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1070       data, sizeof(data), sample_range, unwind_plan));
1071 
1072   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1073 
1074   // We're verifying that no row was created for the 'pushq $0'
1075   EXPECT_EQ(0ull, row_sp->GetOffset());
1076 
1077   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1078   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1079       data, sizeof(data), sample_range, unwind_plan));
1080 
1081   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1082 
1083   // We're verifying that no row was created for the 'pushq $0'
1084   EXPECT_EQ(0ull, row_sp->GetOffset());
1085 }
1086 
TEST_F(Testx86AssemblyInspectionEngine,TestPushExtended)1087 TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
1088   UnwindPlan::Row::RegisterLocation regloc;
1089   UnwindPlan::RowSP row_sp;
1090 
1091   uint8_t data[] = {
1092       0xff, 0x74, 0x24, 0x20,             // pushl 0x20(%esp)
1093       0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl  0xf001ce(%esi)
1094       0xff, 0x30,                         // pushl  (%eax)
1095       0x90                                // nop
1096   };
1097 
1098   AddressRange sample_range(0x1000, sizeof(data));
1099   UnwindPlan unwind_plan(eRegisterKindLLDB);
1100 
1101   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1102   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1103       data, sizeof(data), sample_range, unwind_plan));
1104 
1105   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1106 
1107   EXPECT_EQ(4ull, row_sp->GetOffset());
1108   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1109   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1110   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1111 
1112   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1113   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1114       data, sizeof(data), sample_range, unwind_plan));
1115 
1116   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1117   EXPECT_EQ(4ull, row_sp->GetOffset());
1118   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1119   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1120   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1121 
1122   row_sp = unwind_plan.GetRowForFunctionOffset(10);
1123   EXPECT_EQ(10ull, row_sp->GetOffset());
1124   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1125   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1126   EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
1127 
1128   row_sp = unwind_plan.GetRowForFunctionOffset(12);
1129   EXPECT_EQ(12ull, row_sp->GetOffset());
1130   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1131   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1132   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1133 }
1134 
TEST_F(Testx86AssemblyInspectionEngine,TestPushR15)1135 TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
1136   UnwindPlan::Row::RegisterLocation regloc;
1137   UnwindPlan::RowSP row_sp;
1138 
1139   uint8_t data[] = {
1140       0x41, 0x57, // pushq %r15
1141       0x90        // nop
1142   };
1143 
1144   AddressRange sample_range(0x1000, sizeof(data));
1145   UnwindPlan unwind_plan(eRegisterKindLLDB);
1146 
1147   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1148   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1149       data, sizeof(data), sample_range, unwind_plan));
1150 
1151   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1152 
1153   EXPECT_EQ(2ull, row_sp->GetOffset());
1154   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1155   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1156   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1157 
1158   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
1159   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1160   EXPECT_EQ(-16, regloc.GetOffset());
1161 }
1162 
TEST_F(Testx86AssemblyInspectionEngine,TestPushR14)1163 TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {
1164   UnwindPlan::Row::RegisterLocation regloc;
1165   UnwindPlan::RowSP row_sp;
1166 
1167   uint8_t data[] = {
1168       0x41, 0x56, // pushq %r14
1169       0x90        // nop
1170   };
1171 
1172   AddressRange sample_range(0x1000, sizeof(data));
1173   UnwindPlan unwind_plan(eRegisterKindLLDB);
1174 
1175   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1176   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1177       data, sizeof(data), sample_range, unwind_plan));
1178 
1179   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1180 
1181   EXPECT_EQ(2ull, row_sp->GetOffset());
1182   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1183   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1184   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1185 
1186   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
1187   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1188   EXPECT_EQ(-16, regloc.GetOffset());
1189 }
1190 
TEST_F(Testx86AssemblyInspectionEngine,TestPushR13)1191 TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {
1192   UnwindPlan::Row::RegisterLocation regloc;
1193   UnwindPlan::RowSP row_sp;
1194 
1195   uint8_t data[] = {
1196       0x41, 0x55, // pushq %r13
1197       0x90        // nop
1198   };
1199 
1200   AddressRange sample_range(0x1000, sizeof(data));
1201   UnwindPlan unwind_plan(eRegisterKindLLDB);
1202 
1203   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1204   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1205       data, sizeof(data), sample_range, unwind_plan));
1206 
1207   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1208 
1209   EXPECT_EQ(2ull, row_sp->GetOffset());
1210   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1211   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1212   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1213 
1214   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
1215   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1216   EXPECT_EQ(-16, regloc.GetOffset());
1217 }
1218 
TEST_F(Testx86AssemblyInspectionEngine,TestPushR12)1219 TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {
1220   UnwindPlan::Row::RegisterLocation regloc;
1221   UnwindPlan::RowSP row_sp;
1222 
1223   uint8_t data[] = {
1224       0x41, 0x54, // pushq %r13
1225       0x90        // nop
1226   };
1227 
1228   AddressRange sample_range(0x1000, sizeof(data));
1229   UnwindPlan unwind_plan(eRegisterKindLLDB);
1230 
1231   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1232   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1233       data, sizeof(data), sample_range, unwind_plan));
1234 
1235   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1236 
1237   EXPECT_EQ(2ull, row_sp->GetOffset());
1238   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1239   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1240   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1241 
1242   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
1243   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1244   EXPECT_EQ(-16, regloc.GetOffset());
1245 }
1246 
TEST_F(Testx86AssemblyInspectionEngine,TestPushRBX)1247 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {
1248   UnwindPlan::Row::RegisterLocation regloc;
1249   UnwindPlan::RowSP row_sp;
1250 
1251   uint8_t data[] = {
1252       0x53, // pushq %rbx
1253       0x90  // nop
1254   };
1255 
1256   AddressRange sample_range(0x1000, sizeof(data));
1257   UnwindPlan unwind_plan(eRegisterKindLLDB);
1258 
1259   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1260   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1261       data, sizeof(data), sample_range, unwind_plan));
1262 
1263   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1264 
1265   EXPECT_EQ(1ull, row_sp->GetOffset());
1266   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1267   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1268   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1269 
1270   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
1271   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1272   EXPECT_EQ(-16, regloc.GetOffset());
1273 }
1274 
1275 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1276 // eax, ecx, edx are all considered volatile and push/pops of them are
1277 // not tracked (except to keep track of stack pointer movement)
TEST_F(Testx86AssemblyInspectionEngine,TestPushEAX)1278 TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) {
1279   UnwindPlan::Row::RegisterLocation regloc;
1280   UnwindPlan::RowSP row_sp;
1281   AddressRange sample_range;
1282   UnwindPlan unwind_plan(eRegisterKindLLDB);
1283   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1284 
1285   uint8_t data[] = {
1286       0x50, // pushl %eax
1287       0x90  // nop
1288   };
1289 
1290   sample_range = AddressRange(0x1000, sizeof(data));
1291 
1292   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1293       data, sizeof(data), sample_range, unwind_plan));
1294 
1295   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1296   EXPECT_EQ(1ull, row_sp->GetOffset());
1297   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1298   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1299   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1300 
1301   EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
1302 }
1303 
1304 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1305 // eax, ecx, edx are all considered volatile and push/pops of them are
1306 // not tracked (except to keep track of stack pointer movement)
TEST_F(Testx86AssemblyInspectionEngine,TestPushECX)1307 TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) {
1308   UnwindPlan::Row::RegisterLocation regloc;
1309   UnwindPlan::RowSP row_sp;
1310   AddressRange sample_range;
1311   UnwindPlan unwind_plan(eRegisterKindLLDB);
1312   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1313 
1314   uint8_t data[] = {
1315       0x51, // pushl %ecx
1316       0x90  // nop
1317   };
1318 
1319   sample_range = AddressRange(0x1000, sizeof(data));
1320 
1321   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1322       data, sizeof(data), sample_range, unwind_plan));
1323 
1324   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1325   EXPECT_EQ(1ull, row_sp->GetOffset());
1326   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1327   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1328   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1329 
1330   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
1331 }
1332 
1333 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1334 // eax, ecx, edx are all considered volatile and push/pops of them are
1335 // not tracked (except to keep track of stack pointer movement)
TEST_F(Testx86AssemblyInspectionEngine,TestPushEDX)1336 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) {
1337   UnwindPlan::Row::RegisterLocation regloc;
1338   UnwindPlan::RowSP row_sp;
1339   AddressRange sample_range;
1340   UnwindPlan unwind_plan(eRegisterKindLLDB);
1341   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1342 
1343   uint8_t data[] = {
1344       0x52, // pushl %edx
1345       0x90  // nop
1346   };
1347 
1348   sample_range = AddressRange(0x1000, sizeof(data));
1349 
1350   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1351       data, sizeof(data), sample_range, unwind_plan));
1352 
1353   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1354   EXPECT_EQ(1ull, row_sp->GetOffset());
1355   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1356   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1357   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1358 
1359   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
1360 }
1361 
TEST_F(Testx86AssemblyInspectionEngine,TestPushEBX)1362 TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {
1363   UnwindPlan::Row::RegisterLocation regloc;
1364   UnwindPlan::RowSP row_sp;
1365   AddressRange sample_range;
1366   UnwindPlan unwind_plan(eRegisterKindLLDB);
1367   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1368 
1369   uint8_t data[] = {
1370       0x53, // pushl %ebx
1371       0x90  // nop
1372   };
1373 
1374   sample_range = AddressRange(0x1000, sizeof(data));
1375 
1376   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1377       data, sizeof(data), sample_range, unwind_plan));
1378 
1379   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1380   EXPECT_EQ(1ull, row_sp->GetOffset());
1381   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1382   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1383   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1384 
1385   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
1386   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1387   EXPECT_EQ(-8, regloc.GetOffset());
1388 }
1389 
TEST_F(Testx86AssemblyInspectionEngine,TestPushEBP)1390 TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {
1391   UnwindPlan::Row::RegisterLocation regloc;
1392   UnwindPlan::RowSP row_sp;
1393   AddressRange sample_range;
1394   UnwindPlan unwind_plan(eRegisterKindLLDB);
1395   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1396 
1397   uint8_t data[] = {
1398       0x55, // pushl %ebp
1399       0x90  // nop
1400   };
1401 
1402   sample_range = AddressRange(0x1000, sizeof(data));
1403 
1404   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1405       data, sizeof(data), sample_range, unwind_plan));
1406 
1407   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1408   EXPECT_EQ(1ull, row_sp->GetOffset());
1409   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1410   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1411   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1412 
1413   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
1414   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1415   EXPECT_EQ(-8, regloc.GetOffset());
1416 }
1417 
TEST_F(Testx86AssemblyInspectionEngine,TestPushRBPWithREX)1418 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBPWithREX) {
1419   UnwindPlan::Row::RegisterLocation regloc;
1420   UnwindPlan::RowSP row_sp;
1421 
1422   uint8_t data[] = {
1423       0x40, 0x55, // pushq %rbp
1424       0x90  // nop
1425   };
1426 
1427   AddressRange sample_range(0x1000, sizeof(data));
1428   UnwindPlan unwind_plan(eRegisterKindLLDB);
1429 
1430   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1431   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1432       data, sizeof(data), sample_range, unwind_plan));
1433 
1434   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1435 
1436   EXPECT_EQ(2ull, row_sp->GetOffset());
1437   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1438   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1439   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1440 
1441   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
1442   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1443   EXPECT_EQ(-16, regloc.GetOffset());
1444 }
1445 
TEST_F(Testx86AssemblyInspectionEngine,TestPushESI)1446 TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {
1447   UnwindPlan::Row::RegisterLocation regloc;
1448   UnwindPlan::RowSP row_sp;
1449   AddressRange sample_range;
1450   UnwindPlan unwind_plan(eRegisterKindLLDB);
1451   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1452 
1453   uint8_t data[] = {
1454       0x56, // pushl %esi
1455       0x90  // nop
1456   };
1457 
1458   sample_range = AddressRange(0x1000, sizeof(data));
1459 
1460   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1461       data, sizeof(data), sample_range, unwind_plan));
1462 
1463   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1464   EXPECT_EQ(1ull, row_sp->GetOffset());
1465   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1466   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1467   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1468 
1469   EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
1470   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1471   EXPECT_EQ(-8, regloc.GetOffset());
1472 }
1473 
TEST_F(Testx86AssemblyInspectionEngine,TestPushEDI)1474 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {
1475   UnwindPlan::Row::RegisterLocation regloc;
1476   UnwindPlan::RowSP row_sp;
1477   AddressRange sample_range;
1478   UnwindPlan unwind_plan(eRegisterKindLLDB);
1479   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1480 
1481   uint8_t data[] = {
1482       0x57, // pushl %edi
1483       0x90  // nop
1484   };
1485 
1486   sample_range = AddressRange(0x1000, sizeof(data));
1487 
1488   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1489       data, sizeof(data), sample_range, unwind_plan));
1490 
1491   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1492   EXPECT_EQ(1ull, row_sp->GetOffset());
1493   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1494   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1495   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1496 
1497   EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
1498   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1499   EXPECT_EQ(-8, regloc.GetOffset());
1500 }
1501 
TEST_F(Testx86AssemblyInspectionEngine,TestMovRSPtoRBP)1502 TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
1503   UnwindPlan::Row::RegisterLocation regloc;
1504   UnwindPlan::RowSP row_sp;
1505 
1506   uint8_t data64_1[] = {
1507       0x48, 0x8b, 0xec, // movq %rsp, %rbp
1508       0x90              // nop
1509   };
1510 
1511   AddressRange sample_range(0x1000, sizeof(data64_1));
1512   UnwindPlan unwind_plan(eRegisterKindLLDB);
1513 
1514   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1515   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1516       data64_1, sizeof(data64_1), sample_range, unwind_plan));
1517 
1518   row_sp = unwind_plan.GetRowForFunctionOffset(3);
1519 
1520   EXPECT_EQ(3ull, row_sp->GetOffset());
1521   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
1522   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1523   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1524 
1525   uint8_t data64_2[] = {
1526       0x48, 0x89, 0xe5, // movq %rsp, %rbp
1527       0x90              // nop
1528   };
1529 
1530   sample_range = AddressRange(0x1000, sizeof(data64_2));
1531   unwind_plan.Clear();
1532   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1533       data64_2, sizeof(data64_2), sample_range, unwind_plan));
1534 
1535   row_sp = unwind_plan.GetRowForFunctionOffset(3);
1536   EXPECT_EQ(3ull, row_sp->GetOffset());
1537   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
1538   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1539   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1540 
1541   uint8_t data32_1[] = {
1542       0x8b, 0xec, // movl %rsp, %rbp
1543       0x90        // nop
1544   };
1545 
1546   sample_range = AddressRange(0x1000, sizeof(data32_1));
1547   unwind_plan.Clear();
1548   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1549       data32_1, sizeof(data32_1), sample_range, unwind_plan));
1550 
1551   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1552   EXPECT_EQ(2ull, row_sp->GetOffset());
1553   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
1554   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1555   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1556 
1557   uint8_t data32_2[] = {
1558       0x89, 0xe5, // movl %rsp, %rbp
1559       0x90        // nop
1560   };
1561 
1562   sample_range = AddressRange(0x1000, sizeof(data32_2));
1563   unwind_plan.Clear();
1564   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1565       data32_2, sizeof(data32_2), sample_range, unwind_plan));
1566 
1567   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1568   EXPECT_EQ(2ull, row_sp->GetOffset());
1569   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
1570   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1571   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1572 }
1573 
TEST_F(Testx86AssemblyInspectionEngine,TestSubRSP)1574 TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {
1575   UnwindPlan::Row::RegisterLocation regloc;
1576   UnwindPlan::RowSP row_sp;
1577   AddressRange sample_range;
1578   UnwindPlan unwind_plan(eRegisterKindLLDB);
1579   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1580 
1581   uint8_t data1[] = {
1582       0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp
1583       0x90                                      // nop
1584   };
1585 
1586   sample_range = AddressRange(0x1000, sizeof(data1));
1587 
1588   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1589       data1, sizeof(data1), sample_range, unwind_plan));
1590 
1591   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1592   EXPECT_EQ(7ull, row_sp->GetOffset());
1593   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1594   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1595   EXPECT_EQ(264, row_sp->GetCFAValue().GetOffset());
1596 
1597   uint8_t data2[] = {
1598       0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp
1599       0x90                    // nop
1600   };
1601 
1602   sample_range = AddressRange(0x1000, sizeof(data2));
1603 
1604   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1605       data2, sizeof(data2), sample_range, unwind_plan));
1606 
1607   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1608   EXPECT_EQ(4ull, row_sp->GetOffset());
1609   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1610   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1611   EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
1612 }
1613 
TEST_F(Testx86AssemblyInspectionEngine,TestSubESP)1614 TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {
1615   UnwindPlan::Row::RegisterLocation regloc;
1616   UnwindPlan::RowSP row_sp;
1617   AddressRange sample_range;
1618   UnwindPlan unwind_plan(eRegisterKindLLDB);
1619   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1620 
1621   uint8_t data1[] = {
1622       0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp
1623       0x90                                // nop
1624   };
1625 
1626   sample_range = AddressRange(0x1000, sizeof(data1));
1627 
1628   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1629       data1, sizeof(data1), sample_range, unwind_plan));
1630 
1631   row_sp = unwind_plan.GetRowForFunctionOffset(6);
1632   EXPECT_EQ(6ull, row_sp->GetOffset());
1633   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1634   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1635   EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset());
1636 
1637   uint8_t data2[] = {
1638       0x83, 0xec, 0x10, // subq $0x10, %esp
1639       0x90              // nop
1640   };
1641 
1642   sample_range = AddressRange(0x1000, sizeof(data2));
1643 
1644   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1645       data2, sizeof(data2), sample_range, unwind_plan));
1646 
1647   row_sp = unwind_plan.GetRowForFunctionOffset(3);
1648   EXPECT_EQ(3ull, row_sp->GetOffset());
1649   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1650   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1651   EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
1652 }
1653 
TEST_F(Testx86AssemblyInspectionEngine,TestAddRSP)1654 TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {
1655   UnwindPlan::Row::RegisterLocation regloc;
1656   UnwindPlan::RowSP row_sp;
1657   AddressRange sample_range;
1658   UnwindPlan unwind_plan(eRegisterKindLLDB);
1659   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1660 
1661   uint8_t data1[] = {
1662       0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp
1663       0x90                                      // nop
1664   };
1665 
1666   sample_range = AddressRange(0x1000, sizeof(data1));
1667 
1668   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1669       data1, sizeof(data1), sample_range, unwind_plan));
1670 
1671   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1672   EXPECT_EQ(7ull, row_sp->GetOffset());
1673   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1674   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1675   EXPECT_EQ(8 - 256, row_sp->GetCFAValue().GetOffset());
1676 
1677   uint8_t data2[] = {
1678       0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp
1679       0x90                    // nop
1680   };
1681 
1682   sample_range = AddressRange(0x1000, sizeof(data2));
1683 
1684   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1685       data2, sizeof(data2), sample_range, unwind_plan));
1686 
1687   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1688   EXPECT_EQ(4ull, row_sp->GetOffset());
1689   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1690   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1691   EXPECT_EQ(8 - 16, row_sp->GetCFAValue().GetOffset());
1692 }
1693 
TEST_F(Testx86AssemblyInspectionEngine,TestAddESP)1694 TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {
1695   UnwindPlan::Row::RegisterLocation regloc;
1696   UnwindPlan::RowSP row_sp;
1697   AddressRange sample_range;
1698   UnwindPlan unwind_plan(eRegisterKindLLDB);
1699   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1700 
1701   uint8_t data1[] = {
1702       0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
1703       0x90                                // nop
1704   };
1705 
1706   sample_range = AddressRange(0x1000, sizeof(data1));
1707 
1708   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1709       data1, sizeof(data1), sample_range, unwind_plan));
1710 
1711   row_sp = unwind_plan.GetRowForFunctionOffset(6);
1712   EXPECT_EQ(6ull, row_sp->GetOffset());
1713   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1714   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1715   EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset());
1716 
1717   uint8_t data2[] = {
1718       0x83, 0xc4, 0x10, // addq $0x10, %esp
1719       0x90              // nop
1720   };
1721 
1722   sample_range = AddressRange(0x1000, sizeof(data2));
1723 
1724   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1725       data2, sizeof(data2), sample_range, unwind_plan));
1726 
1727   row_sp = unwind_plan.GetRowForFunctionOffset(3);
1728   EXPECT_EQ(3ull, row_sp->GetOffset());
1729   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1730   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1731   EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset());
1732 }
1733 
1734 // FIXME add test for lea_rsp_pattern_p
1735 
TEST_F(Testx86AssemblyInspectionEngine,TestPopRBX)1736 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {
1737   UnwindPlan::Row::RegisterLocation regloc;
1738   UnwindPlan::RowSP row_sp;
1739   AddressRange sample_range;
1740   UnwindPlan unwind_plan(eRegisterKindLLDB);
1741   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1742 
1743   uint8_t data[] = {
1744       0x53, // pushq %rbx
1745       0x5b, // popq %rbx
1746       0x90  // nop
1747   };
1748 
1749   sample_range = AddressRange(0x1000, sizeof(data));
1750 
1751   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1752       data, sizeof(data), sample_range, unwind_plan));
1753 
1754   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1755   EXPECT_EQ(2ull, row_sp->GetOffset());
1756   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1757   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1758   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1759   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
1760 }
1761 
TEST_F(Testx86AssemblyInspectionEngine,TestPopRBP)1762 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {
1763   UnwindPlan::Row::RegisterLocation regloc;
1764   UnwindPlan::RowSP row_sp;
1765   AddressRange sample_range;
1766   UnwindPlan unwind_plan(eRegisterKindLLDB);
1767   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1768 
1769   uint8_t data[] = {
1770       0x55, // pushq %rbp
1771       0x5d, // popq %rbp
1772       0x90  // nop
1773   };
1774 
1775   sample_range = AddressRange(0x1000, sizeof(data));
1776 
1777   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1778       data, sizeof(data), sample_range, unwind_plan));
1779 
1780   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1781   EXPECT_EQ(2ull, row_sp->GetOffset());
1782   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1783   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1784   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1785   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
1786 }
1787 
TEST_F(Testx86AssemblyInspectionEngine,TestPopR12)1788 TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {
1789   UnwindPlan::Row::RegisterLocation regloc;
1790   UnwindPlan::RowSP row_sp;
1791   AddressRange sample_range;
1792   UnwindPlan unwind_plan(eRegisterKindLLDB);
1793   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1794 
1795   uint8_t data[] = {
1796       0x41, 0x54, // pushq %r12
1797       0x41, 0x5c, // popq %r12
1798       0x90        // nop
1799   };
1800 
1801   sample_range = AddressRange(0x1000, sizeof(data));
1802 
1803   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1804       data, sizeof(data), sample_range, unwind_plan));
1805 
1806   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1807   EXPECT_EQ(4ull, row_sp->GetOffset());
1808   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1809   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1810   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1811   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
1812 }
1813 
TEST_F(Testx86AssemblyInspectionEngine,TestPopR13)1814 TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {
1815   UnwindPlan::Row::RegisterLocation regloc;
1816   UnwindPlan::RowSP row_sp;
1817   AddressRange sample_range;
1818   UnwindPlan unwind_plan(eRegisterKindLLDB);
1819   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1820 
1821   uint8_t data[] = {
1822       0x41, 0x55, // pushq %r13
1823       0x41, 0x5d, // popq %r13
1824       0x90        // nop
1825   };
1826 
1827   sample_range = AddressRange(0x1000, sizeof(data));
1828 
1829   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1830       data, sizeof(data), sample_range, unwind_plan));
1831 
1832   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1833   EXPECT_EQ(4ull, row_sp->GetOffset());
1834   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1835   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1836   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1837   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
1838 }
1839 
TEST_F(Testx86AssemblyInspectionEngine,TestPopR14)1840 TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {
1841   UnwindPlan::Row::RegisterLocation regloc;
1842   UnwindPlan::RowSP row_sp;
1843   AddressRange sample_range;
1844   UnwindPlan unwind_plan(eRegisterKindLLDB);
1845   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1846 
1847   uint8_t data[] = {
1848       0x41, 0x56, // pushq %r14
1849       0x41, 0x5e, // popq %r14
1850       0x90        // nop
1851   };
1852 
1853   sample_range = AddressRange(0x1000, sizeof(data));
1854 
1855   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1856       data, sizeof(data), sample_range, unwind_plan));
1857 
1858   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1859   EXPECT_EQ(4ull, row_sp->GetOffset());
1860   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1861   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1862   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1863   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
1864 }
1865 
TEST_F(Testx86AssemblyInspectionEngine,TestPopR15)1866 TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {
1867   UnwindPlan::Row::RegisterLocation regloc;
1868   UnwindPlan::RowSP row_sp;
1869   AddressRange sample_range;
1870   UnwindPlan unwind_plan(eRegisterKindLLDB);
1871   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1872 
1873   uint8_t data[] = {
1874       0x41, 0x57, // pushq %r15
1875       0x41, 0x5f, // popq %r15
1876       0x90        // nop
1877   };
1878 
1879   sample_range = AddressRange(0x1000, sizeof(data));
1880 
1881   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1882       data, sizeof(data), sample_range, unwind_plan));
1883 
1884   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1885   EXPECT_EQ(4ull, row_sp->GetOffset());
1886   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1887   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1888   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1889   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
1890 }
1891 
TEST_F(Testx86AssemblyInspectionEngine,TestPopEBX)1892 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {
1893   UnwindPlan::Row::RegisterLocation regloc;
1894   UnwindPlan::RowSP row_sp;
1895   AddressRange sample_range;
1896   UnwindPlan unwind_plan(eRegisterKindLLDB);
1897   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1898 
1899   uint8_t data[] = {
1900       0x53, // pushl %ebx
1901       0x5b, // popl %ebx
1902       0x90  // nop
1903   };
1904 
1905   sample_range = AddressRange(0x1000, sizeof(data));
1906 
1907   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1908       data, sizeof(data), sample_range, unwind_plan));
1909 
1910   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1911   EXPECT_EQ(2ull, row_sp->GetOffset());
1912   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1913   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1914   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1915   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
1916 }
1917 
TEST_F(Testx86AssemblyInspectionEngine,TestPopEBP)1918 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {
1919   UnwindPlan::Row::RegisterLocation regloc;
1920   UnwindPlan::RowSP row_sp;
1921   AddressRange sample_range;
1922   UnwindPlan unwind_plan(eRegisterKindLLDB);
1923   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1924 
1925   uint8_t data[] = {
1926       0x55, // pushl %ebp
1927       0x5d, // popl %ebp
1928       0x90  // nop
1929   };
1930 
1931   sample_range = AddressRange(0x1000, sizeof(data));
1932 
1933   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1934       data, sizeof(data), sample_range, unwind_plan));
1935 
1936   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1937   EXPECT_EQ(2ull, row_sp->GetOffset());
1938   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1939   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1940   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1941   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
1942 }
1943 
TEST_F(Testx86AssemblyInspectionEngine,TestPopRBPWithREX)1944 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBPWithREX) {
1945   UnwindPlan::Row::RegisterLocation regloc;
1946   UnwindPlan::RowSP row_sp;
1947   AddressRange sample_range;
1948   UnwindPlan unwind_plan(eRegisterKindLLDB);
1949   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1950 
1951   uint8_t data[] = {
1952       0x40, 0x55, // pushq %rbp
1953       0x40, 0x5d, // popq %rbp
1954       0x90        // nop
1955   };
1956 
1957   sample_range = AddressRange(0x1000, sizeof(data));
1958 
1959   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1960       data, sizeof(data), sample_range, unwind_plan));
1961 
1962   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1963   EXPECT_EQ(4ull, row_sp->GetOffset());
1964   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1965   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1966   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1967   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
1968 }
1969 
TEST_F(Testx86AssemblyInspectionEngine,TestPopESI)1970 TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {
1971   UnwindPlan::Row::RegisterLocation regloc;
1972   UnwindPlan::RowSP row_sp;
1973   AddressRange sample_range;
1974   UnwindPlan unwind_plan(eRegisterKindLLDB);
1975   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1976 
1977   uint8_t data[] = {
1978       0x56, // pushl %esi
1979       0x5e, // popl %esi
1980       0x90  // nop
1981   };
1982 
1983   sample_range = AddressRange(0x1000, sizeof(data));
1984 
1985   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1986       data, sizeof(data), sample_range, unwind_plan));
1987 
1988   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1989   EXPECT_EQ(2ull, row_sp->GetOffset());
1990   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1991   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1992   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1993   EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
1994 }
1995 
TEST_F(Testx86AssemblyInspectionEngine,TestPopEDI)1996 TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {
1997   UnwindPlan::Row::RegisterLocation regloc;
1998   UnwindPlan::RowSP row_sp;
1999   AddressRange sample_range;
2000   UnwindPlan unwind_plan(eRegisterKindLLDB);
2001   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2002 
2003   uint8_t data[] = {
2004       0x57, // pushl %edi
2005       0x5f, // popl %edi
2006       0x90  // nop
2007   };
2008 
2009   sample_range = AddressRange(0x1000, sizeof(data));
2010 
2011   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2012       data, sizeof(data), sample_range, unwind_plan));
2013 
2014   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2015   EXPECT_EQ(2ull, row_sp->GetOffset());
2016   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2017   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2018   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2019   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
2020 }
2021 
2022 // We don't track these registers, but make sure the CFA address is updated
2023 // if we're defining the CFA in term of esp.
TEST_F(Testx86AssemblyInspectionEngine,Testi386IgnoredRegisters)2024 TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {
2025   UnwindPlan::Row::RegisterLocation regloc;
2026   UnwindPlan::RowSP row_sp;
2027   AddressRange sample_range;
2028   UnwindPlan unwind_plan(eRegisterKindLLDB);
2029   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2030 
2031   uint8_t data[] = {
2032       0x0e, // push cs
2033       0x16, // push ss
2034       0x1e, // push ds
2035       0x06, // push es
2036 
2037       0x07, // pop es
2038       0x1f, // pop ds
2039       0x17, // pop ss
2040 
2041       0x90 // nop
2042   };
2043 
2044   sample_range = AddressRange(0x1000, sizeof(data));
2045 
2046   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2047       data, sizeof(data), sample_range, unwind_plan));
2048 
2049   row_sp = unwind_plan.GetRowForFunctionOffset(4);
2050   EXPECT_EQ(4ull, row_sp->GetOffset());
2051   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2052   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2053   EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
2054 
2055   row_sp = unwind_plan.GetRowForFunctionOffset(7);
2056   EXPECT_EQ(7ull, row_sp->GetOffset());
2057   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2058   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2059   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2060 }
2061 
TEST_F(Testx86AssemblyInspectionEngine,TestLEAVE)2062 TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {
2063   UnwindPlan::Row::RegisterLocation regloc;
2064   UnwindPlan::RowSP row_sp;
2065   AddressRange sample_range;
2066   UnwindPlan unwind_plan(eRegisterKindLLDB);
2067   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2068   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2069 
2070   uint8_t data[] = {
2071       0x55, // push %rbp/ebp
2072       0xc9, // leave
2073       0x90  // nop
2074   };
2075 
2076   sample_range = AddressRange(0x1000, sizeof(data));
2077 
2078   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2079       data, sizeof(data), sample_range, unwind_plan));
2080 
2081   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2082   EXPECT_EQ(2ull, row_sp->GetOffset());
2083   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2084   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2085   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2086   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2087 
2088   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2089       data, sizeof(data), sample_range, unwind_plan));
2090 
2091   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2092   EXPECT_EQ(2ull, row_sp->GetOffset());
2093   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2094   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2095   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2096   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2097 }
2098 
2099 // In i386, which lacks pc-relative addressing, a common code sequence
2100 // is to call the next instruction (i.e. call imm32, value of 0) which
2101 // pushes the addr of the next insn on the stack, and then pop that value
2102 // into a register (the "pic base" register).
TEST_F(Testx86AssemblyInspectionEngine,TestCALLNextInsn)2103 TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {
2104   UnwindPlan::Row::RegisterLocation regloc;
2105   UnwindPlan::RowSP row_sp;
2106   AddressRange sample_range;
2107   UnwindPlan unwind_plan(eRegisterKindLLDB);
2108   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2109 
2110   uint8_t data[] = {
2111       0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
2112       0x90                          // nop
2113   };
2114 
2115   sample_range = AddressRange(0x1000, sizeof(data));
2116 
2117   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2118       data, sizeof(data), sample_range, unwind_plan));
2119 
2120   row_sp = unwind_plan.GetRowForFunctionOffset(5);
2121   EXPECT_EQ(5ull, row_sp->GetOffset());
2122   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2123   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2124   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2125   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2126 }
2127 
TEST_F(Testx86AssemblyInspectionEngine,TestSpillRegToStackViaMOVx86_64)2128 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {
2129   UnwindPlan::Row::RegisterLocation regloc;
2130   UnwindPlan::RowSP row_sp;
2131   AddressRange sample_range;
2132   UnwindPlan unwind_plan(eRegisterKindLLDB);
2133   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2134 
2135   uint8_t data[] = {
2136       0x55,                                     // pushq %rbp
2137       0x48, 0x89, 0xe5,                         // movq %rsp, %rbp
2138       0x4c, 0x89, 0x75, 0xc0,                   // movq   %r14, -0x40(%rbp)
2139       0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq   %r15, -0x5d8(%rbp)
2140       0x48, 0x89, 0x5d, 0xb8,                   // movq %rbx, -0x48(%rbp)
2141       0x90                                      // nop
2142   };
2143 
2144   sample_range = AddressRange(0x1000, sizeof(data));
2145 
2146   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2147       data, sizeof(data), sample_range, unwind_plan));
2148 
2149   row_sp = unwind_plan.GetRowForFunctionOffset(19);
2150   EXPECT_EQ(19ull, row_sp->GetOffset());
2151   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2152   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2153 
2154   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
2155   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2156   EXPECT_EQ(-80, regloc.GetOffset());
2157 
2158   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
2159   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2160   EXPECT_EQ(-1512, regloc.GetOffset());
2161 
2162   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
2163   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2164   EXPECT_EQ(-88, regloc.GetOffset());
2165 }
2166 
TEST_F(Testx86AssemblyInspectionEngine,TestSpillRegToStackViaMOVi386)2167 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {
2168   UnwindPlan::Row::RegisterLocation regloc;
2169   UnwindPlan::RowSP row_sp;
2170   AddressRange sample_range;
2171   UnwindPlan unwind_plan(eRegisterKindLLDB);
2172   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2173 
2174   uint8_t data[] = {
2175       0x55,                               // pushl %ebp
2176       0x89, 0xe5,                         // movl %esp, %ebp
2177       0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
2178       0x89, 0x75, 0xe0,                   // movl %esi, -0x20(%ebp)
2179       0x90                                // nop
2180   };
2181 
2182   sample_range = AddressRange(0x1000, sizeof(data));
2183 
2184   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2185       data, sizeof(data), sample_range, unwind_plan));
2186 
2187   row_sp = unwind_plan.GetRowForFunctionOffset(12);
2188   EXPECT_EQ(12ull, row_sp->GetOffset());
2189   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2190   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2191 
2192   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
2193   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2194   EXPECT_EQ(-344, regloc.GetOffset());
2195 
2196   EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
2197   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2198   EXPECT_EQ(-40, regloc.GetOffset());
2199 }
2200 
TEST_F(Testx86AssemblyInspectionEngine,TestSpArithx86_64Augmented)2201 TEST_F(Testx86AssemblyInspectionEngine, TestSpArithx86_64Augmented) {
2202   UnwindPlan::Row::RegisterLocation regloc;
2203   UnwindPlan::RowSP row_sp;
2204   AddressRange sample_range;
2205   UnwindPlan unwind_plan(eRegisterKindLLDB);
2206   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2207 
2208   uint8_t data[] = {
2209       0x55,             // pushq %rbp
2210       0x48, 0x89, 0xe5, // movq %rsp, %rbp
2211 
2212       // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2213       // has a bug where it can't augment a function that is just
2214       // prologue+epilogue - it needs at least one other instruction
2215       // in between.
2216 
2217       0x90,                            // nop
2218       0x48, 0x81, 0xec, 0x88, 0, 0, 0, // subq   $0x88, %rsp
2219       0x90,                            // nop
2220       0x48, 0x81, 0xc4, 0x88, 0, 0, 0, // addq   $0x88, %rsp
2221 
2222       0x5d, // popq %rbp
2223       0xc3  // retq
2224   };
2225 
2226   sample_range = AddressRange(0x1000, sizeof(data));
2227 
2228   unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2229   unwind_plan.SetPlanValidAddressRange(sample_range);
2230   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2231 
2232   row_sp = std::make_shared<UnwindPlan::Row>();
2233 
2234   // Describe offset 0
2235   row_sp->SetOffset(0);
2236   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
2237 
2238   regloc.SetAtCFAPlusOffset(-8);
2239   row_sp->SetRegisterInfo(k_rip, regloc);
2240 
2241   unwind_plan.AppendRow(row_sp);
2242 
2243   // Allocate a new Row, populate it with the existing Row contents.
2244   UnwindPlan::Row *new_row = new UnwindPlan::Row;
2245   *new_row = *row_sp.get();
2246   row_sp.reset(new_row);
2247 
2248   // Describe offset 1
2249   row_sp->SetOffset(1);
2250   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
2251   regloc.SetAtCFAPlusOffset(-16);
2252   row_sp->SetRegisterInfo(k_rbp, regloc);
2253   unwind_plan.AppendRow(row_sp);
2254 
2255   // Allocate a new Row, populate it with the existing Row contents.
2256   new_row = new UnwindPlan::Row;
2257   *new_row = *row_sp.get();
2258   row_sp.reset(new_row);
2259 
2260   // Describe offset 4
2261   row_sp->SetOffset(4);
2262   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
2263   unwind_plan.AppendRow(row_sp);
2264 
2265   RegisterContextSP reg_ctx_sp;
2266   EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2267       data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2268 
2269   // Before we touch the stack pointer, we should still refer to the
2270   // row from after the prologue.
2271   row_sp = unwind_plan.GetRowForFunctionOffset(5);
2272   EXPECT_EQ(4ull, row_sp->GetOffset());
2273 
2274   // Check the first stack pointer update.
2275   row_sp = unwind_plan.GetRowForFunctionOffset(12);
2276   EXPECT_EQ(12ull, row_sp->GetOffset());
2277   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2278   EXPECT_EQ(152, row_sp->GetCFAValue().GetOffset());
2279 
2280   // After the nop, we should still refer to the same row.
2281   row_sp = unwind_plan.GetRowForFunctionOffset(13);
2282   EXPECT_EQ(12ull, row_sp->GetOffset());
2283 
2284   // Check that the second stack pointer update is reflected in the
2285   // unwind plan.
2286   row_sp = unwind_plan.GetRowForFunctionOffset(20);
2287   EXPECT_EQ(20ull, row_sp->GetOffset());
2288   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2289   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2290 }
2291 
TEST_F(Testx86AssemblyInspectionEngine,TestSimplex86_64Augmented)2292 TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {
2293   UnwindPlan::Row::RegisterLocation regloc;
2294   UnwindPlan::RowSP row_sp;
2295   AddressRange sample_range;
2296   UnwindPlan unwind_plan(eRegisterKindLLDB);
2297   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2298 
2299   uint8_t data[] = {
2300       0x55,             // pushq %rbp
2301       0x48, 0x89, 0xe5, // movq %rsp, %rbp
2302 
2303       // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2304       // has a bug where it can't augment a function that is just
2305       // prologue+epilogue - it needs at least one other instruction
2306       // in between.
2307       0x90, // nop
2308 
2309       0x5d, // popq %rbp
2310       0xc3  // retq
2311   };
2312 
2313   sample_range = AddressRange(0x1000, sizeof(data));
2314 
2315   unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2316   unwind_plan.SetPlanValidAddressRange(sample_range);
2317   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2318 
2319   row_sp = std::make_shared<UnwindPlan::Row>();
2320 
2321   // Describe offset 0
2322   row_sp->SetOffset(0);
2323   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
2324 
2325   regloc.SetAtCFAPlusOffset(-8);
2326   row_sp->SetRegisterInfo(k_rip, regloc);
2327 
2328   unwind_plan.AppendRow(row_sp);
2329 
2330   // Allocate a new Row, populate it with the existing Row contents.
2331   UnwindPlan::Row *new_row = new UnwindPlan::Row;
2332   *new_row = *row_sp.get();
2333   row_sp.reset(new_row);
2334 
2335   // Describe offset 1
2336   row_sp->SetOffset(1);
2337   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
2338   regloc.SetAtCFAPlusOffset(-16);
2339   row_sp->SetRegisterInfo(k_rbp, regloc);
2340   unwind_plan.AppendRow(row_sp);
2341 
2342   // Allocate a new Row, populate it with the existing Row contents.
2343   new_row = new UnwindPlan::Row;
2344   *new_row = *row_sp.get();
2345   row_sp.reset(new_row);
2346 
2347   // Describe offset 4
2348   row_sp->SetOffset(4);
2349   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rbp, 16);
2350   unwind_plan.AppendRow(row_sp);
2351 
2352   RegisterContextSP reg_ctx_sp;
2353   EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2354       data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2355 
2356   row_sp = unwind_plan.GetRowForFunctionOffset(6);
2357   EXPECT_EQ(6ull, row_sp->GetOffset());
2358   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2359   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2360 
2361   // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2362   // doesn't track register restores (pop'ing a reg value back from
2363   // the stack) - it was just written to make stepping work correctly.
2364   // Technically we should be able to do the following test, but it
2365   // won't work today - the unwind plan will still say that the caller's
2366   // rbp is on the stack.
2367   // EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2368 }
2369 
TEST_F(Testx86AssemblyInspectionEngine,TestSimplei386ugmented)2370 TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) {
2371   UnwindPlan::Row::RegisterLocation regloc;
2372   UnwindPlan::RowSP row_sp;
2373   AddressRange sample_range;
2374   UnwindPlan unwind_plan(eRegisterKindLLDB);
2375   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2376 
2377   uint8_t data[] = {
2378       0x55,       // pushl %ebp
2379       0x89, 0xe5, // movl %esp, %ebp
2380 
2381       // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2382       // has a bug where it can't augment a function that is just
2383       // prologue+epilogue - it needs at least one other instruction
2384       // in between.
2385       0x90, // nop
2386 
2387       0x5d, // popl %ebp
2388       0xc3  // retl
2389   };
2390 
2391   sample_range = AddressRange(0x1000, sizeof(data));
2392 
2393   unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2394   unwind_plan.SetPlanValidAddressRange(sample_range);
2395   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2396 
2397   row_sp = std::make_shared<UnwindPlan::Row>();
2398 
2399   // Describe offset 0
2400   row_sp->SetOffset(0);
2401   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 4);
2402 
2403   regloc.SetAtCFAPlusOffset(-4);
2404   row_sp->SetRegisterInfo(k_eip, regloc);
2405 
2406   unwind_plan.AppendRow(row_sp);
2407 
2408   // Allocate a new Row, populate it with the existing Row contents.
2409   UnwindPlan::Row *new_row = new UnwindPlan::Row;
2410   *new_row = *row_sp.get();
2411   row_sp.reset(new_row);
2412 
2413   // Describe offset 1
2414   row_sp->SetOffset(1);
2415   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 8);
2416   regloc.SetAtCFAPlusOffset(-8);
2417   row_sp->SetRegisterInfo(k_ebp, regloc);
2418   unwind_plan.AppendRow(row_sp);
2419 
2420   // Allocate a new Row, populate it with the existing Row contents.
2421   new_row = new UnwindPlan::Row;
2422   *new_row = *row_sp.get();
2423   row_sp.reset(new_row);
2424 
2425   // Describe offset 3
2426   row_sp->SetOffset(3);
2427   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_ebp, 8);
2428   unwind_plan.AppendRow(row_sp);
2429 
2430   RegisterContextSP reg_ctx_sp;
2431   EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite(
2432       data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2433 
2434   row_sp = unwind_plan.GetRowForFunctionOffset(5);
2435   EXPECT_EQ(5ull, row_sp->GetOffset());
2436   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2437   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2438 
2439   // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2440   // doesn't track register restores (pop'ing a reg value back from
2441   // the stack) - it was just written to make stepping work correctly.
2442   // Technically we should be able to do the following test, but it
2443   // won't work today - the unwind plan will still say that the caller's
2444   // ebp is on the stack.
2445   // EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2446 }
2447 
2448 // Check that the i386 disassembler disassembles past an opcode that
2449 // is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler
2450 // stops
2451 // disassembling at that point (long-mode).
TEST_F(Testx86AssemblyInspectionEngine,Test32BitOnlyInstruction)2452 TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {
2453   UnwindPlan::Row::RegisterLocation regloc;
2454   UnwindPlan::RowSP row_sp;
2455   AddressRange sample_range;
2456   UnwindPlan unwind_plan(eRegisterKindLLDB);
2457   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2458   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2459 
2460   uint8_t data[] = {
2461       0x43, // incl $ebx --- an invalid opcode in 64-bit mode
2462       0x55, // pushl %ebp
2463       0x90  // nop
2464   };
2465 
2466   sample_range = AddressRange(0x1000, sizeof(data));
2467 
2468   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2469       data, sizeof(data), sample_range, unwind_plan));
2470 
2471   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2472   EXPECT_EQ(2ull, row_sp->GetOffset());
2473   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2474   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2475   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2476 
2477   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
2478   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2479   EXPECT_EQ(-8, regloc.GetOffset());
2480 
2481   unwind_plan.Clear();
2482 
2483   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2484       data, sizeof(data), sample_range, unwind_plan));
2485 
2486   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2487   EXPECT_EQ(0ull, row_sp->GetOffset());
2488   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2489   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2490   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2491 
2492   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2493 }
2494 
TEST_F(Testx86AssemblyInspectionEngine,TestStackRealign8BitDisp_i386)2495 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {
2496   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2497 
2498   uint8_t data[] = {
2499       0x55,             // pushl %ebp
2500       0x89, 0xe5,       // movl %esp, %ebp
2501       0x53,             // pushl %ebx
2502       0x83, 0xe4, 0xf0, // andl $-16, %esp
2503       0x83, 0xec, 0x10, // subl $16, %esp
2504       0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp
2505       0x5b,             // popl %ebx
2506       0x5d,             // popl %ebp
2507       0xc3,             // retl
2508   };
2509 
2510   AddressRange sample_range(0x1000, sizeof(data));
2511   UnwindPlan plan(eRegisterKindLLDB);
2512   ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2513                                                            sample_range, plan));
2514 
2515   UnwindPlan::Row::FAValue esp_plus_4, esp_plus_8, ebp_plus_8;
2516   esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
2517   esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
2518   ebp_plus_8.SetIsRegisterPlusOffset(k_ebp, 8);
2519 
2520   EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2521   EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2522   for (size_t i = 3; i < sizeof(data) - 2; ++i)
2523     EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2524         << "i: " << i;
2525   EXPECT_EQ(esp_plus_4,
2526             plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
2527 }
2528 
TEST_F(Testx86AssemblyInspectionEngine,TestStackRealign32BitDisp_x86_64)2529 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
2530   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
2531 
2532   uint8_t data[] = {
2533       0x55,                                     // pushq %rbp
2534       0x48, 0x89, 0xe5,                         // movq %rsp, %rbp
2535       0x53,                                     // pushl %rbx
2536       0x48, 0x83, 0xe4, 0xf0,                   // andq $-16, %rsp
2537       0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp
2538       0x48, 0x8d, 0x65, 0xf8,                   // leaq -8(%rbp), %rsp
2539       0x5b,                                     // popq %rbx
2540       0x5d,                                     // popq %rbp
2541       0xc3,                                     // retq
2542   };
2543 
2544   AddressRange sample_range(0x1000, sizeof(data));
2545   UnwindPlan plan(eRegisterKindLLDB);
2546   ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2547                                                            sample_range, plan));
2548 
2549   UnwindPlan::Row::FAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
2550   rsp_plus_8.SetIsRegisterPlusOffset(k_rsp, 8);
2551   rsp_plus_16.SetIsRegisterPlusOffset(k_rsp, 16);
2552   rbp_plus_16.SetIsRegisterPlusOffset(k_rbp, 16);
2553 
2554   EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2555   EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2556   for (size_t i = 4; i < sizeof(data) - 2; ++i)
2557     EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2558         << "i: " << i;
2559   EXPECT_EQ(rsp_plus_8,
2560             plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
2561 }
2562 
TEST_F(Testx86AssemblyInspectionEngine,TestStackRealignMSVC_i386)2563 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealignMSVC_i386) {
2564   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2565 
2566   uint8_t data[] = {
2567       0x53,                               // offset 00 -- pushl %ebx
2568       0x8b, 0xdc,                         // offset 01 -- movl %esp, %ebx
2569       0x83, 0xec, 0x08,                   // offset 03 -- subl $8, %esp
2570       0x81, 0xe4, 0x00, 0xff, 0xff, 0xff, // offset 06 -- andl $-256, %esp
2571       0x83, 0xc4, 0x04,                   // offset 12 -- addl $4, %esp
2572       0x55,                               // offset 15 -- pushl %ebp
2573       0x8b, 0xec,                         // offset 16 -- movl %esp, %ebp
2574       0x81, 0xec, 0x00, 0x02, 0x00, 0x00, // offset 18 -- subl $512, %esp
2575       0x89, 0x7d, 0xfc,                   // offset 24 -- movl %edi, -4(%ebp)
2576       0x8b, 0xe5,                         // offset 27 -- movl %ebp, %esp
2577       0x5d,                               // offset 29 -- popl %ebp
2578       0x8b, 0xe3,                         // offset 30 -- movl %ebx, %esp
2579       0x5b,                               // offset 32 -- popl %ebx
2580       0xc3                                // offset 33 -- retl
2581   };
2582 
2583   AddressRange sample_range(0x1000, sizeof(data));
2584   UnwindPlan plan(eRegisterKindLLDB);
2585   ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2586                                                            sample_range, plan));
2587 
2588   UnwindPlan::Row::FAValue esp_minus_4, esp_plus_0, esp_plus_4, esp_plus_8,
2589       ebx_plus_8, ebp_plus_0;
2590   esp_minus_4.SetIsRegisterPlusOffset(k_esp, -4);
2591   esp_plus_0.SetIsRegisterPlusOffset(k_esp, 0);
2592   esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
2593   esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
2594   ebx_plus_8.SetIsRegisterPlusOffset(k_ebx, 8);
2595   ebp_plus_0.SetIsRegisterPlusOffset(k_ebp, 0);
2596 
2597   // Test CFA
2598   EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2599   EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2600   for (size_t i = 3; i < 33; ++i)
2601     EXPECT_EQ(ebx_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2602         << "i: " << i;
2603   EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(33)->GetCFAValue());
2604 
2605   // Test AFA
2606   EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(12)->GetAFAValue());
2607   EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(15)->GetAFAValue());
2608   EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(16)->GetAFAValue());
2609   for (size_t i = 18; i < 30; ++i)
2610     EXPECT_EQ(ebp_plus_0, plan.GetRowForFunctionOffset(i)->GetAFAValue())
2611         << "i: " << i;
2612   EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(30)->GetAFAValue());
2613 
2614   // Test saved register
2615   UnwindPlan::Row::RegisterLocation reg_loc;
2616   EXPECT_TRUE(
2617       plan.GetRowForFunctionOffset(27)->GetRegisterInfo(k_edi, reg_loc));
2618   EXPECT_TRUE(reg_loc.IsAtAFAPlusOffset());
2619   EXPECT_EQ(-4, reg_loc.GetOffset());
2620 }
2621 
2622 // Give the disassembler random bytes to test that it doesn't exceed
2623 // the bounds of the array when run under clang's address sanitizer.
TEST_F(Testx86AssemblyInspectionEngine,TestDisassemblyJunkBytes)2624 TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) {
2625   AddressRange sample_range;
2626   UnwindPlan unwind_plan(eRegisterKindLLDB);
2627   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2628   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2629 
2630   uint8_t data[] = {
2631       0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
2632       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
2633 
2634   sample_range = AddressRange(0x1000, sizeof(data));
2635 
2636   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2637       data, sizeof(data), sample_range, unwind_plan));
2638 
2639   unwind_plan.Clear();
2640 
2641   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2642       data, sizeof(data), sample_range, unwind_plan));
2643 
2644 }
2645 
TEST_F(Testx86AssemblyInspectionEngine,TestReturnDetect)2646 TEST_F(Testx86AssemblyInspectionEngine, TestReturnDetect) {
2647   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
2648 
2649   // Single fragment with all four return forms.
2650   // We want to verify that the unwind state is reset after each ret.
2651   uint8_t data[] = {
2652       0x55,             // offset  0 -- pushq %rbp
2653       0x48, 0x89, 0xe5, // offset  1 -- movq %rsp, %rbp
2654       0x31, 0xc0,       // offset  4 -- xorl %eax, %eax
2655       0x5d,             // offset  6 -- popq %rbp
2656       0xc3,             // offset  7 -- retq
2657       0x31, 0xc0,       // offset  8 -- xorl %eax, %eax
2658       0x5d,             // offset 10 -- popq %rbp
2659       0xcb,             // offset 11 -- retf
2660       0x31, 0xc0,       // offset 12 -- xorl %eax, %eax
2661       0x5d,             // offset 14 -- popq %rbp
2662       0xc2, 0x22, 0x11, // offset 15 -- retq 0x1122
2663       0x31, 0xc0,       // offset 18 -- xorl %eax, %eax
2664       0x5d,             // offset 20 -- popq %rbp
2665       0xca, 0x44, 0x33, // offset 21 -- retf 0x3344
2666       0x31, 0xc0,       // offset 24 -- xorl %eax, %eax
2667   };
2668 
2669   AddressRange sample_range(0x1000, sizeof(data));
2670 
2671   UnwindPlan unwind_plan(eRegisterKindLLDB);
2672   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2673       data, sizeof(data), sample_range, unwind_plan));
2674 
2675   // Expect following unwind rows:
2676   //  0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2677   //  1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2678   //  4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2679   //  7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2680   //  8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2681   // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2682   // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2683   // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2684   // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2685   // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2686   // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2687 
2688   EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
2689   EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
2690               eLazyBoolYes);
2691   EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
2692 
2693   UnwindPlan::Row::RegisterLocation regloc;
2694 
2695   //  0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2696   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
2697   EXPECT_EQ(0ull, row_sp->GetOffset());
2698   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2699   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2700   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2701 
2702   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2703   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2704   EXPECT_EQ(-8, regloc.GetOffset());
2705 
2706   //  1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2707   row_sp = unwind_plan.GetRowForFunctionOffset(1);
2708   EXPECT_EQ(1ull, row_sp->GetOffset());
2709   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2710   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2711   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2712 
2713   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2714   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2715   EXPECT_EQ(-8, regloc.GetOffset());
2716 
2717   //  4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2718   row_sp = unwind_plan.GetRowForFunctionOffset(4);
2719   EXPECT_EQ(4ull, row_sp->GetOffset());
2720   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2721   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2722   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2723 
2724   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2725   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2726   EXPECT_EQ(-8, regloc.GetOffset());
2727 
2728   //  7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2729   row_sp = unwind_plan.GetRowForFunctionOffset(7);
2730   EXPECT_EQ(7ull, row_sp->GetOffset());
2731   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2732   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2733   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2734 
2735   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2736   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2737   EXPECT_EQ(-8, regloc.GetOffset());
2738 
2739   //  8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2740   row_sp = unwind_plan.GetRowForFunctionOffset(8);
2741   EXPECT_EQ(8ull, row_sp->GetOffset());
2742   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2743   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2744   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2745 
2746   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2747   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2748   EXPECT_EQ(-8, regloc.GetOffset());
2749 
2750   // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2751   row_sp = unwind_plan.GetRowForFunctionOffset(11);
2752   EXPECT_EQ(11ull, row_sp->GetOffset());
2753   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2754   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2755   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2756 
2757   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2758   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2759   EXPECT_EQ(-8, regloc.GetOffset());
2760 
2761   // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2762   row_sp = unwind_plan.GetRowForFunctionOffset(12);
2763   EXPECT_EQ(12ull, row_sp->GetOffset());
2764   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2765   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2766   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2767 
2768   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2769   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2770   EXPECT_EQ(-8, regloc.GetOffset());
2771 
2772   // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2773   row_sp = unwind_plan.GetRowForFunctionOffset(15);
2774   EXPECT_EQ(15ull, row_sp->GetOffset());
2775   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2776   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2777   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2778 
2779   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2780   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2781   EXPECT_EQ(-8, regloc.GetOffset());
2782 
2783   // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2784   row_sp = unwind_plan.GetRowForFunctionOffset(18);
2785   EXPECT_EQ(18ull, row_sp->GetOffset());
2786   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2787   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2788   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2789 
2790   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2791   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2792   EXPECT_EQ(-8, regloc.GetOffset());
2793 
2794   // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2795   row_sp = unwind_plan.GetRowForFunctionOffset(21);
2796   EXPECT_EQ(21ull, row_sp->GetOffset());
2797   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2798   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2799   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2800 
2801   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2802   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2803   EXPECT_EQ(-8, regloc.GetOffset());
2804 
2805   // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2806   row_sp = unwind_plan.GetRowForFunctionOffset(24);
2807   EXPECT_EQ(24ull, row_sp->GetOffset());
2808   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2809   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2810   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2811 
2812   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2813   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2814   EXPECT_EQ(-8, regloc.GetOffset());
2815 }
2816 
2817 
2818 // Test mid-function epilogues - the unwind state post-prologue
2819 // should be re-instated.
2820 
TEST_F(Testx86AssemblyInspectionEngine,TestDisassemblyMidFunctionEpilogues)2821 TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {
2822   AddressRange sample_range;
2823   UnwindPlan unwind_plan(eRegisterKindLLDB);
2824   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2825   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2826 
2827   uint8_t data[] = {
2828     0x55,                   // <+0>: pushq %rbp
2829     0x48, 0x89, 0xe5,       // <+1>: movq %rsp, %rbp
2830     0x48, 0x83, 0xec, 0x70, // <+4>: subq $0x70, %rsp
2831     0x90,                   // <+8>: nop               // prologue set up
2832 
2833     0x74, 0x7,              // <+9>: je 7 <+18>
2834     0x48, 0x83, 0xc4, 0x70, // <+11>: addq $0x70, %rsp
2835     0x5d,                   // <+15>: popq %rbp
2836     0xff, 0xe0,             // <+16>: jmpq *%rax      // epilogue completed
2837 
2838     0x90,                   // <+18>: nop             // prologue setup back
2839 
2840     0x74, 0x7,              // <+19>: je 6 <+27>
2841     0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp
2842     0x5d,                   // <+25>: popq %rbp
2843     0xc3,                   // <+26>: retq            // epilogue completed
2844 
2845     0x90,                   // <+27>: nop             // prologue setup back
2846 
2847     0x48, 0x83, 0xc4, 0x70, // <+28>: addq $0x70, %rsp
2848     0x5d,                   // <+32>: popq %rbp
2849     0xc3,                   // <+33>: retq            // epilogue completed
2850 
2851   };
2852 
2853   sample_range = AddressRange(0x1000, sizeof(data));
2854 
2855   int wordsize = 4;
2856   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2857       data, sizeof(data), sample_range, unwind_plan));
2858 
2859   // Check that we've unwound the stack after the first mid-function epilogue
2860   // row:   CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
2861   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(16);
2862   EXPECT_EQ(16ull, row_sp->GetOffset());
2863   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2864   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2865   EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2866 
2867   // Check that we've reinstated the stack frame setup
2868   // unwind instructions after a jmpq *%eax
2869   // row:   CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
2870   row_sp = unwind_plan.GetRowForFunctionOffset(18);
2871   EXPECT_EQ(18ull, row_sp->GetOffset());
2872   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
2873   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2874   EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2875 
2876   // Check that we've reinstated the stack frame setup
2877   // unwind instructions after a mid-function retq
2878   // row:   CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
2879   row_sp = unwind_plan.GetRowForFunctionOffset(27);
2880   EXPECT_EQ(27ull, row_sp->GetOffset());
2881   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
2882   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2883   EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2884 
2885   // After last instruction in the function, verify that
2886   // the stack frame has been unwound
2887   // row:   CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
2888   row_sp = unwind_plan.GetRowForFunctionOffset(33);
2889   EXPECT_EQ(33ull, row_sp->GetOffset());
2890   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2891   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2892   EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2893 
2894 
2895   unwind_plan.Clear();
2896 
2897   wordsize = 8;
2898   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2899       data, sizeof(data), sample_range, unwind_plan));
2900 
2901   // Check that we've unwound the stack after the first mid-function epilogue
2902   // row:   CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2903   row_sp = unwind_plan.GetRowForFunctionOffset(16);
2904   EXPECT_EQ(16ull, row_sp->GetOffset());
2905   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2906   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2907   EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2908 
2909   // Check that we've reinstated the stack frame setup
2910   // unwind instructions after a jmpq *%eax
2911   // row:   CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
2912   row_sp = unwind_plan.GetRowForFunctionOffset(18);
2913   EXPECT_EQ(18ull, row_sp->GetOffset());
2914   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2915   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2916   EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2917 
2918   // Check that we've reinstated the stack frame setup
2919   // unwind instructions after a mid-function retq
2920   // row:   CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
2921   row_sp = unwind_plan.GetRowForFunctionOffset(27);
2922   EXPECT_EQ(27ull, row_sp->GetOffset());
2923   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2924   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2925   EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2926 
2927   // After last instruction in the function, verify that
2928   // the stack frame has been unwound
2929   // row:   CFA=rsp +8 => esp=CFA+0 rip=[CFA-8]
2930   row_sp = unwind_plan.GetRowForFunctionOffset(33);
2931   EXPECT_EQ(33ull, row_sp->GetOffset());
2932   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2933   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2934   EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2935 
2936 
2937 }
2938