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