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