1 //===-- Testx86AssemblyInspectionEngine.cpp ---------------------------*- C++
2 //-*-===//
3 
4 //
5 //                     The LLVM Compiler Infrastructure
6 //
7 // This file is distributed under the University of Illinois Open Source
8 // License. See LICENSE.TXT for details.
9 //
10 //===----------------------------------------------------------------------===//
11 
12 #include "gtest/gtest.h"
13 
14 #include <vector>
15 
16 #include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h"
17 #include "lldb/Core/Address.h"
18 #include "lldb/Core/AddressRange.h"
19 #include "lldb/Core/ArchSpec.h"
20 #include "lldb/Symbol/UnwindPlan.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", nullptr);
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", nullptr);
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 TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
134   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
135 
136   // 'int main() { }' compiled for x86_64-apple-macosx with clang
137   uint8_t data[] = {
138       0x55,             // offset 0 -- pushq %rbp
139       0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
140       0x31, 0xc0,       // offset 4 -- xorl %eax, %eax
141       0x5d,             // offset 6 -- popq %rbp
142       0xc3              // offset 7 -- retq
143   };
144 
145   AddressRange sample_range(0x1000, sizeof(data));
146 
147   UnwindPlan unwind_plan(eRegisterKindLLDB);
148   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
149       data, sizeof(data), sample_range, unwind_plan));
150 
151   // Expect four unwind rows:
152   // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
153   // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
154   // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
155   // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
156 
157   EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
158   EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
159               eLazyBoolYes);
160   EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
161 
162   UnwindPlan::Row::RegisterLocation regloc;
163 
164   // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
165   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
166   EXPECT_EQ(0ull, row_sp->GetOffset());
167   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
168   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
169   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
170 
171   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
172   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
173   EXPECT_EQ(-8, regloc.GetOffset());
174 
175   // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
176   row_sp = unwind_plan.GetRowForFunctionOffset(1);
177   EXPECT_EQ(1ull, row_sp->GetOffset());
178   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
179   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
180   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
181 
182   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
183   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
184   EXPECT_EQ(-8, regloc.GetOffset());
185 
186   // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
187   row_sp = unwind_plan.GetRowForFunctionOffset(4);
188   EXPECT_EQ(4ull, row_sp->GetOffset());
189   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
190   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
191   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
192 
193   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
194   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
195   EXPECT_EQ(-8, regloc.GetOffset());
196 
197   // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
198   row_sp = unwind_plan.GetRowForFunctionOffset(7);
199   EXPECT_EQ(7ull, row_sp->GetOffset());
200   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
201   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
202   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
203 
204   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
205   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
206   EXPECT_EQ(-8, regloc.GetOffset());
207 }
208 
209 TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) {
210   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
211 
212   // 'int main() { }' compiled for i386-apple-macosx with clang
213   uint8_t data[] = {
214       0x55,       // offset 0 -- pushl %ebp
215       0x89, 0xe5, // offset 1 -- movl %esp, %ebp
216       0x31, 0xc0, // offset 3 -- xorl %eax, %eax
217       0x5d,       // offset 5 -- popl %ebp
218       0xc3        // offset 6 -- retl
219   };
220 
221   AddressRange sample_range(0x1000, sizeof(data));
222 
223   UnwindPlan unwind_plan(eRegisterKindLLDB);
224   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
225       data, sizeof(data), sample_range, unwind_plan));
226 
227   // Expect four unwind rows:
228   // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
229   // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
230   // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
231   // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
232 
233   EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_esp);
234   EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
235               eLazyBoolYes);
236   EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
237 
238   UnwindPlan::Row::RegisterLocation regloc;
239 
240   // offset 0 -- pushl %ebp
241   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
242   EXPECT_EQ(0ull, row_sp->GetOffset());
243   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
244   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
245   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
246 
247   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
248   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
249   EXPECT_TRUE(regloc.GetOffset() == -4);
250 
251   // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
252   row_sp = unwind_plan.GetRowForFunctionOffset(1);
253   EXPECT_EQ(1ull, row_sp->GetOffset());
254   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
255   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
256   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
257 
258   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
259   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
260   EXPECT_EQ(-4, regloc.GetOffset());
261 
262   // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
263   row_sp = unwind_plan.GetRowForFunctionOffset(3);
264   EXPECT_EQ(3ull, row_sp->GetOffset());
265   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
266   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
267   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
268 
269   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
270   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
271   EXPECT_EQ(-4, regloc.GetOffset());
272 
273   // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
274   row_sp = unwind_plan.GetRowForFunctionOffset(6);
275   EXPECT_EQ(6ull, row_sp->GetOffset());
276   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
277   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
278   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
279 
280   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
281   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
282   EXPECT_EQ(-4, regloc.GetOffset());
283 }
284 
285 TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) {
286   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
287 
288   // this source file:
289   //
290   // #include <stdio.h>
291   // int main (int argc, char **argv)
292   // {
293   //
294   //     const int arrsize = 60;
295   //     int buf[arrsize * arrsize];
296   //     int accum = argc;
297   //     for (int i = 0; i < arrsize; i++)
298   //         for (int j = 0; j < arrsize; j++)
299   //         {
300   //             if (i > 0 && j > 0)
301   //             {
302   //                 int n = buf[(i-1) * (j-1)] * 2;
303   //                 int m = buf[(i-1) * (j-1)] / 2;
304   //                 int j = buf[(i-1) * (j-1)] + 2;
305   //                 int k = buf[(i-1) * (j-1)] - 2;
306   //                 printf ("%d ", n + m + j + k);
307   //                 buf[(i-1) * (j-1)] += n - m + j - k;
308   //             }
309   //             buf[i*j] = accum++;
310   //         }
311   //
312   //     return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
313   //     arrsize) - 3]);
314   // }
315   //
316   // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx
317 
318   uint8_t data[] = {
319       0x55,       // offset 0  -- pushq %rbp
320       0x41, 0x57, // offset 1  -- pushq %r15
321       0x41, 0x56, // offset 3  -- pushq %r14
322       0x41, 0x55, // offset 5  -- pushq %r13
323       0x41, 0x54, // offset 7  -- pushq %r12
324       0x53,       // offset 9  -- pushq %rbx
325       0x48, 0x81, 0xec, 0x68, 0x38, 0x00,
326       0x00, // offset 10 -- subq $0x3868, %rsp
327 
328       // ....
329 
330       0x48, 0x81, 0xc4, 0x68, 0x38, 0x00,
331       0x00,                        // offset 17 -- addq $0x3868, %rsp
332       0x5b,                        // offset 24 -- popq %rbx
333       0x41, 0x5c,                  // offset 25 -- popq %r12
334       0x41, 0x5d,                  // offset 27 -- popq %r13
335       0x41, 0x5e,                  // offset 29 -- popq %r14
336       0x41, 0x5f,                  // offset 31 -- popq %r15
337       0x5d,                        // offset 33 -- popq %rbp
338       0xc3,                        // offset 34 -- retq
339       0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever
340   };
341 
342   AddressRange sample_range(0x1000, sizeof(data));
343 
344   UnwindPlan unwind_plan(eRegisterKindLLDB);
345   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
346       data, sizeof(data), sample_range, unwind_plan));
347 
348   // Unwind rules should look like
349   // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
350   // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
351   // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
352   // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
353   // rip=[CFA-8
354   // 7: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
355   // r15=[CFA-24] rip=[CFA-8]
356   // 9: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
357   // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
358   // 10: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
359   // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
360   // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
361   // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
362 
363   // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
364   // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
365   // 25: 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   // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
368   // r15=[CFA-24] rip=[CFA-8]
369   // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
370   // rip=[CFA-8]
371   // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
372   // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
373   // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
374 
375   UnwindPlan::Row::RegisterLocation regloc;
376 
377   // grab the Row for when the prologue has finished executing:
378   // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
379   // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
380 
381   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(17);
382 
383   EXPECT_EQ(17ull, row_sp->GetOffset());
384   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
385   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
386   EXPECT_EQ(14496, row_sp->GetCFAValue().GetOffset());
387 
388   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
389   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
390   EXPECT_EQ(-8, regloc.GetOffset());
391 
392   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
393   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
394   EXPECT_EQ(-16, regloc.GetOffset());
395 
396   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
397   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
398   EXPECT_EQ(-24, regloc.GetOffset());
399 
400   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
401   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
402   EXPECT_EQ(-32, regloc.GetOffset());
403 
404   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
405   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
406   EXPECT_EQ(-40, regloc.GetOffset());
407 
408   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
409   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
410   EXPECT_EQ(-48, regloc.GetOffset());
411 
412   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
413   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
414   EXPECT_EQ(-56, regloc.GetOffset());
415 
416   // grab the Row for when the epilogue has finished executing:
417   // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
418 
419   row_sp = unwind_plan.GetRowForFunctionOffset(34);
420 
421   EXPECT_EQ(34ull, row_sp->GetOffset());
422   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
423   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
424   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
425 
426   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
427   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
428   EXPECT_EQ(-8, regloc.GetOffset());
429 
430   // these could be set to IsSame and be valid -- meaning that the
431   // register value is the same as the caller's -- but I'd rather
432   // they not be mentioned at all.
433 
434   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
435   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
436   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
437   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
438   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
439   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
440   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
441   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
442   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
443   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
444   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
445   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
446   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
447   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
448   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
449 }
450 
451 TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessBigStackFrame) {
452   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
453 
454   // this source file:
455   //
456   // #include <stdio.h>
457   // int main (int argc, char **argv)
458   // {
459   //
460   //     const int arrsize = 60;
461   //     int buf[arrsize * arrsize];
462   //     int accum = argc;
463   //     for (int i = 0; i < arrsize; i++)
464   //         for (int j = 0; j < arrsize; j++)
465   //         {
466   //             if (i > 0 && j > 0)
467   //             {
468   //                 int n = buf[(i-1) * (j-1)] * 2;
469   //                 int m = buf[(i-1) * (j-1)] / 2;
470   //                 int j = buf[(i-1) * (j-1)] + 2;
471   //                 int k = buf[(i-1) * (j-1)] - 2;
472   //                 printf ("%d ", n + m + j + k);
473   //                 buf[(i-1) * (j-1)] += n - m + j - k;
474   //             }
475   //             buf[i*j] = accum++;
476   //         }
477   //
478   //     return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
479   //     arrsize) - 3]);
480   // }
481   //
482   // compiled 'clang -arch i386 -fomit-frame-pointer -Os' for i386-apple-macosx
483 
484   // simplified assembly version of the above function, which is used as the
485   // input
486   // data:
487   //
488   // 	.section	__TEXT,__text,regular,pure_instructions
489   // 	.macosx_version_min 10, 12
490   // 	.globl	_main
491   // 	.align	4, 0x90
492   // _main:                                  ## @main
493   // ## BB#0:
494   // 	pushl %ebp
495   // 	pushl %ebx
496   // 	pushl %edi
497   // 	pushl %esi
498   // L0$pb:
499   // 	subl $0x386c, %esp
500   //     calll L1
501   // L1:
502   //     popl %ecx
503   //     movl %ecx, 0x8(%esp)
504   //     subl $0x8, %esp
505   //     pushl %eax
506   //     pushl 0x20(%esp)
507   //     calll _puts
508   //     addl $0x10, %esp
509   //     incl %ebx
510   //     addl $0x386c, %esp
511   //     popl %esi
512   //     popl %edi
513   //     popl %ebx
514   //     popl %ebp
515   //     retl
516   //
517   // 	.section	__TEXT,__cstring,cstring_literals
518   // L_.str:                                 ## @.str
519   // 	.asciz	"HI"
520   //
521   //
522   // .subsections_via_symbols
523 
524   uint8_t data[] = {
525       0x55,
526       // offset 0 -- pushl %ebp
527 
528       0x53,
529       // offset 1 -- pushl %ebx
530 
531       0x57,
532       // offset 2 -- pushl %edi
533 
534       0x56,
535       // offset 3 -- pushl %esi
536 
537       0x81, 0xec, 0x6c, 0x38, 0x00, 0x00,
538       // offset 4 -- subl $0x386c, %esp
539 
540       0xe8, 0x00, 0x00, 0x00, 0x00,
541       // offset 10 -- calll 0
542       // call the next instruction, to put the pc on the stack
543 
544       0x59,
545       // offset 15 -- popl %ecx
546       // pop the saved pc address into ecx
547 
548       0x89, 0x4c, 0x24, 0x08,
549       // offset 16 -- movl %ecx, 0x8(%esp)
550 
551       // ....
552 
553       0x83, 0xec, 0x08,
554       // offset 20 -- subl $0x8, %esp
555 
556       0x50,
557       // offset 23 -- pushl %eax
558 
559       0xff, 0x74, 0x24, 0x20,
560       // offset 24 -- pushl 0x20(%esp)
561 
562       0xe8, 0x8c, 0x00, 0x00, 0x00,
563       // offset 28 -- calll puts
564 
565       0x83, 0xc4, 0x10,
566       // offset 33 -- addl $0x10, %esp
567       // get esp back to the value it was before the
568       // alignment & argument saves for the puts call
569 
570       0x43,
571       // offset 36 -- incl %ebx
572 
573       // ....
574 
575       0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00,
576       // offset 37 -- addl $0x386c, %esp
577 
578       0x5e,
579       // offset 43 -- popl %esi
580 
581       0x5f,
582       // offset 44 -- popl %edi
583 
584       0x5b,
585       // offset 45 -- popl %ebx
586 
587       0x5d,
588       // offset 46 -- popl %ebp
589 
590       0xc3,
591       // offset 47 -- retl
592 
593       0xe8, 0x12, 0x34, 0x56, 0x78,
594       // offset 48 -- calll __stack_chk_fail
595   };
596 
597   AddressRange sample_range(0x1000, sizeof(data));
598 
599   UnwindPlan unwind_plan(eRegisterKindLLDB);
600   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
601       data, sizeof(data), sample_range, unwind_plan));
602 
603   // Unwind rules should look like
604   //
605   //   0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
606   //   1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
607   //   2: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
608   //   3: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
609   //   eip=[CFA-4]
610   //   4: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
611   //   esp=CFA+0 eip=[CFA-4]
612   //  10: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
613   //  esp=CFA+0 eip=[CFA-4]
614   //  15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
615   //  esp=CFA+0 eip=[CFA-4]
616   //  16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
617   //  esp=CFA+0 eip=[CFA-4]
618   //
619   //  ....
620   //
621   //  23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
622   //  esp=CFA+0 eip=[CFA-4]
623   //  24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
624   //  esp=CFA+0 eip=[CFA-4]
625   //  28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
626   //  esp=CFA+0 eip=[CFA-4]
627   //  36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
628   //  esp=CFA+0 eip=[CFA-4]
629   //
630   //  .....
631   //
632   //  37: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
633   //  esp=CFA+0 eip=[CFA-4]
634   //  43: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
635   //  esp=CFA+0 eip=[CFA-4]
636   //  44: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
637   //  eip=[CFA-4]
638   //  45: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
639   //  46: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
640   //  47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
641   //  48: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
642   //  esp=CFA+0 eip=[CFA-4]
643 
644   UnwindPlan::Row::RegisterLocation regloc;
645   UnwindPlan::RowSP row_sp;
646 
647   // Check that we get the CFA correct for the pic base setup sequence
648 
649   // CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
650   // esp=CFA+0 eip=[CFA-4]
651   row_sp = unwind_plan.GetRowForFunctionOffset(10);
652   EXPECT_EQ(10ull, row_sp->GetOffset());
653   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
654   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
655   EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
656 
657   // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
658   // esp=CFA+0 eip=[CFA-4]
659   row_sp = unwind_plan.GetRowForFunctionOffset(15);
660   EXPECT_EQ(15ull, row_sp->GetOffset());
661   EXPECT_EQ(14468, row_sp->GetCFAValue().GetOffset());
662 
663   // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
664   // esp=CFA+0 eip=[CFA-4]
665   row_sp = unwind_plan.GetRowForFunctionOffset(16);
666   EXPECT_EQ(16ull, row_sp->GetOffset());
667   EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
668 
669   // Check that the row for offset 16 has the registers saved that we expect
670 
671   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
672   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
673   EXPECT_EQ(-4, regloc.GetOffset());
674 
675   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
676   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
677   EXPECT_EQ(-8, regloc.GetOffset());
678 
679   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
680   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
681   EXPECT_EQ(-12, regloc.GetOffset());
682 
683   EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
684   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
685   EXPECT_EQ(-16, regloc.GetOffset());
686 
687   EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
688   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
689   EXPECT_EQ(-20, regloc.GetOffset());
690 
691   //
692   // Check the pushing & popping around the call printf instruction
693 
694   // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
695   // esp=CFA+0 eip=[CFA-4]
696   row_sp = unwind_plan.GetRowForFunctionOffset(23);
697   EXPECT_EQ(23ull, row_sp->GetOffset());
698   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
699   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
700   EXPECT_EQ(14472, row_sp->GetCFAValue().GetOffset());
701 
702   // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
703   // esp=CFA+0 eip=[CFA-4]
704   row_sp = unwind_plan.GetRowForFunctionOffset(24);
705   EXPECT_EQ(24ull, row_sp->GetOffset());
706   EXPECT_EQ(14476, row_sp->GetCFAValue().GetOffset());
707 
708   // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
709   // esp=CFA+0 eip=[CFA-4]
710   row_sp = unwind_plan.GetRowForFunctionOffset(28);
711   EXPECT_EQ(28ull, row_sp->GetOffset());
712   EXPECT_EQ(14480, row_sp->GetCFAValue().GetOffset());
713 
714   // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
715   // esp=CFA+0 eip=[CFA-4]
716   row_sp = unwind_plan.GetRowForFunctionOffset(36);
717   EXPECT_EQ(36ull, row_sp->GetOffset());
718   EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
719 
720   // Check that the epilogue gets us back to the original unwind state
721 
722   //  47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
723   row_sp = unwind_plan.GetRowForFunctionOffset(47);
724   EXPECT_EQ(47ull, row_sp->GetOffset());
725   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
726   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
727   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
728 
729   EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
730   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
731   EXPECT_EQ(-4, regloc.GetOffset());
732 
733   EXPECT_TRUE(row_sp->GetRegisterInfo(k_esp, regloc));
734   EXPECT_TRUE(regloc.IsCFAPlusOffset());
735   EXPECT_EQ(0, regloc.GetOffset());
736 
737   // Check that no unexpected registers were saved
738 
739   EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
740   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
741   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
742   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
743   EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
744   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
745   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
746 }
747 
748 TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessSmallStackFrame) {
749   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
750 
751   // this source file:
752   // #include <stdio.h>
753   // int main () {
754   //    puts ("HI");
755   // }
756   //
757   // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx
758 
759   uint8_t data[] = {
760       0x50,
761       // offset 0  -- pushq %rax
762 
763       0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00,
764       // offset 1 -- leaq 0x32(%rip), %rdi ; "HI"
765 
766       0xe8, 0x0b, 0x00, 0x00, 0x00,
767       // offset 8 -- callq 0x100000f58 ; puts
768 
769       0x31, 0xc9,
770       // offset 13 -- xorl %ecx, %ecx
771 
772       0x89, 0x44, 0x24, 0x04,
773       // offset 15 -- movl %eax, 0x4(%rsp)
774 
775       0x89, 0xc8,
776       // offset 19 -- movl %ecx, %eax
777 
778       0x59,
779       // offset 21 -- popq %rcx
780 
781       0xc3
782       // offset 22 -- retq
783   };
784 
785   AddressRange sample_range(0x1000, sizeof(data));
786 
787   UnwindPlan unwind_plan(eRegisterKindLLDB);
788   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
789       data, sizeof(data), sample_range, unwind_plan));
790 
791   // Unwind rules should look like
792   //     0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
793   //     1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
794   //    22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
795 
796   UnwindPlan::Row::RegisterLocation regloc;
797 
798   // grab the Row for when the prologue has finished executing:
799   //     1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
800 
801   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(13);
802 
803   EXPECT_EQ(1ull, row_sp->GetOffset());
804   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
805   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
806   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
807 
808   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
809   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
810   EXPECT_EQ(-8, regloc.GetOffset());
811 
812   // none of these were spilled
813 
814   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
815   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
816   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
817   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
818   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
819   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
820   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
821   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
822   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
823   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
824   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
825   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
826   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
827   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
828   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
829 
830   // grab the Row for when the epilogue has finished executing:
831   //     22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
832 
833   row_sp = unwind_plan.GetRowForFunctionOffset(22);
834 
835   EXPECT_EQ(22ull, row_sp->GetOffset());
836   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
837   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
838   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
839 
840   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
841   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
842   EXPECT_EQ(-8, regloc.GetOffset());
843 }
844 
845 TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) {
846   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
847 
848   // this source file:
849   // #include <stdio.h>
850   // int main () {
851   //    puts ("HI");
852   // }
853   //
854   // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx
855 
856   uint8_t data[] = {
857       0x83, 0xec, 0x0c,
858       // offset 0 -- subl $0xc, %esp
859 
860       0xe8, 0x00, 0x00, 0x00, 0x00,
861       // offset 3 -- calll 0 {call the next instruction, to put the pc on
862       // the stack}
863 
864       0x58,
865       // offset 8 -- popl %eax {pop the saved pc value off stack, into eax}
866 
867       0x8d, 0x80, 0x3a, 0x00, 0x00, 0x00,
868       // offset 9 -- leal 0x3a(%eax),%eax
869 
870       0x89, 0x04, 0x24,
871       // offset 15 -- movl %eax, (%esp)
872 
873       0xe8, 0x0d, 0x00, 0x00, 0x00,
874       // offset 18 -- calll 0x1f94 (puts)
875 
876       0x31, 0xc9,
877       // offset 23 -- xorl %ecx, %ecx
878 
879       0x89, 0x44, 0x24, 0x08,
880       // offset 25 -- movl %eax, 0x8(%esp)
881 
882       0x89, 0xc8,
883       // offset 29 -- movl %ecx, %eax
884 
885       0x83, 0xc4, 0x0c,
886       // offset 31 -- addl $0xc, %esp
887 
888       0xc3
889       // offset 34 -- retl
890   };
891 
892   AddressRange sample_range(0x1000, sizeof(data));
893 
894   UnwindPlan unwind_plan(eRegisterKindLLDB);
895   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
896       data, sizeof(data), sample_range, unwind_plan));
897 
898   // Unwind rules should look like
899   // row[0]:    0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
900   // row[1]:    3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
901   // row[2]:    8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
902   // row[3]:    9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
903   // row[4]:   34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
904 
905   UnwindPlan::Row::RegisterLocation regloc;
906 
907   // Check unwind state before we set up the picbase register
908   //      3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
909 
910   UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(3);
911 
912   EXPECT_EQ(3ull, row_sp->GetOffset());
913   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
914   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
915   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
916 
917   // Check unwind state after we call the next instruction
918   // 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
919 
920   row_sp = unwind_plan.GetRowForFunctionOffset(8);
921   EXPECT_EQ(8ull, row_sp->GetOffset());
922   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
923   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
924   EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
925 
926   // Check unwind state after we pop the pic base value off the stack
927   // row[3]:    9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
928 
929   row_sp = unwind_plan.GetRowForFunctionOffset(9);
930   EXPECT_EQ(9ull, row_sp->GetOffset());
931   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
932   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
933   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
934 
935   // Check that no unexpected registers were saved
936 
937   EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
938   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
939   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
940   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
941   EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
942   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
943   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
944 
945   // verify that we get back to the original unwind state before the ret
946   //  34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
947 
948   row_sp = unwind_plan.GetRowForFunctionOffset(34);
949   EXPECT_EQ(34ull, row_sp->GetOffset());
950   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
951   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
952   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
953 }
954 
955 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
956   UnwindPlan::Row::RegisterLocation regloc;
957   UnwindPlan::RowSP row_sp;
958 
959   uint8_t data[] = {
960       0x55, // pushq %rbp
961       0x90  // nop
962   };
963 
964   AddressRange sample_range(0x1000, sizeof(data));
965   UnwindPlan unwind_plan(eRegisterKindLLDB);
966 
967   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
968   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
969       data, sizeof(data), sample_range, unwind_plan));
970 
971   row_sp = unwind_plan.GetRowForFunctionOffset(1);
972 
973   EXPECT_EQ(1ull, row_sp->GetOffset());
974   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
975   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
976   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
977 
978   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
979   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
980   EXPECT_EQ(-16, regloc.GetOffset());
981 
982   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
983   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
984       data, sizeof(data), sample_range, unwind_plan));
985 
986   row_sp = unwind_plan.GetRowForFunctionOffset(1);
987 
988   EXPECT_EQ(1ull, row_sp->GetOffset());
989   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
990   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
991   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
992 
993   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
994   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
995   EXPECT_EQ(-8, regloc.GetOffset());
996 }
997 
998 TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
999   UnwindPlan::Row::RegisterLocation regloc;
1000   UnwindPlan::RowSP row_sp;
1001 
1002   uint8_t data[] = {
1003       0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
1004       0x6a, 0x7d,                   // pushl $0x7d
1005       0x90                          // nop
1006   };
1007 
1008   AddressRange sample_range(0x1000, sizeof(data));
1009   UnwindPlan unwind_plan(eRegisterKindLLDB);
1010 
1011   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1012   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1013       data, sizeof(data), sample_range, unwind_plan));
1014 
1015   row_sp = unwind_plan.GetRowForFunctionOffset(5);
1016   EXPECT_EQ(5ull, row_sp->GetOffset());
1017   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1018   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1019   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1020 
1021   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1022   EXPECT_EQ(7ull, row_sp->GetOffset());
1023   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1024   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1025   EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
1026 
1027   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1028   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1029       data, sizeof(data), sample_range, unwind_plan));
1030 
1031   row_sp = unwind_plan.GetRowForFunctionOffset(5);
1032   EXPECT_EQ(5ull, row_sp->GetOffset());
1033   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1034   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1035   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1036 
1037   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1038   EXPECT_EQ(7ull, row_sp->GetOffset());
1039   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1040   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1041   EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
1042 }
1043 
1044 // We treat 'pushq $0' / 'pushl $0' specially - this shows up
1045 // in the first function called in a new thread and it needs to
1046 // put a 0 as the saved pc.  We pretend it didn't change the CFA.
1047 TEST_F(Testx86AssemblyInspectionEngine, TestPush0) {
1048   UnwindPlan::Row::RegisterLocation regloc;
1049   UnwindPlan::RowSP row_sp;
1050 
1051   uint8_t data[] = {
1052       0x6a, 0x00, // pushq $0
1053       0x90        // nop
1054   };
1055 
1056   AddressRange sample_range(0x1000, sizeof(data));
1057   UnwindPlan unwind_plan(eRegisterKindLLDB);
1058 
1059   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1060   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1061       data, sizeof(data), sample_range, unwind_plan));
1062 
1063   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1064 
1065   // We're verifying that no row was created for the 'pushq $0'
1066   EXPECT_EQ(0ull, row_sp->GetOffset());
1067 
1068   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1069   EXPECT_TRUE(engine32->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 
1078 TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
1079   UnwindPlan::Row::RegisterLocation regloc;
1080   UnwindPlan::RowSP row_sp;
1081 
1082   uint8_t data[] = {
1083       0xff, 0x74, 0x24, 0x20,             // pushl 0x20(%esp)
1084       0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl  0xf001ce(%esi)
1085       0xff, 0x30,                         // pushl  (%eax)
1086       0x90                                // nop
1087   };
1088 
1089   AddressRange sample_range(0x1000, sizeof(data));
1090   UnwindPlan unwind_plan(eRegisterKindLLDB);
1091 
1092   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1093   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1094       data, sizeof(data), sample_range, unwind_plan));
1095 
1096   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1097 
1098   EXPECT_EQ(4ull, row_sp->GetOffset());
1099   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1100   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1101   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1102 
1103   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1104   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1105       data, sizeof(data), sample_range, unwind_plan));
1106 
1107   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1108   EXPECT_EQ(4ull, row_sp->GetOffset());
1109   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1110   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1111   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1112 
1113   row_sp = unwind_plan.GetRowForFunctionOffset(10);
1114   EXPECT_EQ(10ull, row_sp->GetOffset());
1115   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1116   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1117   EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
1118 
1119   row_sp = unwind_plan.GetRowForFunctionOffset(12);
1120   EXPECT_EQ(12ull, row_sp->GetOffset());
1121   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1122   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1123   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1124 }
1125 
1126 TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
1127   UnwindPlan::Row::RegisterLocation regloc;
1128   UnwindPlan::RowSP row_sp;
1129 
1130   uint8_t data[] = {
1131       0x41, 0x57, // pushq %r15
1132       0x90        // nop
1133   };
1134 
1135   AddressRange sample_range(0x1000, sizeof(data));
1136   UnwindPlan unwind_plan(eRegisterKindLLDB);
1137 
1138   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1139   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1140       data, sizeof(data), sample_range, unwind_plan));
1141 
1142   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1143 
1144   EXPECT_EQ(2ull, row_sp->GetOffset());
1145   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1146   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1147   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1148 
1149   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
1150   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1151   EXPECT_EQ(-16, regloc.GetOffset());
1152 }
1153 
1154 TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {
1155   UnwindPlan::Row::RegisterLocation regloc;
1156   UnwindPlan::RowSP row_sp;
1157 
1158   uint8_t data[] = {
1159       0x41, 0x56, // pushq %r14
1160       0x90        // nop
1161   };
1162 
1163   AddressRange sample_range(0x1000, sizeof(data));
1164   UnwindPlan unwind_plan(eRegisterKindLLDB);
1165 
1166   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1167   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1168       data, sizeof(data), sample_range, unwind_plan));
1169 
1170   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1171 
1172   EXPECT_EQ(2ull, row_sp->GetOffset());
1173   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1174   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1175   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1176 
1177   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
1178   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1179   EXPECT_EQ(-16, regloc.GetOffset());
1180 }
1181 
1182 TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {
1183   UnwindPlan::Row::RegisterLocation regloc;
1184   UnwindPlan::RowSP row_sp;
1185 
1186   uint8_t data[] = {
1187       0x41, 0x55, // pushq %r13
1188       0x90        // nop
1189   };
1190 
1191   AddressRange sample_range(0x1000, sizeof(data));
1192   UnwindPlan unwind_plan(eRegisterKindLLDB);
1193 
1194   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1195   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1196       data, sizeof(data), sample_range, unwind_plan));
1197 
1198   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1199 
1200   EXPECT_EQ(2ull, row_sp->GetOffset());
1201   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1202   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1203   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1204 
1205   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
1206   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1207   EXPECT_EQ(-16, regloc.GetOffset());
1208 }
1209 
1210 TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {
1211   UnwindPlan::Row::RegisterLocation regloc;
1212   UnwindPlan::RowSP row_sp;
1213 
1214   uint8_t data[] = {
1215       0x41, 0x54, // pushq %r13
1216       0x90        // nop
1217   };
1218 
1219   AddressRange sample_range(0x1000, sizeof(data));
1220   UnwindPlan unwind_plan(eRegisterKindLLDB);
1221 
1222   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1223   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1224       data, sizeof(data), sample_range, unwind_plan));
1225 
1226   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1227 
1228   EXPECT_EQ(2ull, row_sp->GetOffset());
1229   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1230   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1231   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1232 
1233   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
1234   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1235   EXPECT_EQ(-16, regloc.GetOffset());
1236 }
1237 
1238 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {
1239   UnwindPlan::Row::RegisterLocation regloc;
1240   UnwindPlan::RowSP row_sp;
1241 
1242   uint8_t data[] = {
1243       0x53, // pushq %rbx
1244       0x90  // nop
1245   };
1246 
1247   AddressRange sample_range(0x1000, sizeof(data));
1248   UnwindPlan unwind_plan(eRegisterKindLLDB);
1249 
1250   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1251   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1252       data, sizeof(data), sample_range, unwind_plan));
1253 
1254   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1255 
1256   EXPECT_EQ(1ull, row_sp->GetOffset());
1257   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1258   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1259   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1260 
1261   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
1262   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1263   EXPECT_EQ(-16, regloc.GetOffset());
1264 }
1265 
1266 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1267 // eax, ecx, edx are all considered volatile and push/pops of them are
1268 // not tracked (except to keep track of stack pointer movement)
1269 TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) {
1270   UnwindPlan::Row::RegisterLocation regloc;
1271   UnwindPlan::RowSP row_sp;
1272   AddressRange sample_range;
1273   UnwindPlan unwind_plan(eRegisterKindLLDB);
1274   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1275 
1276   uint8_t data[] = {
1277       0x50, // pushl %eax
1278       0x90  // nop
1279   };
1280 
1281   sample_range = AddressRange(0x1000, sizeof(data));
1282 
1283   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1284       data, sizeof(data), sample_range, unwind_plan));
1285 
1286   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1287   EXPECT_EQ(1ull, row_sp->GetOffset());
1288   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1289   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1290   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1291 
1292   EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
1293 }
1294 
1295 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1296 // eax, ecx, edx are all considered volatile and push/pops of them are
1297 // not tracked (except to keep track of stack pointer movement)
1298 TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) {
1299   UnwindPlan::Row::RegisterLocation regloc;
1300   UnwindPlan::RowSP row_sp;
1301   AddressRange sample_range;
1302   UnwindPlan unwind_plan(eRegisterKindLLDB);
1303   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1304 
1305   uint8_t data[] = {
1306       0x51, // pushl %ecx
1307       0x90  // nop
1308   };
1309 
1310   sample_range = AddressRange(0x1000, sizeof(data));
1311 
1312   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1313       data, sizeof(data), sample_range, unwind_plan));
1314 
1315   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1316   EXPECT_EQ(1ull, row_sp->GetOffset());
1317   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1318   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1319   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1320 
1321   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
1322 }
1323 
1324 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1325 // eax, ecx, edx are all considered volatile and push/pops of them are
1326 // not tracked (except to keep track of stack pointer movement)
1327 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) {
1328   UnwindPlan::Row::RegisterLocation regloc;
1329   UnwindPlan::RowSP row_sp;
1330   AddressRange sample_range;
1331   UnwindPlan unwind_plan(eRegisterKindLLDB);
1332   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1333 
1334   uint8_t data[] = {
1335       0x52, // pushl %edx
1336       0x90  // nop
1337   };
1338 
1339   sample_range = AddressRange(0x1000, sizeof(data));
1340 
1341   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1342       data, sizeof(data), sample_range, unwind_plan));
1343 
1344   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1345   EXPECT_EQ(1ull, row_sp->GetOffset());
1346   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1347   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1348   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1349 
1350   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
1351 }
1352 
1353 TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {
1354   UnwindPlan::Row::RegisterLocation regloc;
1355   UnwindPlan::RowSP row_sp;
1356   AddressRange sample_range;
1357   UnwindPlan unwind_plan(eRegisterKindLLDB);
1358   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1359 
1360   uint8_t data[] = {
1361       0x53, // pushl %ebx
1362       0x90  // nop
1363   };
1364 
1365   sample_range = AddressRange(0x1000, sizeof(data));
1366 
1367   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1368       data, sizeof(data), sample_range, unwind_plan));
1369 
1370   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1371   EXPECT_EQ(1ull, row_sp->GetOffset());
1372   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1373   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1374   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1375 
1376   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
1377   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1378   EXPECT_EQ(-8, regloc.GetOffset());
1379 }
1380 
1381 TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {
1382   UnwindPlan::Row::RegisterLocation regloc;
1383   UnwindPlan::RowSP row_sp;
1384   AddressRange sample_range;
1385   UnwindPlan unwind_plan(eRegisterKindLLDB);
1386   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1387 
1388   uint8_t data[] = {
1389       0x55, // pushl %ebp
1390       0x90  // nop
1391   };
1392 
1393   sample_range = AddressRange(0x1000, sizeof(data));
1394 
1395   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1396       data, sizeof(data), sample_range, unwind_plan));
1397 
1398   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1399   EXPECT_EQ(1ull, row_sp->GetOffset());
1400   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1401   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1402   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1403 
1404   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
1405   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1406   EXPECT_EQ(-8, regloc.GetOffset());
1407 }
1408 
1409 TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {
1410   UnwindPlan::Row::RegisterLocation regloc;
1411   UnwindPlan::RowSP row_sp;
1412   AddressRange sample_range;
1413   UnwindPlan unwind_plan(eRegisterKindLLDB);
1414   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1415 
1416   uint8_t data[] = {
1417       0x56, // pushl %esi
1418       0x90  // nop
1419   };
1420 
1421   sample_range = AddressRange(0x1000, sizeof(data));
1422 
1423   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1424       data, sizeof(data), sample_range, unwind_plan));
1425 
1426   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1427   EXPECT_EQ(1ull, row_sp->GetOffset());
1428   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1429   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1430   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1431 
1432   EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
1433   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1434   EXPECT_EQ(-8, regloc.GetOffset());
1435 }
1436 
1437 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {
1438   UnwindPlan::Row::RegisterLocation regloc;
1439   UnwindPlan::RowSP row_sp;
1440   AddressRange sample_range;
1441   UnwindPlan unwind_plan(eRegisterKindLLDB);
1442   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1443 
1444   uint8_t data[] = {
1445       0x57, // pushl %edi
1446       0x90  // nop
1447   };
1448 
1449   sample_range = AddressRange(0x1000, sizeof(data));
1450 
1451   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1452       data, sizeof(data), sample_range, unwind_plan));
1453 
1454   row_sp = unwind_plan.GetRowForFunctionOffset(1);
1455   EXPECT_EQ(1ull, row_sp->GetOffset());
1456   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1457   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1458   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1459 
1460   EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
1461   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1462   EXPECT_EQ(-8, regloc.GetOffset());
1463 }
1464 
1465 TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
1466   UnwindPlan::Row::RegisterLocation regloc;
1467   UnwindPlan::RowSP row_sp;
1468 
1469   uint8_t data64_1[] = {
1470       0x48, 0x8b, 0xec, // movq %rsp, %rbp
1471       0x90              // nop
1472   };
1473 
1474   AddressRange sample_range(0x1000, sizeof(data64_1));
1475   UnwindPlan unwind_plan(eRegisterKindLLDB);
1476 
1477   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1478   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1479       data64_1, sizeof(data64_1), sample_range, unwind_plan));
1480 
1481   row_sp = unwind_plan.GetRowForFunctionOffset(3);
1482 
1483   EXPECT_EQ(3ull, row_sp->GetOffset());
1484   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
1485   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1486   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1487 
1488   uint8_t data64_2[] = {
1489       0x48, 0x89, 0xe5, // movq %rsp, %rbp
1490       0x90              // nop
1491   };
1492 
1493   sample_range = AddressRange(0x1000, sizeof(data64_2));
1494   unwind_plan.Clear();
1495   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1496       data64_2, sizeof(data64_2), sample_range, unwind_plan));
1497 
1498   row_sp = unwind_plan.GetRowForFunctionOffset(3);
1499   EXPECT_EQ(3ull, row_sp->GetOffset());
1500   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
1501   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1502   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1503 
1504   uint8_t data32_1[] = {
1505       0x8b, 0xec, // movl %rsp, %rbp
1506       0x90        // nop
1507   };
1508 
1509   sample_range = AddressRange(0x1000, sizeof(data32_1));
1510   unwind_plan.Clear();
1511   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1512       data32_1, sizeof(data32_1), sample_range, unwind_plan));
1513 
1514   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1515   EXPECT_EQ(2ull, row_sp->GetOffset());
1516   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
1517   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1518   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1519 
1520   uint8_t data32_2[] = {
1521       0x89, 0xe5, // movl %rsp, %rbp
1522       0x90        // nop
1523   };
1524 
1525   sample_range = AddressRange(0x1000, sizeof(data32_2));
1526   unwind_plan.Clear();
1527   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1528       data32_2, sizeof(data32_2), sample_range, unwind_plan));
1529 
1530   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1531   EXPECT_EQ(2ull, row_sp->GetOffset());
1532   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
1533   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1534   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1535 }
1536 
1537 TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {
1538   UnwindPlan::Row::RegisterLocation regloc;
1539   UnwindPlan::RowSP row_sp;
1540   AddressRange sample_range;
1541   UnwindPlan unwind_plan(eRegisterKindLLDB);
1542   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1543 
1544   uint8_t data1[] = {
1545       0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp
1546       0x90                                      // nop
1547   };
1548 
1549   sample_range = AddressRange(0x1000, sizeof(data1));
1550 
1551   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1552       data1, sizeof(data1), sample_range, unwind_plan));
1553 
1554   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1555   EXPECT_EQ(7ull, row_sp->GetOffset());
1556   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1557   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1558   EXPECT_EQ(264, row_sp->GetCFAValue().GetOffset());
1559 
1560   uint8_t data2[] = {
1561       0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp
1562       0x90                    // nop
1563   };
1564 
1565   sample_range = AddressRange(0x1000, sizeof(data2));
1566 
1567   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1568       data2, sizeof(data2), sample_range, unwind_plan));
1569 
1570   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1571   EXPECT_EQ(4ull, row_sp->GetOffset());
1572   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1573   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1574   EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
1575 }
1576 
1577 TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {
1578   UnwindPlan::Row::RegisterLocation regloc;
1579   UnwindPlan::RowSP row_sp;
1580   AddressRange sample_range;
1581   UnwindPlan unwind_plan(eRegisterKindLLDB);
1582   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1583 
1584   uint8_t data1[] = {
1585       0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp
1586       0x90                                // nop
1587   };
1588 
1589   sample_range = AddressRange(0x1000, sizeof(data1));
1590 
1591   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1592       data1, sizeof(data1), sample_range, unwind_plan));
1593 
1594   row_sp = unwind_plan.GetRowForFunctionOffset(6);
1595   EXPECT_EQ(6ull, row_sp->GetOffset());
1596   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1597   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1598   EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset());
1599 
1600   uint8_t data2[] = {
1601       0x83, 0xec, 0x10, // subq $0x10, %esp
1602       0x90              // nop
1603   };
1604 
1605   sample_range = AddressRange(0x1000, sizeof(data2));
1606 
1607   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1608       data2, sizeof(data2), sample_range, unwind_plan));
1609 
1610   row_sp = unwind_plan.GetRowForFunctionOffset(3);
1611   EXPECT_EQ(3ull, row_sp->GetOffset());
1612   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1613   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1614   EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
1615 }
1616 
1617 TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {
1618   UnwindPlan::Row::RegisterLocation regloc;
1619   UnwindPlan::RowSP row_sp;
1620   AddressRange sample_range;
1621   UnwindPlan unwind_plan(eRegisterKindLLDB);
1622   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1623 
1624   uint8_t data1[] = {
1625       0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp
1626       0x90                                      // nop
1627   };
1628 
1629   sample_range = AddressRange(0x1000, sizeof(data1));
1630 
1631   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1632       data1, sizeof(data1), sample_range, unwind_plan));
1633 
1634   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1635   EXPECT_EQ(7ull, row_sp->GetOffset());
1636   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1637   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1638   EXPECT_EQ(8 - 256, row_sp->GetCFAValue().GetOffset());
1639 
1640   uint8_t data2[] = {
1641       0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp
1642       0x90                    // nop
1643   };
1644 
1645   sample_range = AddressRange(0x1000, sizeof(data2));
1646 
1647   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1648       data2, sizeof(data2), sample_range, unwind_plan));
1649 
1650   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1651   EXPECT_EQ(4ull, row_sp->GetOffset());
1652   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1653   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1654   EXPECT_EQ(8 - 16, row_sp->GetCFAValue().GetOffset());
1655 }
1656 
1657 TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {
1658   UnwindPlan::Row::RegisterLocation regloc;
1659   UnwindPlan::RowSP row_sp;
1660   AddressRange sample_range;
1661   UnwindPlan unwind_plan(eRegisterKindLLDB);
1662   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1663 
1664   uint8_t data1[] = {
1665       0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
1666       0x90                                // nop
1667   };
1668 
1669   sample_range = AddressRange(0x1000, sizeof(data1));
1670 
1671   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1672       data1, sizeof(data1), sample_range, unwind_plan));
1673 
1674   row_sp = unwind_plan.GetRowForFunctionOffset(6);
1675   EXPECT_EQ(6ull, row_sp->GetOffset());
1676   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1677   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1678   EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset());
1679 
1680   uint8_t data2[] = {
1681       0x83, 0xc4, 0x10, // addq $0x10, %esp
1682       0x90              // nop
1683   };
1684 
1685   sample_range = AddressRange(0x1000, sizeof(data2));
1686 
1687   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1688       data2, sizeof(data2), sample_range, unwind_plan));
1689 
1690   row_sp = unwind_plan.GetRowForFunctionOffset(3);
1691   EXPECT_EQ(3ull, row_sp->GetOffset());
1692   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1693   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1694   EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset());
1695 }
1696 
1697 // FIXME add test for lea_rsp_pattern_p
1698 
1699 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {
1700   UnwindPlan::Row::RegisterLocation regloc;
1701   UnwindPlan::RowSP row_sp;
1702   AddressRange sample_range;
1703   UnwindPlan unwind_plan(eRegisterKindLLDB);
1704   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1705 
1706   uint8_t data[] = {
1707       0x53, // pushq %rbx
1708       0x5b, // popq %rbx
1709       0x90  // nop
1710   };
1711 
1712   sample_range = AddressRange(0x1000, sizeof(data));
1713 
1714   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1715       data, sizeof(data), sample_range, unwind_plan));
1716 
1717   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1718   EXPECT_EQ(2ull, row_sp->GetOffset());
1719   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1720   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1721   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1722   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
1723 }
1724 
1725 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {
1726   UnwindPlan::Row::RegisterLocation regloc;
1727   UnwindPlan::RowSP row_sp;
1728   AddressRange sample_range;
1729   UnwindPlan unwind_plan(eRegisterKindLLDB);
1730   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1731 
1732   uint8_t data[] = {
1733       0x55, // pushq %rbp
1734       0x5d, // popq %rbp
1735       0x90  // nop
1736   };
1737 
1738   sample_range = AddressRange(0x1000, sizeof(data));
1739 
1740   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1741       data, sizeof(data), sample_range, unwind_plan));
1742 
1743   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1744   EXPECT_EQ(2ull, row_sp->GetOffset());
1745   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1746   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1747   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1748   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
1749 }
1750 
1751 TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {
1752   UnwindPlan::Row::RegisterLocation regloc;
1753   UnwindPlan::RowSP row_sp;
1754   AddressRange sample_range;
1755   UnwindPlan unwind_plan(eRegisterKindLLDB);
1756   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1757 
1758   uint8_t data[] = {
1759       0x41, 0x54, // pushq %r12
1760       0x41, 0x5c, // popq %r12
1761       0x90        // nop
1762   };
1763 
1764   sample_range = AddressRange(0x1000, sizeof(data));
1765 
1766   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1767       data, sizeof(data), sample_range, unwind_plan));
1768 
1769   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1770   EXPECT_EQ(4ull, row_sp->GetOffset());
1771   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1772   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1773   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1774   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
1775 }
1776 
1777 TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {
1778   UnwindPlan::Row::RegisterLocation regloc;
1779   UnwindPlan::RowSP row_sp;
1780   AddressRange sample_range;
1781   UnwindPlan unwind_plan(eRegisterKindLLDB);
1782   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1783 
1784   uint8_t data[] = {
1785       0x41, 0x55, // pushq %r13
1786       0x41, 0x5d, // popq %r13
1787       0x90        // nop
1788   };
1789 
1790   sample_range = AddressRange(0x1000, sizeof(data));
1791 
1792   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1793       data, sizeof(data), sample_range, unwind_plan));
1794 
1795   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1796   EXPECT_EQ(4ull, row_sp->GetOffset());
1797   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1798   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1799   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1800   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
1801 }
1802 
1803 TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {
1804   UnwindPlan::Row::RegisterLocation regloc;
1805   UnwindPlan::RowSP row_sp;
1806   AddressRange sample_range;
1807   UnwindPlan unwind_plan(eRegisterKindLLDB);
1808   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1809 
1810   uint8_t data[] = {
1811       0x41, 0x56, // pushq %r14
1812       0x41, 0x5e, // popq %r14
1813       0x90        // nop
1814   };
1815 
1816   sample_range = AddressRange(0x1000, sizeof(data));
1817 
1818   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1819       data, sizeof(data), sample_range, unwind_plan));
1820 
1821   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1822   EXPECT_EQ(4ull, row_sp->GetOffset());
1823   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1824   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1825   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1826   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
1827 }
1828 
1829 TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {
1830   UnwindPlan::Row::RegisterLocation regloc;
1831   UnwindPlan::RowSP row_sp;
1832   AddressRange sample_range;
1833   UnwindPlan unwind_plan(eRegisterKindLLDB);
1834   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1835 
1836   uint8_t data[] = {
1837       0x41, 0x57, // pushq %r15
1838       0x41, 0x5f, // popq %r15
1839       0x90        // nop
1840   };
1841 
1842   sample_range = AddressRange(0x1000, sizeof(data));
1843 
1844   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1845       data, sizeof(data), sample_range, unwind_plan));
1846 
1847   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1848   EXPECT_EQ(4ull, row_sp->GetOffset());
1849   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1850   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1851   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1852   EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
1853 }
1854 
1855 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {
1856   UnwindPlan::Row::RegisterLocation regloc;
1857   UnwindPlan::RowSP row_sp;
1858   AddressRange sample_range;
1859   UnwindPlan unwind_plan(eRegisterKindLLDB);
1860   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1861 
1862   uint8_t data[] = {
1863       0x53, // pushl %ebx
1864       0x5b, // popl %ebx
1865       0x90  // nop
1866   };
1867 
1868   sample_range = AddressRange(0x1000, sizeof(data));
1869 
1870   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1871       data, sizeof(data), sample_range, unwind_plan));
1872 
1873   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1874   EXPECT_EQ(2ull, row_sp->GetOffset());
1875   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1876   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1877   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1878   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
1879 }
1880 
1881 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {
1882   UnwindPlan::Row::RegisterLocation regloc;
1883   UnwindPlan::RowSP row_sp;
1884   AddressRange sample_range;
1885   UnwindPlan unwind_plan(eRegisterKindLLDB);
1886   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1887 
1888   uint8_t data[] = {
1889       0x55, // pushl %ebp
1890       0x5d, // popl %ebp
1891       0x90  // nop
1892   };
1893 
1894   sample_range = AddressRange(0x1000, sizeof(data));
1895 
1896   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1897       data, sizeof(data), sample_range, unwind_plan));
1898 
1899   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1900   EXPECT_EQ(2ull, row_sp->GetOffset());
1901   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1902   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1903   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1904   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
1905 }
1906 
1907 TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {
1908   UnwindPlan::Row::RegisterLocation regloc;
1909   UnwindPlan::RowSP row_sp;
1910   AddressRange sample_range;
1911   UnwindPlan unwind_plan(eRegisterKindLLDB);
1912   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1913 
1914   uint8_t data[] = {
1915       0x56, // pushl %esi
1916       0x5e, // popl %esi
1917       0x90  // nop
1918   };
1919 
1920   sample_range = AddressRange(0x1000, sizeof(data));
1921 
1922   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1923       data, sizeof(data), sample_range, unwind_plan));
1924 
1925   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1926   EXPECT_EQ(2ull, row_sp->GetOffset());
1927   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1928   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1929   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1930   EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
1931 }
1932 
1933 TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {
1934   UnwindPlan::Row::RegisterLocation regloc;
1935   UnwindPlan::RowSP row_sp;
1936   AddressRange sample_range;
1937   UnwindPlan unwind_plan(eRegisterKindLLDB);
1938   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1939 
1940   uint8_t data[] = {
1941       0x57, // pushl %edi
1942       0x5f, // popl %edi
1943       0x90  // nop
1944   };
1945 
1946   sample_range = AddressRange(0x1000, sizeof(data));
1947 
1948   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1949       data, sizeof(data), sample_range, unwind_plan));
1950 
1951   row_sp = unwind_plan.GetRowForFunctionOffset(2);
1952   EXPECT_EQ(2ull, row_sp->GetOffset());
1953   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1954   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1955   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1956   EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
1957 }
1958 
1959 // We don't track these registers, but make sure the CFA address is updated
1960 // if we're defining the CFA in term of esp.
1961 TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {
1962   UnwindPlan::Row::RegisterLocation regloc;
1963   UnwindPlan::RowSP row_sp;
1964   AddressRange sample_range;
1965   UnwindPlan unwind_plan(eRegisterKindLLDB);
1966   std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1967 
1968   uint8_t data[] = {
1969       0x0e, // push cs
1970       0x16, // push ss
1971       0x1e, // push ds
1972       0x06, // push es
1973 
1974       0x07, // pop es
1975       0x1f, // pop ds
1976       0x17, // pop ss
1977 
1978       0x90 // nop
1979   };
1980 
1981   sample_range = AddressRange(0x1000, sizeof(data));
1982 
1983   EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1984       data, sizeof(data), sample_range, unwind_plan));
1985 
1986   row_sp = unwind_plan.GetRowForFunctionOffset(4);
1987   EXPECT_EQ(4ull, row_sp->GetOffset());
1988   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1989   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1990   EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
1991 
1992   row_sp = unwind_plan.GetRowForFunctionOffset(7);
1993   EXPECT_EQ(7ull, row_sp->GetOffset());
1994   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1995   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1996   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1997 }
1998 
1999 TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {
2000   UnwindPlan::Row::RegisterLocation regloc;
2001   UnwindPlan::RowSP row_sp;
2002   AddressRange sample_range;
2003   UnwindPlan unwind_plan(eRegisterKindLLDB);
2004   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2005   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2006 
2007   uint8_t data[] = {
2008       0x55, // push %rbp/ebp
2009       0xc9, // leave
2010       0x90  // nop
2011   };
2012 
2013   sample_range = AddressRange(0x1000, sizeof(data));
2014 
2015   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2016       data, sizeof(data), sample_range, unwind_plan));
2017 
2018   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2019   EXPECT_EQ(2ull, row_sp->GetOffset());
2020   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2021   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2022   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2023   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2024 
2025   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2026       data, sizeof(data), sample_range, unwind_plan));
2027 
2028   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2029   EXPECT_EQ(2ull, row_sp->GetOffset());
2030   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2031   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2032   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2033   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2034 }
2035 
2036 // In i386, which lacks pc-relative addressing, a common code sequence
2037 // is to call the next instruction (i.e. call imm32, value of 0) which
2038 // pushes the addr of the next insn on the stack, and then pop that value
2039 // into a register (the "pic base" register).
2040 TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {
2041   UnwindPlan::Row::RegisterLocation regloc;
2042   UnwindPlan::RowSP row_sp;
2043   AddressRange sample_range;
2044   UnwindPlan unwind_plan(eRegisterKindLLDB);
2045   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2046 
2047   uint8_t data[] = {
2048       0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
2049       0x90                          // nop
2050   };
2051 
2052   sample_range = AddressRange(0x1000, sizeof(data));
2053 
2054   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2055       data, sizeof(data), sample_range, unwind_plan));
2056 
2057   row_sp = unwind_plan.GetRowForFunctionOffset(5);
2058   EXPECT_EQ(5ull, row_sp->GetOffset());
2059   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2060   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2061   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2062   EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2063 }
2064 
2065 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {
2066   UnwindPlan::Row::RegisterLocation regloc;
2067   UnwindPlan::RowSP row_sp;
2068   AddressRange sample_range;
2069   UnwindPlan unwind_plan(eRegisterKindLLDB);
2070   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2071 
2072   uint8_t data[] = {
2073       0x55,                                     // pushq %rbp
2074       0x48, 0x89, 0xe5,                         // movq %rsp, %rbp
2075       0x4c, 0x89, 0x75, 0xc0,                   // movq   %r14, -0x40(%rbp)
2076       0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq   %r15, -0x5d8(%rbp)
2077       0x48, 0x89, 0x5d, 0xb8,                   // movq %rbx, -0x48(%rbp)
2078       0x90                                      // nop
2079   };
2080 
2081   sample_range = AddressRange(0x1000, sizeof(data));
2082 
2083   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2084       data, sizeof(data), sample_range, unwind_plan));
2085 
2086   row_sp = unwind_plan.GetRowForFunctionOffset(19);
2087   EXPECT_EQ(19ull, row_sp->GetOffset());
2088   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2089   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2090 
2091   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
2092   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2093   EXPECT_EQ(-80, regloc.GetOffset());
2094 
2095   EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
2096   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2097   EXPECT_EQ(-1512, regloc.GetOffset());
2098 
2099   EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
2100   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2101   EXPECT_EQ(-88, regloc.GetOffset());
2102 }
2103 
2104 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {
2105   UnwindPlan::Row::RegisterLocation regloc;
2106   UnwindPlan::RowSP row_sp;
2107   AddressRange sample_range;
2108   UnwindPlan unwind_plan(eRegisterKindLLDB);
2109   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2110 
2111   uint8_t data[] = {
2112       0x55,                               // pushl %ebp
2113       0x89, 0xe5,                         // movl %esp, %ebp
2114       0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
2115       0x89, 0x75, 0xe0,                   // movl %esi, -0x20(%ebp)
2116       0x90                                // nop
2117   };
2118 
2119   sample_range = AddressRange(0x1000, sizeof(data));
2120 
2121   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2122       data, sizeof(data), sample_range, unwind_plan));
2123 
2124   row_sp = unwind_plan.GetRowForFunctionOffset(12);
2125   EXPECT_EQ(12ull, row_sp->GetOffset());
2126   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2127   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2128 
2129   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
2130   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2131   EXPECT_EQ(-344, regloc.GetOffset());
2132 
2133   EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
2134   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2135   EXPECT_EQ(-40, regloc.GetOffset());
2136 }
2137 
2138 TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {
2139   UnwindPlan::Row::RegisterLocation regloc;
2140   UnwindPlan::RowSP row_sp;
2141   AddressRange sample_range;
2142   UnwindPlan unwind_plan(eRegisterKindLLDB);
2143   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2144 
2145   uint8_t data[] = {
2146       0x55,             // pushq %rbp
2147       0x48, 0x89, 0xe5, // movq %rsp, %rbp
2148 
2149       // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2150       // has a bug where it can't augment a function that is just
2151       // prologue+epilogue - it needs at least one other instruction
2152       // in between.
2153       0x90, // nop
2154 
2155       0x5d, // popq %rbp
2156       0xc3  // retq
2157   };
2158 
2159   sample_range = AddressRange(0x1000, sizeof(data));
2160 
2161   unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2162   unwind_plan.SetPlanValidAddressRange(sample_range);
2163   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2164 
2165   row_sp.reset(new UnwindPlan::Row);
2166 
2167   // Describe offset 0
2168   row_sp->SetOffset(0);
2169   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
2170 
2171   regloc.SetAtCFAPlusOffset(-8);
2172   row_sp->SetRegisterInfo(k_rip, regloc);
2173 
2174   unwind_plan.AppendRow(row_sp);
2175 
2176   // Allocate a new Row, populate it with the existing Row contents.
2177   UnwindPlan::Row *new_row = new UnwindPlan::Row;
2178   *new_row = *row_sp.get();
2179   row_sp.reset(new_row);
2180 
2181   // Describe offset 1
2182   row_sp->SetOffset(1);
2183   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
2184   regloc.SetAtCFAPlusOffset(-16);
2185   row_sp->SetRegisterInfo(k_rbp, regloc);
2186   unwind_plan.AppendRow(row_sp);
2187 
2188   // Allocate a new Row, populate it with the existing Row contents.
2189   new_row = new UnwindPlan::Row;
2190   *new_row = *row_sp.get();
2191   row_sp.reset(new_row);
2192 
2193   // Describe offset 4
2194   row_sp->SetOffset(4);
2195   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rbp, 16);
2196   unwind_plan.AppendRow(row_sp);
2197 
2198   RegisterContextSP reg_ctx_sp;
2199   EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2200       data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2201 
2202   row_sp = unwind_plan.GetRowForFunctionOffset(6);
2203   EXPECT_EQ(6ull, row_sp->GetOffset());
2204   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2205   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2206 
2207   // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2208   // doesn't track register restores (pop'ing a reg value back from
2209   // the stack) - it was just written to make stepping work correctly.
2210   // Technically we should be able to do the following test, but it
2211   // won't work today - the unwind plan will still say that the caller's
2212   // rbp is on the stack.
2213   // EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2214 }
2215 
2216 TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) {
2217   UnwindPlan::Row::RegisterLocation regloc;
2218   UnwindPlan::RowSP row_sp;
2219   AddressRange sample_range;
2220   UnwindPlan unwind_plan(eRegisterKindLLDB);
2221   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2222 
2223   uint8_t data[] = {
2224       0x55,       // pushl %ebp
2225       0x89, 0xe5, // movl %esp, %ebp
2226 
2227       // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2228       // has a bug where it can't augment a function that is just
2229       // prologue+epilogue - it needs at least one other instruction
2230       // in between.
2231       0x90, // nop
2232 
2233       0x5d, // popl %ebp
2234       0xc3  // retl
2235   };
2236 
2237   sample_range = AddressRange(0x1000, sizeof(data));
2238 
2239   unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2240   unwind_plan.SetPlanValidAddressRange(sample_range);
2241   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2242 
2243   row_sp.reset(new UnwindPlan::Row);
2244 
2245   // Describe offset 0
2246   row_sp->SetOffset(0);
2247   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 4);
2248 
2249   regloc.SetAtCFAPlusOffset(-4);
2250   row_sp->SetRegisterInfo(k_eip, regloc);
2251 
2252   unwind_plan.AppendRow(row_sp);
2253 
2254   // Allocate a new Row, populate it with the existing Row contents.
2255   UnwindPlan::Row *new_row = new UnwindPlan::Row;
2256   *new_row = *row_sp.get();
2257   row_sp.reset(new_row);
2258 
2259   // Describe offset 1
2260   row_sp->SetOffset(1);
2261   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 8);
2262   regloc.SetAtCFAPlusOffset(-8);
2263   row_sp->SetRegisterInfo(k_ebp, regloc);
2264   unwind_plan.AppendRow(row_sp);
2265 
2266   // Allocate a new Row, populate it with the existing Row contents.
2267   new_row = new UnwindPlan::Row;
2268   *new_row = *row_sp.get();
2269   row_sp.reset(new_row);
2270 
2271   // Describe offset 3
2272   row_sp->SetOffset(3);
2273   row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_ebp, 8);
2274   unwind_plan.AppendRow(row_sp);
2275 
2276   RegisterContextSP reg_ctx_sp;
2277   EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite(
2278       data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2279 
2280   row_sp = unwind_plan.GetRowForFunctionOffset(5);
2281   EXPECT_EQ(5ull, row_sp->GetOffset());
2282   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2283   EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2284 
2285   // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2286   // doesn't track register restores (pop'ing a reg value back from
2287   // the stack) - it was just written to make stepping work correctly.
2288   // Technically we should be able to do the following test, but it
2289   // won't work today - the unwind plan will still say that the caller's
2290   // ebp is on the stack.
2291   // EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2292 }
2293 
2294 // Check that the i386 disassembler disassembles past an opcode that
2295 // is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler
2296 // stops
2297 // disassembling at that point (long-mode).
2298 TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {
2299   UnwindPlan::Row::RegisterLocation regloc;
2300   UnwindPlan::RowSP row_sp;
2301   AddressRange sample_range;
2302   UnwindPlan unwind_plan(eRegisterKindLLDB);
2303   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2304   std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2305 
2306   uint8_t data[] = {
2307       0x43, // incl $ebx --- an invalid opcode in 64-bit mode
2308       0x55, // pushl %ebp
2309       0x90  // nop
2310   };
2311 
2312   sample_range = AddressRange(0x1000, sizeof(data));
2313 
2314   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2315       data, sizeof(data), sample_range, unwind_plan));
2316 
2317   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2318   EXPECT_EQ(2ull, row_sp->GetOffset());
2319   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2320   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2321   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2322 
2323   EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
2324   EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2325   EXPECT_EQ(-8, regloc.GetOffset());
2326 
2327   unwind_plan.Clear();
2328 
2329   EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2330       data, sizeof(data), sample_range, unwind_plan));
2331 
2332   row_sp = unwind_plan.GetRowForFunctionOffset(2);
2333   EXPECT_EQ(0ull, row_sp->GetOffset());
2334   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2335   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2336   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2337 
2338   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2339 }
2340