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