blob: e216d4be16fd73162ea92f7c3b4fd3758cab63a0 [file] [log] [blame]
Jason Molenda74b8fbc2016-09-29 01:00:16 +00001//===-- 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
24using namespace lldb;
25using namespace lldb_private;
26
27class Testx86AssemblyInspectionEngine : public testing::Test {
28public:
Jason Molenda075605c2016-10-12 02:46:22 +000029 static void SetUpTestCase();
Jason Molenda74b8fbc2016-09-29 01:00:16 +000030
31 // static void TearDownTestCase() { }
32
33 // virtual void SetUp() override { }
34
35 // virtual void TearDown() override { }
36
37protected:
38};
39
Jason Molenda075605c2016-10-12 02:46:22 +000040void Testx86AssemblyInspectionEngine::SetUpTestCase() {
41 llvm::InitializeAllTargets();
42 llvm::InitializeAllAsmPrinters();
43 llvm::InitializeAllTargetMCs();
44 llvm::InitializeAllDisassemblers();
45}
46
Jason Molenda74b8fbc2016-09-29 01:00:16 +000047// 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
Jason Molenda415f7322016-09-29 04:01:43 +000053const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",
54 "rsi", "rdi", "r8", "r9", "r10", "r11",
55 "r12", "r13", "r14", "r15", "rip"};
Jason Molenda74b8fbc2016-09-29 01:00:16 +000056
57enum x86_64_regs {
58 k_rax = 0,
Jason Molenda415f7322016-09-29 04:01:43 +000059 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
Jason Molenda74b8fbc2016-09-29 01:00:16 +000075};
76
77// names should match the constants below. These will be the eRegisterKindLLDB
78// register numbers.
79
80const char *i386_reg_names[] = {"eax", "ecx", "edx", "ebx", "esp",
81 "ebp", "esi", "edi", "eip"};
82
83enum 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
95std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {
96
97 ArchSpec arch("x86_64-apple-macosx", nullptr);
Jason Molenda74b8fbc2016-09-29 01:00:16 +000098 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
114std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {
115
116 ArchSpec arch("i386-apple-macosx", nullptr);
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000117 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
133TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
134 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
135
Jason Molenda415f7322016-09-29 04:01:43 +0000136 // 'int main() { }' compiled for x86_64-apple-macosx with clang
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000137 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000166 EXPECT_EQ(0ull, row_sp->GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000167 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
168 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000169 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000170
171 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
172 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000173 EXPECT_EQ(-8, regloc.GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000174
175 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
176 row_sp = unwind_plan.GetRowForFunctionOffset(1);
Justin Bognerb69c3162016-10-17 18:22:03 +0000177 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000178 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
179 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000180 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000181
182 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
183 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000184 EXPECT_EQ(-8, regloc.GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000185
186 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
187 row_sp = unwind_plan.GetRowForFunctionOffset(4);
Justin Bognerb69c3162016-10-17 18:22:03 +0000188 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000189 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
190 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000191 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000192
193 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
194 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000195 EXPECT_EQ(-8, regloc.GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000196
197 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
198 row_sp = unwind_plan.GetRowForFunctionOffset(7);
Justin Bognerb69c3162016-10-17 18:22:03 +0000199 EXPECT_EQ(7ull, row_sp->GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000200 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
201 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000202 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000203
204 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
205 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000206 EXPECT_EQ(-8, regloc.GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000207}
208
209TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) {
210 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
211
Jason Molenda415f7322016-09-29 04:01:43 +0000212 // 'int main() { }' compiled for i386-apple-macosx with clang
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000213 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000242 EXPECT_EQ(0ull, row_sp->GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000243 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
244 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000245 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000246
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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000253 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000254 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
255 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000256 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000257
258 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
259 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000260 EXPECT_EQ(-4, regloc.GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000261
262 // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
263 row_sp = unwind_plan.GetRowForFunctionOffset(3);
Justin Bognerb69c3162016-10-17 18:22:03 +0000264 EXPECT_EQ(3ull, row_sp->GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000265 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
266 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000267 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000268
269 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
270 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000271 EXPECT_EQ(-4, regloc.GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000272
273 // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
274 row_sp = unwind_plan.GetRowForFunctionOffset(6);
Justin Bognerb69c3162016-10-17 18:22:03 +0000275 EXPECT_EQ(6ull, row_sp->GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000276 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
277 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000278 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000279
280 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
281 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000282 EXPECT_EQ(-4, regloc.GetOffset());
Jason Molenda74b8fbc2016-09-29 01:00:16 +0000283}
Jason Molenda415f7322016-09-29 04:01:43 +0000284
285TEST_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
Jason Molendaf96c13d2016-09-29 23:57:33 +0000339 0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever
Jason Molenda415f7322016-09-29 04:01:43 +0000340 };
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
Justin Bognerb69c3162016-10-17 18:22:03 +0000383 EXPECT_EQ(17ull, row_sp->GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000384 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
385 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000386 EXPECT_EQ(14496, row_sp->GetCFAValue().GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000387
388 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
389 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000390 EXPECT_EQ(-8, regloc.GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000391
392 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
393 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000394 EXPECT_EQ(-16, regloc.GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000395
396 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
397 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000398 EXPECT_EQ(-24, regloc.GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000399
400 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
401 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000402 EXPECT_EQ(-32, regloc.GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000403
404 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
405 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000406 EXPECT_EQ(-40, regloc.GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000407
408 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
409 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000410 EXPECT_EQ(-48, regloc.GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000411
412 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
413 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000414 EXPECT_EQ(-56, regloc.GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000415
Jason Molendaf96c13d2016-09-29 23:57:33 +0000416 // grab the Row for when the epilogue has finished executing:
Jason Molenda415f7322016-09-29 04:01:43 +0000417 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
418
419 row_sp = unwind_plan.GetRowForFunctionOffset(34);
420
Justin Bognerb69c3162016-10-17 18:22:03 +0000421 EXPECT_EQ(34ull, row_sp->GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000422 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
423 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
Jason Molendaf96c13d2016-09-29 23:57:33 +0000424 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000425
426 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
427 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
Jason Molendaf96c13d2016-09-29 23:57:33 +0000428 EXPECT_EQ(-8, regloc.GetOffset());
Jason Molenda415f7322016-09-29 04:01:43 +0000429
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.
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000433
434 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
Jason Molendaf96c13d2016-09-29 23:57:33 +0000435 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000436 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));
Jason Molenda415f7322016-09-29 04:01:43 +0000449}
Jason Molendaf96c13d2016-09-29 23:57:33 +0000450
Jason Molendac0657a62016-10-01 00:19:26 +0000451TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000652 EXPECT_EQ(10ull, row_sp->GetOffset());
Jason Molendac0657a62016-10-01 00:19:26 +0000653 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000660 EXPECT_EQ(15ull, row_sp->GetOffset());
Jason Molendac0657a62016-10-01 00:19:26 +0000661 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000666 EXPECT_EQ(16ull, row_sp->GetOffset());
Jason Molendac0657a62016-10-01 00:19:26 +0000667 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000697 EXPECT_EQ(23ull, row_sp->GetOffset());
Jason Molendac0657a62016-10-01 00:19:26 +0000698 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000705 EXPECT_EQ(24ull, row_sp->GetOffset());
Jason Molendac0657a62016-10-01 00:19:26 +0000706 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000711 EXPECT_EQ(28ull, row_sp->GetOffset());
Jason Molendac0657a62016-10-01 00:19:26 +0000712 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000717 EXPECT_EQ(36ull, row_sp->GetOffset());
Jason Molendac0657a62016-10-01 00:19:26 +0000718 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000724 EXPECT_EQ(47ull, row_sp->GetOffset());
Jason Molendac0657a62016-10-01 00:19:26 +0000725 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}
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000747
748TEST_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[] = {
Jason Molendac0657a62016-10-01 00:19:26 +0000760 0x50,
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000761 // offset 0 -- pushq %rax
762
Jason Molendac0657a62016-10-01 00:19:26 +0000763 0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00,
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000764 // offset 1 -- leaq 0x32(%rip), %rdi ; "HI"
765
Jason Molendac0657a62016-10-01 00:19:26 +0000766 0xe8, 0x0b, 0x00, 0x00, 0x00,
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000767 // offset 8 -- callq 0x100000f58 ; puts
768
769 0x31, 0xc9,
770 // offset 13 -- xorl %ecx, %ecx
Jason Molendac0657a62016-10-01 00:19:26 +0000771
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000772 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
Jason Molendac0657a62016-10-01 00:19:26 +0000792 // 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]
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000795
796 UnwindPlan::Row::RegisterLocation regloc;
797
798 // grab the Row for when the prologue has finished executing:
Jason Molendac0657a62016-10-01 00:19:26 +0000799 // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000800
801 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(13);
802
Justin Bognerb69c3162016-10-17 18:22:03 +0000803 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000804 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
Justin Bognerb69c3162016-10-17 18:22:03 +0000835 EXPECT_EQ(22ull, row_sp->GetOffset());
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000836 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
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000845TEST_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
Jason Molendac0657a62016-10-01 00:19:26 +0000859
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000860 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
Jason Molendac0657a62016-10-01 00:19:26 +0000899 // 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]
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000904
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
Justin Bognerb69c3162016-10-17 18:22:03 +0000912 EXPECT_EQ(3ull, row_sp->GetOffset());
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000913 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);
Justin Bognerb69c3162016-10-17 18:22:03 +0000921 EXPECT_EQ(8ull, row_sp->GetOffset());
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000922 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
Jason Molendac0657a62016-10-01 00:19:26 +0000927 // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000928
929 row_sp = unwind_plan.GetRowForFunctionOffset(9);
Justin Bognerb69c3162016-10-17 18:22:03 +0000930 EXPECT_EQ(9ull, row_sp->GetOffset());
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000931 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
Jason Molendac0657a62016-10-01 00:19:26 +0000946 // 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000947
948 row_sp = unwind_plan.GetRowForFunctionOffset(34);
Justin Bognerb69c3162016-10-17 18:22:03 +0000949 EXPECT_EQ(34ull, row_sp->GetOffset());
Jason Molenda7b10b1d2016-09-30 00:41:15 +0000950 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}
Jason Molenda56f04972016-10-01 04:50:25 +0000954
955TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
956 UnwindPlan::Row::RegisterLocation regloc;
957 UnwindPlan::RowSP row_sp;
958
959 uint8_t data[] = {
Jason Molendad99f9472016-10-05 22:37:01 +0000960 0x55, // pushq %rbp
Jason Molenda56f04972016-10-01 04:50:25 +0000961 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
Justin Bognerb69c3162016-10-17 18:22:03 +0000973 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +0000974 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
Justin Bognerb69c3162016-10-17 18:22:03 +0000988 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +0000989 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
998TEST_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
Jason Molenda2630acc2016-10-04 05:10:06 +00001004 0x6a, 0x7d, // pushl $0x7d
Jason Molenda56f04972016-10-01 04:50:25 +00001005 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001016 EXPECT_EQ(5ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001017 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
Jason Molenda2630acc2016-10-04 05:10:06 +00001021 row_sp = unwind_plan.GetRowForFunctionOffset(7);
Justin Bognerb69c3162016-10-17 18:22:03 +00001022 EXPECT_EQ(7ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001023 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
Jason Molenda56f04972016-10-01 04:50:25 +00001027 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001032 EXPECT_EQ(5ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001033 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1034 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1035 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001036
1037 row_sp = unwind_plan.GetRowForFunctionOffset(7);
Justin Bognerb69c3162016-10-17 18:22:03 +00001038 EXPECT_EQ(7ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001039 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1040 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1041 EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001042}
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.
1047TEST_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'
Justin Bognerb69c3162016-10-17 18:22:03 +00001066 EXPECT_EQ(0ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001067
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'
Justin Bognerb69c3162016-10-17 18:22:03 +00001075 EXPECT_EQ(0ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001076}
1077
1078TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
1079 UnwindPlan::Row::RegisterLocation regloc;
1080 UnwindPlan::RowSP row_sp;
1081
1082 uint8_t data[] = {
Jason Molenda2630acc2016-10-04 05:10:06 +00001083 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
Jason Molenda56f04972016-10-01 04:50:25 +00001087 };
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
Justin Bognerb69c3162016-10-17 18:22:03 +00001098 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001099 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001108 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001109 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1110 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1111 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001112
1113 row_sp = unwind_plan.GetRowForFunctionOffset(10);
Justin Bognerb69c3162016-10-17 18:22:03 +00001114 EXPECT_EQ(10ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001115 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001120 EXPECT_EQ(12ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001121 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1122 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1123 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001124}
1125
1126TEST_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
Justin Bognerb69c3162016-10-17 18:22:03 +00001144 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001145 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
1154TEST_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
Justin Bognerb69c3162016-10-17 18:22:03 +00001172 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001173 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
1182TEST_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
Justin Bognerb69c3162016-10-17 18:22:03 +00001200 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001201 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
1210TEST_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
Justin Bognerb69c3162016-10-17 18:22:03 +00001228 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001229 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
1238TEST_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
Justin Bognerb69c3162016-10-17 18:22:03 +00001256 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001257 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
Jason Molenda2630acc2016-10-04 05:10:06 +00001266// 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)
1269TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001287 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001288 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)
1298TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001316 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001317 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)
1327TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001345 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001346 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
1353TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001371 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001372 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
1381TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001399 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001400 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
1409TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001427 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001428 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
1437TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001455 EXPECT_EQ(1ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001456 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
Jason Molenda56f04972016-10-01 04:50:25 +00001465TEST_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
Justin Bognerb69c3162016-10-17 18:22:03 +00001483 EXPECT_EQ(3ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001484 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001499 EXPECT_EQ(3ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001500 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001515 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001516 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001531 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001532 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
1537TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001555 EXPECT_EQ(7ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001556 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001571 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001572 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
1577TEST_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[] = {
Jason Molendad99f9472016-10-05 22:37:01 +00001585 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp
Jason Molenda56f04972016-10-01 04:50:25 +00001586 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001595 EXPECT_EQ(6ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001596 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001611 EXPECT_EQ(3ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001612 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
1617TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001635 EXPECT_EQ(7ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001636 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001651 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001652 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
1657TEST_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[] = {
Jason Molenda2630acc2016-10-04 05:10:06 +00001665 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
Jason Molenda56f04972016-10-01 04:50:25 +00001666 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001675 EXPECT_EQ(6ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001676 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001691 EXPECT_EQ(3ull, row_sp->GetOffset());
Jason Molenda56f04972016-10-01 04:50:25 +00001692 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}
Jason Molenda2630acc2016-10-04 05:10:06 +00001696
1697// FIXME add test for lea_rsp_pattern_p
1698
1699TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001718 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001719 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
1725TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001744 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001745 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
1751TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001770 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001771 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
1777TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001796 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001797 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
1803TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001822 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001823 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
1829TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001848 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001849 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
1855TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001874 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001875 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
1881TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001900 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001901 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
1907TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001926 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001927 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
1933TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001952 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001953 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.
1961TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001987 EXPECT_EQ(4ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001988 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00001993 EXPECT_EQ(7ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00001994 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
1999TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002019 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00002020 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002029 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00002030 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).
2040TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002058 EXPECT_EQ(5ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00002059 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
2065TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002087 EXPECT_EQ(19ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00002088 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
2104TEST_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[] = {
Jason Molendad99f9472016-10-05 22:37:01 +00002112 0x55, // pushl %ebp
2113 0x89, 0xe5, // movl %esp, %ebp
Jason Molenda2630acc2016-10-04 05:10:06 +00002114 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
2115 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp)
Jason Molendad99f9472016-10-05 22:37:01 +00002116 0x90 // nop
Jason Molenda2630acc2016-10-04 05:10:06 +00002117 };
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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002125 EXPECT_EQ(12ull, row_sp->GetOffset());
Jason Molenda2630acc2016-10-04 05:10:06 +00002126 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}
Jason Molendad99f9472016-10-05 22:37:01 +00002137
2138TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002203 EXPECT_EQ(6ull, row_sp->GetOffset());
Jason Molendad99f9472016-10-05 22:37:01 +00002204 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
2216TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002281 EXPECT_EQ(5ull, row_sp->GetOffset());
Jason Molendad99f9472016-10-05 22:37:01 +00002282 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).
2298TEST_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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002318 EXPECT_EQ(2ull, row_sp->GetOffset());
Jason Molendad99f9472016-10-05 22:37:01 +00002319 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);
Justin Bognerb69c3162016-10-17 18:22:03 +00002333 EXPECT_EQ(0ull, row_sp->GetOffset());
Jason Molendad99f9472016-10-05 22:37:01 +00002334 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}