[AArch64,ELF] Restrict MOVZ/MOVK to non-PIC large code model (#70178)
[llvm-project.git] / lldb / unittests / UnwindAssembly / x86 / Testx86AssemblyInspectionEngine.cpp
blob277cc14ce50c9fa7a47bb1b92ca440fcd7ea5d06
1 //===-- Testx86AssemblyInspectionEngine.cpp -------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
10 #include "gtest/gtest.h"
12 #include <memory>
13 #include <vector>
15 #include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h"
16 #include "lldb/Core/Address.h"
17 #include "lldb/Core/AddressRange.h"
18 #include "lldb/Symbol/UnwindPlan.h"
19 #include "lldb/Utility/ArchSpec.h"
20 #include "lldb/Utility/StreamString.h"
22 #include "llvm/Support/TargetSelect.h"
24 using namespace lldb;
25 using namespace lldb_private;
27 class Testx86AssemblyInspectionEngine : public testing::Test {
28 public:
29 static void SetUpTestCase();
31 // static void TearDownTestCase() { }
33 // virtual void SetUp() override { }
35 // virtual void TearDown() override { }
37 protected:
40 void Testx86AssemblyInspectionEngine::SetUpTestCase() {
41 llvm::InitializeAllTargets();
42 llvm::InitializeAllAsmPrinters();
43 llvm::InitializeAllTargetMCs();
44 llvm::InitializeAllDisassemblers();
47 // only defining the register names / numbers that the unwinder is actually
48 // using today
50 // names should match the constants below. These will be the eRegisterKindLLDB
51 // register numbers.
53 const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",
54 "rsi", "rdi", "r8", "r9", "r10", "r11",
55 "r12", "r13", "r14", "r15", "rip"};
57 enum x86_64_regs {
58 k_rax = 0,
59 k_rbx = 1,
60 k_rcx = 2,
61 k_rdx = 3,
62 k_rsp = 4,
63 k_rbp = 5,
64 k_rsi = 6,
65 k_rdi = 7,
66 k_r8 = 8,
67 k_r9 = 9,
68 k_r10 = 10,
69 k_r11 = 11,
70 k_r12 = 12,
71 k_r13 = 13,
72 k_r14 = 14,
73 k_r15 = 15,
74 k_rip = 16
77 // names should match the constants below. These will be the eRegisterKindLLDB
78 // register numbers.
80 const char *i386_reg_names[] = {"eax", "ecx", "edx", "ebx", "esp",
81 "ebp", "esi", "edi", "eip"};
83 enum i386_regs {
84 k_eax = 0,
85 k_ecx = 1,
86 k_edx = 2,
87 k_ebx = 3,
88 k_esp = 4,
89 k_ebp = 5,
90 k_esi = 6,
91 k_edi = 7,
92 k_eip = 8
95 std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {
97 ArchSpec arch("x86_64-apple-macosx");
98 std::unique_ptr<x86AssemblyInspectionEngine> engine(
99 new x86AssemblyInspectionEngine(arch));
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);
110 engine->Initialize(lldb_regnums);
111 return engine;
114 std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {
116 ArchSpec arch("i386-apple-macosx");
117 std::unique_ptr<x86AssemblyInspectionEngine> engine(
118 new x86AssemblyInspectionEngine(arch));
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);
129 engine->Initialize(lldb_regnums);
130 return engine;
133 namespace lldb_private {
134 static std::ostream &operator<<(std::ostream &OS,
135 const UnwindPlan::Row::FAValue &CFA) {
136 StreamString S;
137 CFA.Dump(S, nullptr, nullptr);
138 return OS << S.GetData();
140 } // namespace lldb_private
142 TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
143 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
145 // 'int main() { }' compiled for x86_64-apple-macosx with clang
146 uint8_t data[] = {
147 0x55, // offset 0 -- pushq %rbp
148 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
149 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
150 0x5d, // offset 6 -- popq %rbp
151 0xc3 // offset 7 -- retq
154 AddressRange sample_range(0x1000, sizeof(data));
156 UnwindPlan unwind_plan(eRegisterKindLLDB);
157 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
158 data, sizeof(data), sample_range, unwind_plan));
160 // Expect four unwind rows:
161 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
162 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
163 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
164 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
166 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
167 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
168 eLazyBoolYes);
169 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
171 UnwindPlan::Row::RegisterLocation regloc;
173 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
174 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
175 EXPECT_EQ(0ull, row_sp->GetOffset());
176 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
177 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
178 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
180 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
181 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
182 EXPECT_EQ(-8, regloc.GetOffset());
184 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
185 row_sp = unwind_plan.GetRowForFunctionOffset(1);
186 EXPECT_EQ(1ull, row_sp->GetOffset());
187 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
188 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
189 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
191 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
192 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
193 EXPECT_EQ(-8, regloc.GetOffset());
195 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
196 row_sp = unwind_plan.GetRowForFunctionOffset(4);
197 EXPECT_EQ(4ull, row_sp->GetOffset());
198 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
199 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
200 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
202 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
203 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
204 EXPECT_EQ(-8, regloc.GetOffset());
206 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
207 row_sp = unwind_plan.GetRowForFunctionOffset(7);
208 EXPECT_EQ(7ull, row_sp->GetOffset());
209 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
210 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
211 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
213 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
214 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
215 EXPECT_EQ(-8, regloc.GetOffset());
218 TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) {
219 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
221 // 'int main() { }' compiled for i386-apple-macosx with clang
222 uint8_t data[] = {
223 0x55, // offset 0 -- pushl %ebp
224 0x89, 0xe5, // offset 1 -- movl %esp, %ebp
225 0x31, 0xc0, // offset 3 -- xorl %eax, %eax
226 0x5d, // offset 5 -- popl %ebp
227 0xc3 // offset 6 -- retl
230 AddressRange sample_range(0x1000, sizeof(data));
232 UnwindPlan unwind_plan(eRegisterKindLLDB);
233 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
234 data, sizeof(data), sample_range, unwind_plan));
236 // Expect four unwind rows:
237 // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
238 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
239 // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
240 // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
242 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_esp);
243 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
244 eLazyBoolYes);
245 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
247 UnwindPlan::Row::RegisterLocation regloc;
249 // offset 0 -- pushl %ebp
250 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
251 EXPECT_EQ(0ull, row_sp->GetOffset());
252 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
253 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
254 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
256 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
257 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
258 EXPECT_TRUE(regloc.GetOffset() == -4);
260 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
261 row_sp = unwind_plan.GetRowForFunctionOffset(1);
262 EXPECT_EQ(1ull, row_sp->GetOffset());
263 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
264 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
265 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
267 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
268 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
269 EXPECT_EQ(-4, regloc.GetOffset());
271 // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
272 row_sp = unwind_plan.GetRowForFunctionOffset(3);
273 EXPECT_EQ(3ull, row_sp->GetOffset());
274 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
275 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
276 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
278 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
279 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
280 EXPECT_EQ(-4, regloc.GetOffset());
282 // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
283 row_sp = unwind_plan.GetRowForFunctionOffset(6);
284 EXPECT_EQ(6ull, row_sp->GetOffset());
285 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
286 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
287 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
289 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
290 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
291 EXPECT_EQ(-4, regloc.GetOffset());
294 TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) {
295 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
297 // this source file:
299 // #include <stdio.h>
300 // int main (int argc, char **argv)
301 // {
303 // const int arrsize = 60;
304 // int buf[arrsize * arrsize];
305 // int accum = argc;
306 // for (int i = 0; i < arrsize; i++)
307 // for (int j = 0; j < arrsize; j++)
308 // {
309 // if (i > 0 && j > 0)
310 // {
311 // int n = buf[(i-1) * (j-1)] * 2;
312 // int m = buf[(i-1) * (j-1)] / 2;
313 // int j = buf[(i-1) * (j-1)] + 2;
314 // int k = buf[(i-1) * (j-1)] - 2;
315 // printf ("%d ", n + m + j + k);
316 // buf[(i-1) * (j-1)] += n - m + j - k;
317 // }
318 // buf[i*j] = accum++;
319 // }
321 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
322 // arrsize) - 3]);
323 // }
325 // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx
327 uint8_t data[] = {
328 0x55, // offset 0 -- pushq %rbp
329 0x41, 0x57, // offset 1 -- pushq %r15
330 0x41, 0x56, // offset 3 -- pushq %r14
331 0x41, 0x55, // offset 5 -- pushq %r13
332 0x41, 0x54, // offset 7 -- pushq %r12
333 0x53, // offset 9 -- pushq %rbx
334 0x48, 0x81, 0xec, 0x68, 0x38, 0x00,
335 0x00, // offset 10 -- subq $0x3868, %rsp
337 // ....
339 0x48, 0x81, 0xc4, 0x68, 0x38, 0x00,
340 0x00, // offset 17 -- addq $0x3868, %rsp
341 0x5b, // offset 24 -- popq %rbx
342 0x41, 0x5c, // offset 25 -- popq %r12
343 0x41, 0x5d, // offset 27 -- popq %r13
344 0x41, 0x5e, // offset 29 -- popq %r14
345 0x41, 0x5f, // offset 31 -- popq %r15
346 0x5d, // offset 33 -- popq %rbp
347 0xc3, // offset 34 -- retq
348 0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever
351 AddressRange sample_range(0x1000, sizeof(data));
353 UnwindPlan unwind_plan(eRegisterKindLLDB);
354 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
355 data, sizeof(data), sample_range, unwind_plan));
357 // Unwind rules should look like
358 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
359 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
360 // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
361 // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
362 // rip=[CFA-8
363 // 7: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
364 // r15=[CFA-24] rip=[CFA-8]
365 // 9: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
366 // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
367 // 10: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
368 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
369 // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
370 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
372 // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
373 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
374 // 25: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
375 // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
376 // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
377 // r15=[CFA-24] rip=[CFA-8]
378 // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
379 // rip=[CFA-8]
380 // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
381 // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
382 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
384 UnwindPlan::Row::RegisterLocation regloc;
386 // grab the Row for when the prologue has finished executing:
387 // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
388 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
390 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(17);
392 EXPECT_EQ(17ull, row_sp->GetOffset());
393 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
394 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
395 EXPECT_EQ(14496, row_sp->GetCFAValue().GetOffset());
397 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
398 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
399 EXPECT_EQ(-8, regloc.GetOffset());
401 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
402 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
403 EXPECT_EQ(-16, regloc.GetOffset());
405 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
406 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
407 EXPECT_EQ(-24, regloc.GetOffset());
409 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
410 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
411 EXPECT_EQ(-32, regloc.GetOffset());
413 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
414 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
415 EXPECT_EQ(-40, regloc.GetOffset());
417 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
418 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
419 EXPECT_EQ(-48, regloc.GetOffset());
421 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
422 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
423 EXPECT_EQ(-56, regloc.GetOffset());
425 // grab the Row for when the epilogue has finished executing:
426 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
428 row_sp = unwind_plan.GetRowForFunctionOffset(34);
430 EXPECT_EQ(34ull, row_sp->GetOffset());
431 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
432 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
433 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
435 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
436 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
437 EXPECT_EQ(-8, regloc.GetOffset());
439 // these could be set to IsSame and be valid -- meaning that the
440 // register value is the same as the caller's -- but I'd rather
441 // they not be mentioned at all.
443 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
444 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
445 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
446 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
447 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
448 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
449 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
450 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
451 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
452 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
453 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
454 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
455 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
456 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
457 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
460 TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessBigStackFrame) {
461 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
463 // this source file:
465 // #include <stdio.h>
466 // int main (int argc, char **argv)
467 // {
469 // const int arrsize = 60;
470 // int buf[arrsize * arrsize];
471 // int accum = argc;
472 // for (int i = 0; i < arrsize; i++)
473 // for (int j = 0; j < arrsize; j++)
474 // {
475 // if (i > 0 && j > 0)
476 // {
477 // int n = buf[(i-1) * (j-1)] * 2;
478 // int m = buf[(i-1) * (j-1)] / 2;
479 // int j = buf[(i-1) * (j-1)] + 2;
480 // int k = buf[(i-1) * (j-1)] - 2;
481 // printf ("%d ", n + m + j + k);
482 // buf[(i-1) * (j-1)] += n - m + j - k;
483 // }
484 // buf[i*j] = accum++;
485 // }
487 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
488 // arrsize) - 3]);
489 // }
491 // compiled 'clang -arch i386 -fomit-frame-pointer -Os' for i386-apple-macosx
493 // simplified assembly version of the above function, which is used as the
494 // input
495 // data:
497 // .section __TEXT,__text,regular,pure_instructions
498 // .macosx_version_min 10, 12
499 // .globl _main
500 // .align 4, 0x90
501 // _main: ## @main
502 // ## BB#0:
503 // pushl %ebp
504 // pushl %ebx
505 // pushl %edi
506 // pushl %esi
507 // L0$pb:
508 // subl $0x386c, %esp
509 // calll L1
510 // L1:
511 // popl %ecx
512 // movl %ecx, 0x8(%esp)
513 // subl $0x8, %esp
514 // pushl %eax
515 // pushl 0x20(%esp)
516 // calll _puts
517 // addl $0x10, %esp
518 // incl %ebx
519 // addl $0x386c, %esp
520 // popl %esi
521 // popl %edi
522 // popl %ebx
523 // popl %ebp
524 // retl
526 // .section __TEXT,__cstring,cstring_literals
527 // L_.str: ## @.str
528 // .asciz "HI"
531 // .subsections_via_symbols
533 uint8_t data[] = {
534 0x55,
535 // offset 0 -- pushl %ebp
537 0x53,
538 // offset 1 -- pushl %ebx
540 0x57,
541 // offset 2 -- pushl %edi
543 0x56,
544 // offset 3 -- pushl %esi
546 0x81, 0xec, 0x6c, 0x38, 0x00, 0x00,
547 // offset 4 -- subl $0x386c, %esp
549 0xe8, 0x00, 0x00, 0x00, 0x00,
550 // offset 10 -- calll 0
551 // call the next instruction, to put the pc on the stack
553 0x59,
554 // offset 15 -- popl %ecx
555 // pop the saved pc address into ecx
557 0x89, 0x4c, 0x24, 0x08,
558 // offset 16 -- movl %ecx, 0x8(%esp)
560 // ....
562 0x83, 0xec, 0x08,
563 // offset 20 -- subl $0x8, %esp
565 0x50,
566 // offset 23 -- pushl %eax
568 0xff, 0x74, 0x24, 0x20,
569 // offset 24 -- pushl 0x20(%esp)
571 0xe8, 0x8c, 0x00, 0x00, 0x00,
572 // offset 28 -- calll puts
574 0x83, 0xc4, 0x10,
575 // offset 33 -- addl $0x10, %esp
576 // get esp back to the value it was before the
577 // alignment & argument saves for the puts call
579 0x43,
580 // offset 36 -- incl %ebx
582 // ....
584 0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00,
585 // offset 37 -- addl $0x386c, %esp
587 0x5e,
588 // offset 43 -- popl %esi
590 0x5f,
591 // offset 44 -- popl %edi
593 0x5b,
594 // offset 45 -- popl %ebx
596 0x5d,
597 // offset 46 -- popl %ebp
599 0xc3,
600 // offset 47 -- retl
602 0xe8, 0x12, 0x34, 0x56, 0x78,
603 // offset 48 -- calll __stack_chk_fail
606 AddressRange sample_range(0x1000, sizeof(data));
608 UnwindPlan unwind_plan(eRegisterKindLLDB);
609 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
610 data, sizeof(data), sample_range, unwind_plan));
612 // Unwind rules should look like
614 // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
615 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
616 // 2: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
617 // 3: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
618 // eip=[CFA-4]
619 // 4: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
620 // esp=CFA+0 eip=[CFA-4]
621 // 10: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
622 // esp=CFA+0 eip=[CFA-4]
623 // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
624 // esp=CFA+0 eip=[CFA-4]
625 // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
626 // esp=CFA+0 eip=[CFA-4]
628 // ....
630 // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
631 // esp=CFA+0 eip=[CFA-4]
632 // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
633 // esp=CFA+0 eip=[CFA-4]
634 // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
635 // esp=CFA+0 eip=[CFA-4]
636 // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
637 // esp=CFA+0 eip=[CFA-4]
639 // .....
641 // 37: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
642 // esp=CFA+0 eip=[CFA-4]
643 // 43: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
644 // esp=CFA+0 eip=[CFA-4]
645 // 44: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
646 // eip=[CFA-4]
647 // 45: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
648 // 46: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
649 // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
650 // 48: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
651 // esp=CFA+0 eip=[CFA-4]
653 UnwindPlan::Row::RegisterLocation regloc;
654 UnwindPlan::RowSP row_sp;
656 // Check that we get the CFA correct for the pic base setup sequence
658 // CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
659 // esp=CFA+0 eip=[CFA-4]
660 row_sp = unwind_plan.GetRowForFunctionOffset(10);
661 EXPECT_EQ(10ull, row_sp->GetOffset());
662 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
663 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
664 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
666 // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
667 // esp=CFA+0 eip=[CFA-4]
668 row_sp = unwind_plan.GetRowForFunctionOffset(15);
669 EXPECT_EQ(15ull, row_sp->GetOffset());
670 EXPECT_EQ(14468, row_sp->GetCFAValue().GetOffset());
672 // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
673 // esp=CFA+0 eip=[CFA-4]
674 row_sp = unwind_plan.GetRowForFunctionOffset(16);
675 EXPECT_EQ(16ull, row_sp->GetOffset());
676 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
678 // Check that the row for offset 16 has the registers saved that we expect
680 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
681 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
682 EXPECT_EQ(-4, regloc.GetOffset());
684 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
685 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
686 EXPECT_EQ(-8, regloc.GetOffset());
688 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
689 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
690 EXPECT_EQ(-12, regloc.GetOffset());
692 EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
693 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
694 EXPECT_EQ(-16, regloc.GetOffset());
696 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
697 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
698 EXPECT_EQ(-20, regloc.GetOffset());
701 // Check the pushing & popping around the call printf instruction
703 // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
704 // esp=CFA+0 eip=[CFA-4]
705 row_sp = unwind_plan.GetRowForFunctionOffset(23);
706 EXPECT_EQ(23ull, row_sp->GetOffset());
707 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
708 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
709 EXPECT_EQ(14472, row_sp->GetCFAValue().GetOffset());
711 // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
712 // esp=CFA+0 eip=[CFA-4]
713 row_sp = unwind_plan.GetRowForFunctionOffset(24);
714 EXPECT_EQ(24ull, row_sp->GetOffset());
715 EXPECT_EQ(14476, row_sp->GetCFAValue().GetOffset());
717 // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
718 // esp=CFA+0 eip=[CFA-4]
719 row_sp = unwind_plan.GetRowForFunctionOffset(28);
720 EXPECT_EQ(28ull, row_sp->GetOffset());
721 EXPECT_EQ(14480, row_sp->GetCFAValue().GetOffset());
723 // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
724 // esp=CFA+0 eip=[CFA-4]
725 row_sp = unwind_plan.GetRowForFunctionOffset(36);
726 EXPECT_EQ(36ull, row_sp->GetOffset());
727 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
729 // Check that the epilogue gets us back to the original unwind state
731 // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
732 row_sp = unwind_plan.GetRowForFunctionOffset(47);
733 EXPECT_EQ(47ull, row_sp->GetOffset());
734 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
735 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
736 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
738 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
739 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
740 EXPECT_EQ(-4, regloc.GetOffset());
742 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esp, regloc));
743 EXPECT_TRUE(regloc.IsCFAPlusOffset());
744 EXPECT_EQ(0, regloc.GetOffset());
746 // Check that no unexpected registers were saved
748 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
749 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
750 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
751 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
752 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
753 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
754 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
757 TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessSmallStackFrame) {
758 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
760 // this source file:
761 // #include <stdio.h>
762 // int main () {
763 // puts ("HI");
764 // }
766 // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx
768 uint8_t data[] = {
769 0x50,
770 // offset 0 -- pushq %rax
772 0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00,
773 // offset 1 -- leaq 0x32(%rip), %rdi ; "HI"
775 0xe8, 0x0b, 0x00, 0x00, 0x00,
776 // offset 8 -- callq 0x100000f58 ; puts
778 0x31, 0xc9,
779 // offset 13 -- xorl %ecx, %ecx
781 0x89, 0x44, 0x24, 0x04,
782 // offset 15 -- movl %eax, 0x4(%rsp)
784 0x89, 0xc8,
785 // offset 19 -- movl %ecx, %eax
787 0x59,
788 // offset 21 -- popq %rcx
790 0xc3
791 // offset 22 -- retq
794 AddressRange sample_range(0x1000, sizeof(data));
796 UnwindPlan unwind_plan(eRegisterKindLLDB);
797 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
798 data, sizeof(data), sample_range, unwind_plan));
800 // Unwind rules should look like
801 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
802 // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
803 // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
805 UnwindPlan::Row::RegisterLocation regloc;
807 // grab the Row for when the prologue has finished executing:
808 // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
810 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(13);
812 EXPECT_EQ(1ull, row_sp->GetOffset());
813 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
814 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
815 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
817 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
818 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
819 EXPECT_EQ(-8, regloc.GetOffset());
821 // none of these were spilled
823 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
824 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
825 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
826 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
827 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
828 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
829 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
830 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
831 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
832 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
833 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
834 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
835 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
836 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
837 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
839 // grab the Row for when the epilogue has finished executing:
840 // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
842 row_sp = unwind_plan.GetRowForFunctionOffset(22);
844 EXPECT_EQ(22ull, row_sp->GetOffset());
845 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
846 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
847 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
849 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
850 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
851 EXPECT_EQ(-8, regloc.GetOffset());
854 TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) {
855 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
857 // this source file:
858 // #include <stdio.h>
859 // int main () {
860 // puts ("HI");
861 // }
863 // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx
865 uint8_t data[] = {
866 0x83, 0xec, 0x0c,
867 // offset 0 -- subl $0xc, %esp
869 0xe8, 0x00, 0x00, 0x00, 0x00,
870 // offset 3 -- calll 0 {call the next instruction, to put the pc on
871 // the stack}
873 0x58,
874 // offset 8 -- popl %eax {pop the saved pc value off stack, into eax}
876 0x8d, 0x80, 0x3a, 0x00, 0x00, 0x00,
877 // offset 9 -- leal 0x3a(%eax),%eax
879 0x89, 0x04, 0x24,
880 // offset 15 -- movl %eax, (%esp)
882 0xe8, 0x0d, 0x00, 0x00, 0x00,
883 // offset 18 -- calll 0x1f94 (puts)
885 0x31, 0xc9,
886 // offset 23 -- xorl %ecx, %ecx
888 0x89, 0x44, 0x24, 0x08,
889 // offset 25 -- movl %eax, 0x8(%esp)
891 0x89, 0xc8,
892 // offset 29 -- movl %ecx, %eax
894 0x83, 0xc4, 0x0c,
895 // offset 31 -- addl $0xc, %esp
897 0xc3
898 // offset 34 -- retl
901 AddressRange sample_range(0x1000, sizeof(data));
903 UnwindPlan unwind_plan(eRegisterKindLLDB);
904 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
905 data, sizeof(data), sample_range, unwind_plan));
907 // Unwind rules should look like
908 // row[0]: 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
909 // row[1]: 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
910 // row[2]: 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
911 // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
912 // row[4]: 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
914 UnwindPlan::Row::RegisterLocation regloc;
916 // Check unwind state before we set up the picbase register
917 // 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
919 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(3);
921 EXPECT_EQ(3ull, row_sp->GetOffset());
922 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
923 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
924 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
926 // Check unwind state after we call the next instruction
927 // 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
929 row_sp = unwind_plan.GetRowForFunctionOffset(8);
930 EXPECT_EQ(8ull, row_sp->GetOffset());
931 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
932 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
933 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
935 // Check unwind state after we pop the pic base value off the stack
936 // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
938 row_sp = unwind_plan.GetRowForFunctionOffset(9);
939 EXPECT_EQ(9ull, row_sp->GetOffset());
940 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
941 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
942 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
944 // Check that no unexpected registers were saved
946 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
947 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
948 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
949 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
950 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
951 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
952 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
954 // verify that we get back to the original unwind state before the ret
955 // 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
957 row_sp = unwind_plan.GetRowForFunctionOffset(34);
958 EXPECT_EQ(34ull, row_sp->GetOffset());
959 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
960 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
961 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
964 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
965 UnwindPlan::Row::RegisterLocation regloc;
966 UnwindPlan::RowSP row_sp;
968 uint8_t data[] = {
969 0x55, // pushq %rbp
970 0x90 // nop
973 AddressRange sample_range(0x1000, sizeof(data));
974 UnwindPlan unwind_plan(eRegisterKindLLDB);
976 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
977 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
978 data, sizeof(data), sample_range, unwind_plan));
980 row_sp = unwind_plan.GetRowForFunctionOffset(1);
982 EXPECT_EQ(1ull, row_sp->GetOffset());
983 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
984 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
985 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
987 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
988 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
989 EXPECT_EQ(-16, regloc.GetOffset());
991 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
992 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
993 data, sizeof(data), sample_range, unwind_plan));
995 row_sp = unwind_plan.GetRowForFunctionOffset(1);
997 EXPECT_EQ(1ull, row_sp->GetOffset());
998 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
999 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1000 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1002 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
1003 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1004 EXPECT_EQ(-8, regloc.GetOffset());
1007 TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
1008 UnwindPlan::Row::RegisterLocation regloc;
1009 UnwindPlan::RowSP row_sp;
1011 uint8_t data[] = {
1012 0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
1013 0x6a, 0x7d, // pushl $0x7d
1014 0x90 // nop
1017 AddressRange sample_range(0x1000, sizeof(data));
1018 UnwindPlan unwind_plan(eRegisterKindLLDB);
1020 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1021 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1022 data, sizeof(data), sample_range, unwind_plan));
1024 row_sp = unwind_plan.GetRowForFunctionOffset(5);
1025 EXPECT_EQ(5ull, row_sp->GetOffset());
1026 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1027 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1028 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1030 row_sp = unwind_plan.GetRowForFunctionOffset(7);
1031 EXPECT_EQ(7ull, row_sp->GetOffset());
1032 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1033 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1034 EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
1036 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1037 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1038 data, sizeof(data), sample_range, unwind_plan));
1040 row_sp = unwind_plan.GetRowForFunctionOffset(5);
1041 EXPECT_EQ(5ull, row_sp->GetOffset());
1042 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1043 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1044 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1046 row_sp = unwind_plan.GetRowForFunctionOffset(7);
1047 EXPECT_EQ(7ull, row_sp->GetOffset());
1048 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1049 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1050 EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
1053 // We treat 'pushq $0' / 'pushl $0' specially - this shows up
1054 // in the first function called in a new thread and it needs to
1055 // put a 0 as the saved pc. We pretend it didn't change the CFA.
1056 TEST_F(Testx86AssemblyInspectionEngine, TestPush0) {
1057 UnwindPlan::Row::RegisterLocation regloc;
1058 UnwindPlan::RowSP row_sp;
1060 uint8_t data[] = {
1061 0x6a, 0x00, // pushq $0
1062 0x90 // nop
1065 AddressRange sample_range(0x1000, sizeof(data));
1066 UnwindPlan unwind_plan(eRegisterKindLLDB);
1068 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1069 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1070 data, sizeof(data), sample_range, unwind_plan));
1072 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1074 // We're verifying that no row was created for the 'pushq $0'
1075 EXPECT_EQ(0ull, row_sp->GetOffset());
1077 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1078 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1079 data, sizeof(data), sample_range, unwind_plan));
1081 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1083 // We're verifying that no row was created for the 'pushq $0'
1084 EXPECT_EQ(0ull, row_sp->GetOffset());
1087 TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
1088 UnwindPlan::Row::RegisterLocation regloc;
1089 UnwindPlan::RowSP row_sp;
1091 uint8_t data[] = {
1092 0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp)
1093 0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl 0xf001ce(%esi)
1094 0xff, 0x30, // pushl (%eax)
1095 0x90 // nop
1098 AddressRange sample_range(0x1000, sizeof(data));
1099 UnwindPlan unwind_plan(eRegisterKindLLDB);
1101 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1102 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1103 data, sizeof(data), sample_range, unwind_plan));
1105 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1107 EXPECT_EQ(4ull, row_sp->GetOffset());
1108 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1109 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1110 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1112 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1113 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1114 data, sizeof(data), sample_range, unwind_plan));
1116 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1117 EXPECT_EQ(4ull, row_sp->GetOffset());
1118 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1119 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1120 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1122 row_sp = unwind_plan.GetRowForFunctionOffset(10);
1123 EXPECT_EQ(10ull, row_sp->GetOffset());
1124 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1125 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1126 EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
1128 row_sp = unwind_plan.GetRowForFunctionOffset(12);
1129 EXPECT_EQ(12ull, row_sp->GetOffset());
1130 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1131 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1132 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1135 TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
1136 UnwindPlan::Row::RegisterLocation regloc;
1137 UnwindPlan::RowSP row_sp;
1139 uint8_t data[] = {
1140 0x41, 0x57, // pushq %r15
1141 0x90 // nop
1144 AddressRange sample_range(0x1000, sizeof(data));
1145 UnwindPlan unwind_plan(eRegisterKindLLDB);
1147 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1148 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1149 data, sizeof(data), sample_range, unwind_plan));
1151 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1153 EXPECT_EQ(2ull, row_sp->GetOffset());
1154 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1155 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1156 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1158 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
1159 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1160 EXPECT_EQ(-16, regloc.GetOffset());
1163 TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {
1164 UnwindPlan::Row::RegisterLocation regloc;
1165 UnwindPlan::RowSP row_sp;
1167 uint8_t data[] = {
1168 0x41, 0x56, // pushq %r14
1169 0x90 // nop
1172 AddressRange sample_range(0x1000, sizeof(data));
1173 UnwindPlan unwind_plan(eRegisterKindLLDB);
1175 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1176 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1177 data, sizeof(data), sample_range, unwind_plan));
1179 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1181 EXPECT_EQ(2ull, row_sp->GetOffset());
1182 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1183 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1184 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1186 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
1187 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1188 EXPECT_EQ(-16, regloc.GetOffset());
1191 TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {
1192 UnwindPlan::Row::RegisterLocation regloc;
1193 UnwindPlan::RowSP row_sp;
1195 uint8_t data[] = {
1196 0x41, 0x55, // pushq %r13
1197 0x90 // nop
1200 AddressRange sample_range(0x1000, sizeof(data));
1201 UnwindPlan unwind_plan(eRegisterKindLLDB);
1203 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1204 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1205 data, sizeof(data), sample_range, unwind_plan));
1207 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1209 EXPECT_EQ(2ull, row_sp->GetOffset());
1210 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1211 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1212 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1214 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
1215 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1216 EXPECT_EQ(-16, regloc.GetOffset());
1219 TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {
1220 UnwindPlan::Row::RegisterLocation regloc;
1221 UnwindPlan::RowSP row_sp;
1223 uint8_t data[] = {
1224 0x41, 0x54, // pushq %r13
1225 0x90 // nop
1228 AddressRange sample_range(0x1000, sizeof(data));
1229 UnwindPlan unwind_plan(eRegisterKindLLDB);
1231 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1232 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1233 data, sizeof(data), sample_range, unwind_plan));
1235 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1237 EXPECT_EQ(2ull, row_sp->GetOffset());
1238 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1239 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1240 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1242 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
1243 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1244 EXPECT_EQ(-16, regloc.GetOffset());
1247 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {
1248 UnwindPlan::Row::RegisterLocation regloc;
1249 UnwindPlan::RowSP row_sp;
1251 uint8_t data[] = {
1252 0x53, // pushq %rbx
1253 0x90 // nop
1256 AddressRange sample_range(0x1000, sizeof(data));
1257 UnwindPlan unwind_plan(eRegisterKindLLDB);
1259 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1260 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1261 data, sizeof(data), sample_range, unwind_plan));
1263 row_sp = unwind_plan.GetRowForFunctionOffset(1);
1265 EXPECT_EQ(1ull, row_sp->GetOffset());
1266 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1267 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1268 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1270 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
1271 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1272 EXPECT_EQ(-16, regloc.GetOffset());
1275 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1276 // eax, ecx, edx are all considered volatile and push/pops of them are
1277 // not tracked (except to keep track of stack pointer movement)
1278 TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) {
1279 UnwindPlan::Row::RegisterLocation regloc;
1280 UnwindPlan::RowSP row_sp;
1281 AddressRange sample_range;
1282 UnwindPlan unwind_plan(eRegisterKindLLDB);
1283 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1285 uint8_t data[] = {
1286 0x50, // pushl %eax
1287 0x90 // nop
1290 sample_range = AddressRange(0x1000, sizeof(data));
1292 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1293 data, sizeof(data), sample_range, unwind_plan));
1295 row_sp = unwind_plan.GetRowForFunctionOffset(1);
1296 EXPECT_EQ(1ull, row_sp->GetOffset());
1297 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1298 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1299 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1301 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
1304 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1305 // eax, ecx, edx are all considered volatile and push/pops of them are
1306 // not tracked (except to keep track of stack pointer movement)
1307 TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) {
1308 UnwindPlan::Row::RegisterLocation regloc;
1309 UnwindPlan::RowSP row_sp;
1310 AddressRange sample_range;
1311 UnwindPlan unwind_plan(eRegisterKindLLDB);
1312 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1314 uint8_t data[] = {
1315 0x51, // pushl %ecx
1316 0x90 // nop
1319 sample_range = AddressRange(0x1000, sizeof(data));
1321 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1322 data, sizeof(data), sample_range, unwind_plan));
1324 row_sp = unwind_plan.GetRowForFunctionOffset(1);
1325 EXPECT_EQ(1ull, row_sp->GetOffset());
1326 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1327 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1328 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1330 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
1333 // The ABI is hardcoded in x86AssemblyInspectionEngine such that
1334 // eax, ecx, edx are all considered volatile and push/pops of them are
1335 // not tracked (except to keep track of stack pointer movement)
1336 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) {
1337 UnwindPlan::Row::RegisterLocation regloc;
1338 UnwindPlan::RowSP row_sp;
1339 AddressRange sample_range;
1340 UnwindPlan unwind_plan(eRegisterKindLLDB);
1341 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1343 uint8_t data[] = {
1344 0x52, // pushl %edx
1345 0x90 // nop
1348 sample_range = AddressRange(0x1000, sizeof(data));
1350 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1351 data, sizeof(data), sample_range, unwind_plan));
1353 row_sp = unwind_plan.GetRowForFunctionOffset(1);
1354 EXPECT_EQ(1ull, row_sp->GetOffset());
1355 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1356 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1357 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1359 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
1362 TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {
1363 UnwindPlan::Row::RegisterLocation regloc;
1364 UnwindPlan::RowSP row_sp;
1365 AddressRange sample_range;
1366 UnwindPlan unwind_plan(eRegisterKindLLDB);
1367 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1369 uint8_t data[] = {
1370 0x53, // pushl %ebx
1371 0x90 // nop
1374 sample_range = AddressRange(0x1000, sizeof(data));
1376 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1377 data, sizeof(data), sample_range, unwind_plan));
1379 row_sp = unwind_plan.GetRowForFunctionOffset(1);
1380 EXPECT_EQ(1ull, row_sp->GetOffset());
1381 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1382 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1383 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1385 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
1386 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1387 EXPECT_EQ(-8, regloc.GetOffset());
1390 TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {
1391 UnwindPlan::Row::RegisterLocation regloc;
1392 UnwindPlan::RowSP row_sp;
1393 AddressRange sample_range;
1394 UnwindPlan unwind_plan(eRegisterKindLLDB);
1395 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1397 uint8_t data[] = {
1398 0x55, // pushl %ebp
1399 0x90 // nop
1402 sample_range = AddressRange(0x1000, sizeof(data));
1404 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1405 data, sizeof(data), sample_range, unwind_plan));
1407 row_sp = unwind_plan.GetRowForFunctionOffset(1);
1408 EXPECT_EQ(1ull, row_sp->GetOffset());
1409 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1410 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1411 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1413 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
1414 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1415 EXPECT_EQ(-8, regloc.GetOffset());
1418 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBPWithREX) {
1419 UnwindPlan::Row::RegisterLocation regloc;
1420 UnwindPlan::RowSP row_sp;
1422 uint8_t data[] = {
1423 0x40, 0x55, // pushq %rbp
1424 0x90 // nop
1427 AddressRange sample_range(0x1000, sizeof(data));
1428 UnwindPlan unwind_plan(eRegisterKindLLDB);
1430 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1431 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1432 data, sizeof(data), sample_range, unwind_plan));
1434 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1436 EXPECT_EQ(2ull, row_sp->GetOffset());
1437 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1438 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1439 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1441 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
1442 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1443 EXPECT_EQ(-16, regloc.GetOffset());
1446 TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {
1447 UnwindPlan::Row::RegisterLocation regloc;
1448 UnwindPlan::RowSP row_sp;
1449 AddressRange sample_range;
1450 UnwindPlan unwind_plan(eRegisterKindLLDB);
1451 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1453 uint8_t data[] = {
1454 0x56, // pushl %esi
1455 0x90 // nop
1458 sample_range = AddressRange(0x1000, sizeof(data));
1460 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1461 data, sizeof(data), sample_range, unwind_plan));
1463 row_sp = unwind_plan.GetRowForFunctionOffset(1);
1464 EXPECT_EQ(1ull, row_sp->GetOffset());
1465 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1466 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1467 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1469 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
1470 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1471 EXPECT_EQ(-8, regloc.GetOffset());
1474 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {
1475 UnwindPlan::Row::RegisterLocation regloc;
1476 UnwindPlan::RowSP row_sp;
1477 AddressRange sample_range;
1478 UnwindPlan unwind_plan(eRegisterKindLLDB);
1479 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1481 uint8_t data[] = {
1482 0x57, // pushl %edi
1483 0x90 // nop
1486 sample_range = AddressRange(0x1000, sizeof(data));
1488 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1489 data, sizeof(data), sample_range, unwind_plan));
1491 row_sp = unwind_plan.GetRowForFunctionOffset(1);
1492 EXPECT_EQ(1ull, row_sp->GetOffset());
1493 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1494 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1495 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1497 EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
1498 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1499 EXPECT_EQ(-8, regloc.GetOffset());
1502 TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
1503 UnwindPlan::Row::RegisterLocation regloc;
1504 UnwindPlan::RowSP row_sp;
1506 uint8_t data64_1[] = {
1507 0x48, 0x8b, 0xec, // movq %rsp, %rbp
1508 0x90 // nop
1511 AddressRange sample_range(0x1000, sizeof(data64_1));
1512 UnwindPlan unwind_plan(eRegisterKindLLDB);
1514 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1515 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1516 data64_1, sizeof(data64_1), sample_range, unwind_plan));
1518 row_sp = unwind_plan.GetRowForFunctionOffset(3);
1520 EXPECT_EQ(3ull, row_sp->GetOffset());
1521 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
1522 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1523 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1525 uint8_t data64_2[] = {
1526 0x48, 0x89, 0xe5, // movq %rsp, %rbp
1527 0x90 // nop
1530 sample_range = AddressRange(0x1000, sizeof(data64_2));
1531 unwind_plan.Clear();
1532 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1533 data64_2, sizeof(data64_2), sample_range, unwind_plan));
1535 row_sp = unwind_plan.GetRowForFunctionOffset(3);
1536 EXPECT_EQ(3ull, row_sp->GetOffset());
1537 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
1538 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1539 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1541 uint8_t data32_1[] = {
1542 0x8b, 0xec, // movl %rsp, %rbp
1543 0x90 // nop
1546 sample_range = AddressRange(0x1000, sizeof(data32_1));
1547 unwind_plan.Clear();
1548 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1549 data32_1, sizeof(data32_1), sample_range, unwind_plan));
1551 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1552 EXPECT_EQ(2ull, row_sp->GetOffset());
1553 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
1554 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1555 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1557 uint8_t data32_2[] = {
1558 0x89, 0xe5, // movl %rsp, %rbp
1559 0x90 // nop
1562 sample_range = AddressRange(0x1000, sizeof(data32_2));
1563 unwind_plan.Clear();
1564 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1565 data32_2, sizeof(data32_2), sample_range, unwind_plan));
1567 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1568 EXPECT_EQ(2ull, row_sp->GetOffset());
1569 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
1570 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1571 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1574 TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {
1575 UnwindPlan::Row::RegisterLocation regloc;
1576 UnwindPlan::RowSP row_sp;
1577 AddressRange sample_range;
1578 UnwindPlan unwind_plan(eRegisterKindLLDB);
1579 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1581 uint8_t data1[] = {
1582 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp
1583 0x90 // nop
1586 sample_range = AddressRange(0x1000, sizeof(data1));
1588 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1589 data1, sizeof(data1), sample_range, unwind_plan));
1591 row_sp = unwind_plan.GetRowForFunctionOffset(7);
1592 EXPECT_EQ(7ull, row_sp->GetOffset());
1593 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1594 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1595 EXPECT_EQ(264, row_sp->GetCFAValue().GetOffset());
1597 uint8_t data2[] = {
1598 0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp
1599 0x90 // nop
1602 sample_range = AddressRange(0x1000, sizeof(data2));
1604 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1605 data2, sizeof(data2), sample_range, unwind_plan));
1607 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1608 EXPECT_EQ(4ull, row_sp->GetOffset());
1609 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1610 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1611 EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
1614 TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {
1615 UnwindPlan::Row::RegisterLocation regloc;
1616 UnwindPlan::RowSP row_sp;
1617 AddressRange sample_range;
1618 UnwindPlan unwind_plan(eRegisterKindLLDB);
1619 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1621 uint8_t data1[] = {
1622 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp
1623 0x90 // nop
1626 sample_range = AddressRange(0x1000, sizeof(data1));
1628 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1629 data1, sizeof(data1), sample_range, unwind_plan));
1631 row_sp = unwind_plan.GetRowForFunctionOffset(6);
1632 EXPECT_EQ(6ull, row_sp->GetOffset());
1633 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1634 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1635 EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset());
1637 uint8_t data2[] = {
1638 0x83, 0xec, 0x10, // subq $0x10, %esp
1639 0x90 // nop
1642 sample_range = AddressRange(0x1000, sizeof(data2));
1644 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1645 data2, sizeof(data2), sample_range, unwind_plan));
1647 row_sp = unwind_plan.GetRowForFunctionOffset(3);
1648 EXPECT_EQ(3ull, row_sp->GetOffset());
1649 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1650 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1651 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
1654 TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {
1655 UnwindPlan::Row::RegisterLocation regloc;
1656 UnwindPlan::RowSP row_sp;
1657 AddressRange sample_range;
1658 UnwindPlan unwind_plan(eRegisterKindLLDB);
1659 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1661 uint8_t data1[] = {
1662 0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp
1663 0x90 // nop
1666 sample_range = AddressRange(0x1000, sizeof(data1));
1668 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1669 data1, sizeof(data1), sample_range, unwind_plan));
1671 row_sp = unwind_plan.GetRowForFunctionOffset(7);
1672 EXPECT_EQ(7ull, row_sp->GetOffset());
1673 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1674 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1675 EXPECT_EQ(8 - 256, row_sp->GetCFAValue().GetOffset());
1677 uint8_t data2[] = {
1678 0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp
1679 0x90 // nop
1682 sample_range = AddressRange(0x1000, sizeof(data2));
1684 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1685 data2, sizeof(data2), sample_range, unwind_plan));
1687 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1688 EXPECT_EQ(4ull, row_sp->GetOffset());
1689 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1690 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1691 EXPECT_EQ(8 - 16, row_sp->GetCFAValue().GetOffset());
1694 TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {
1695 UnwindPlan::Row::RegisterLocation regloc;
1696 UnwindPlan::RowSP row_sp;
1697 AddressRange sample_range;
1698 UnwindPlan unwind_plan(eRegisterKindLLDB);
1699 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1701 uint8_t data1[] = {
1702 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
1703 0x90 // nop
1706 sample_range = AddressRange(0x1000, sizeof(data1));
1708 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1709 data1, sizeof(data1), sample_range, unwind_plan));
1711 row_sp = unwind_plan.GetRowForFunctionOffset(6);
1712 EXPECT_EQ(6ull, row_sp->GetOffset());
1713 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1714 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1715 EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset());
1717 uint8_t data2[] = {
1718 0x83, 0xc4, 0x10, // addq $0x10, %esp
1719 0x90 // nop
1722 sample_range = AddressRange(0x1000, sizeof(data2));
1724 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1725 data2, sizeof(data2), sample_range, unwind_plan));
1727 row_sp = unwind_plan.GetRowForFunctionOffset(3);
1728 EXPECT_EQ(3ull, row_sp->GetOffset());
1729 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1730 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1731 EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset());
1734 // FIXME add test for lea_rsp_pattern_p
1736 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {
1737 UnwindPlan::Row::RegisterLocation regloc;
1738 UnwindPlan::RowSP row_sp;
1739 AddressRange sample_range;
1740 UnwindPlan unwind_plan(eRegisterKindLLDB);
1741 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1743 uint8_t data[] = {
1744 0x53, // pushq %rbx
1745 0x5b, // popq %rbx
1746 0x90 // nop
1749 sample_range = AddressRange(0x1000, sizeof(data));
1751 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1752 data, sizeof(data), sample_range, unwind_plan));
1754 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1755 EXPECT_EQ(2ull, row_sp->GetOffset());
1756 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1757 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1758 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1759 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
1762 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {
1763 UnwindPlan::Row::RegisterLocation regloc;
1764 UnwindPlan::RowSP row_sp;
1765 AddressRange sample_range;
1766 UnwindPlan unwind_plan(eRegisterKindLLDB);
1767 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1769 uint8_t data[] = {
1770 0x55, // pushq %rbp
1771 0x5d, // popq %rbp
1772 0x90 // nop
1775 sample_range = AddressRange(0x1000, sizeof(data));
1777 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1778 data, sizeof(data), sample_range, unwind_plan));
1780 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1781 EXPECT_EQ(2ull, row_sp->GetOffset());
1782 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1783 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1784 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1785 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
1788 TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {
1789 UnwindPlan::Row::RegisterLocation regloc;
1790 UnwindPlan::RowSP row_sp;
1791 AddressRange sample_range;
1792 UnwindPlan unwind_plan(eRegisterKindLLDB);
1793 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1795 uint8_t data[] = {
1796 0x41, 0x54, // pushq %r12
1797 0x41, 0x5c, // popq %r12
1798 0x90 // nop
1801 sample_range = AddressRange(0x1000, sizeof(data));
1803 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1804 data, sizeof(data), sample_range, unwind_plan));
1806 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1807 EXPECT_EQ(4ull, row_sp->GetOffset());
1808 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1809 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1810 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1811 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
1814 TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {
1815 UnwindPlan::Row::RegisterLocation regloc;
1816 UnwindPlan::RowSP row_sp;
1817 AddressRange sample_range;
1818 UnwindPlan unwind_plan(eRegisterKindLLDB);
1819 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1821 uint8_t data[] = {
1822 0x41, 0x55, // pushq %r13
1823 0x41, 0x5d, // popq %r13
1824 0x90 // nop
1827 sample_range = AddressRange(0x1000, sizeof(data));
1829 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1830 data, sizeof(data), sample_range, unwind_plan));
1832 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1833 EXPECT_EQ(4ull, row_sp->GetOffset());
1834 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1835 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1836 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1837 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
1840 TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {
1841 UnwindPlan::Row::RegisterLocation regloc;
1842 UnwindPlan::RowSP row_sp;
1843 AddressRange sample_range;
1844 UnwindPlan unwind_plan(eRegisterKindLLDB);
1845 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1847 uint8_t data[] = {
1848 0x41, 0x56, // pushq %r14
1849 0x41, 0x5e, // popq %r14
1850 0x90 // nop
1853 sample_range = AddressRange(0x1000, sizeof(data));
1855 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1856 data, sizeof(data), sample_range, unwind_plan));
1858 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1859 EXPECT_EQ(4ull, row_sp->GetOffset());
1860 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1861 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1862 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1863 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
1866 TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {
1867 UnwindPlan::Row::RegisterLocation regloc;
1868 UnwindPlan::RowSP row_sp;
1869 AddressRange sample_range;
1870 UnwindPlan unwind_plan(eRegisterKindLLDB);
1871 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1873 uint8_t data[] = {
1874 0x41, 0x57, // pushq %r15
1875 0x41, 0x5f, // popq %r15
1876 0x90 // nop
1879 sample_range = AddressRange(0x1000, sizeof(data));
1881 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1882 data, sizeof(data), sample_range, unwind_plan));
1884 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1885 EXPECT_EQ(4ull, row_sp->GetOffset());
1886 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1887 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1888 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1889 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
1892 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {
1893 UnwindPlan::Row::RegisterLocation regloc;
1894 UnwindPlan::RowSP row_sp;
1895 AddressRange sample_range;
1896 UnwindPlan unwind_plan(eRegisterKindLLDB);
1897 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1899 uint8_t data[] = {
1900 0x53, // pushl %ebx
1901 0x5b, // popl %ebx
1902 0x90 // nop
1905 sample_range = AddressRange(0x1000, sizeof(data));
1907 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1908 data, sizeof(data), sample_range, unwind_plan));
1910 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1911 EXPECT_EQ(2ull, row_sp->GetOffset());
1912 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1913 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1914 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1915 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
1918 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {
1919 UnwindPlan::Row::RegisterLocation regloc;
1920 UnwindPlan::RowSP row_sp;
1921 AddressRange sample_range;
1922 UnwindPlan unwind_plan(eRegisterKindLLDB);
1923 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1925 uint8_t data[] = {
1926 0x55, // pushl %ebp
1927 0x5d, // popl %ebp
1928 0x90 // nop
1931 sample_range = AddressRange(0x1000, sizeof(data));
1933 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1934 data, sizeof(data), sample_range, unwind_plan));
1936 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1937 EXPECT_EQ(2ull, row_sp->GetOffset());
1938 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1939 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1940 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1941 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
1944 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBPWithREX) {
1945 UnwindPlan::Row::RegisterLocation regloc;
1946 UnwindPlan::RowSP row_sp;
1947 AddressRange sample_range;
1948 UnwindPlan unwind_plan(eRegisterKindLLDB);
1949 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1951 uint8_t data[] = {
1952 0x40, 0x55, // pushq %rbp
1953 0x40, 0x5d, // popq %rbp
1954 0x90 // nop
1957 sample_range = AddressRange(0x1000, sizeof(data));
1959 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1960 data, sizeof(data), sample_range, unwind_plan));
1962 row_sp = unwind_plan.GetRowForFunctionOffset(4);
1963 EXPECT_EQ(4ull, row_sp->GetOffset());
1964 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1965 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1966 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1967 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
1970 TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {
1971 UnwindPlan::Row::RegisterLocation regloc;
1972 UnwindPlan::RowSP row_sp;
1973 AddressRange sample_range;
1974 UnwindPlan unwind_plan(eRegisterKindLLDB);
1975 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1977 uint8_t data[] = {
1978 0x56, // pushl %esi
1979 0x5e, // popl %esi
1980 0x90 // nop
1983 sample_range = AddressRange(0x1000, sizeof(data));
1985 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1986 data, sizeof(data), sample_range, unwind_plan));
1988 row_sp = unwind_plan.GetRowForFunctionOffset(2);
1989 EXPECT_EQ(2ull, row_sp->GetOffset());
1990 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1991 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1992 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1993 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
1996 TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {
1997 UnwindPlan::Row::RegisterLocation regloc;
1998 UnwindPlan::RowSP row_sp;
1999 AddressRange sample_range;
2000 UnwindPlan unwind_plan(eRegisterKindLLDB);
2001 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2003 uint8_t data[] = {
2004 0x57, // pushl %edi
2005 0x5f, // popl %edi
2006 0x90 // nop
2009 sample_range = AddressRange(0x1000, sizeof(data));
2011 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2012 data, sizeof(data), sample_range, unwind_plan));
2014 row_sp = unwind_plan.GetRowForFunctionOffset(2);
2015 EXPECT_EQ(2ull, row_sp->GetOffset());
2016 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2017 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2018 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2019 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
2022 // We don't track these registers, but make sure the CFA address is updated
2023 // if we're defining the CFA in term of esp.
2024 TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {
2025 UnwindPlan::Row::RegisterLocation regloc;
2026 UnwindPlan::RowSP row_sp;
2027 AddressRange sample_range;
2028 UnwindPlan unwind_plan(eRegisterKindLLDB);
2029 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2031 uint8_t data[] = {
2032 0x0e, // push cs
2033 0x16, // push ss
2034 0x1e, // push ds
2035 0x06, // push es
2037 0x07, // pop es
2038 0x1f, // pop ds
2039 0x17, // pop ss
2041 0x90 // nop
2044 sample_range = AddressRange(0x1000, sizeof(data));
2046 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2047 data, sizeof(data), sample_range, unwind_plan));
2049 row_sp = unwind_plan.GetRowForFunctionOffset(4);
2050 EXPECT_EQ(4ull, row_sp->GetOffset());
2051 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2052 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2053 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
2055 row_sp = unwind_plan.GetRowForFunctionOffset(7);
2056 EXPECT_EQ(7ull, row_sp->GetOffset());
2057 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2058 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2059 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2062 TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {
2063 UnwindPlan::Row::RegisterLocation regloc;
2064 UnwindPlan::RowSP row_sp;
2065 AddressRange sample_range;
2066 UnwindPlan unwind_plan(eRegisterKindLLDB);
2067 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2068 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2070 uint8_t data[] = {
2071 0x55, // push %rbp/ebp
2072 0xc9, // leave
2073 0x90 // nop
2076 sample_range = AddressRange(0x1000, sizeof(data));
2078 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2079 data, sizeof(data), sample_range, unwind_plan));
2081 row_sp = unwind_plan.GetRowForFunctionOffset(2);
2082 EXPECT_EQ(2ull, row_sp->GetOffset());
2083 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2084 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2085 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2086 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2088 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2089 data, sizeof(data), sample_range, unwind_plan));
2091 row_sp = unwind_plan.GetRowForFunctionOffset(2);
2092 EXPECT_EQ(2ull, row_sp->GetOffset());
2093 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2094 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2095 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2096 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2099 // In i386, which lacks pc-relative addressing, a common code sequence
2100 // is to call the next instruction (i.e. call imm32, value of 0) which
2101 // pushes the addr of the next insn on the stack, and then pop that value
2102 // into a register (the "pic base" register).
2103 TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {
2104 UnwindPlan::Row::RegisterLocation regloc;
2105 UnwindPlan::RowSP row_sp;
2106 AddressRange sample_range;
2107 UnwindPlan unwind_plan(eRegisterKindLLDB);
2108 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2110 uint8_t data[] = {
2111 0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
2112 0x90 // nop
2115 sample_range = AddressRange(0x1000, sizeof(data));
2117 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2118 data, sizeof(data), sample_range, unwind_plan));
2120 row_sp = unwind_plan.GetRowForFunctionOffset(5);
2121 EXPECT_EQ(5ull, row_sp->GetOffset());
2122 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2123 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2124 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2125 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2128 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {
2129 UnwindPlan::Row::RegisterLocation regloc;
2130 UnwindPlan::RowSP row_sp;
2131 AddressRange sample_range;
2132 UnwindPlan unwind_plan(eRegisterKindLLDB);
2133 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2135 uint8_t data[] = {
2136 0x55, // pushq %rbp
2137 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2138 0x4c, 0x89, 0x75, 0xc0, // movq %r14, -0x40(%rbp)
2139 0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq %r15, -0x5d8(%rbp)
2140 0x48, 0x89, 0x5d, 0xb8, // movq %rbx, -0x48(%rbp)
2141 0x90 // nop
2144 sample_range = AddressRange(0x1000, sizeof(data));
2146 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2147 data, sizeof(data), sample_range, unwind_plan));
2149 row_sp = unwind_plan.GetRowForFunctionOffset(19);
2150 EXPECT_EQ(19ull, row_sp->GetOffset());
2151 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2152 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2154 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
2155 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2156 EXPECT_EQ(-80, regloc.GetOffset());
2158 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
2159 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2160 EXPECT_EQ(-1512, regloc.GetOffset());
2162 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
2163 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2164 EXPECT_EQ(-88, regloc.GetOffset());
2167 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {
2168 UnwindPlan::Row::RegisterLocation regloc;
2169 UnwindPlan::RowSP row_sp;
2170 AddressRange sample_range;
2171 UnwindPlan unwind_plan(eRegisterKindLLDB);
2172 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2174 uint8_t data[] = {
2175 0x55, // pushl %ebp
2176 0x89, 0xe5, // movl %esp, %ebp
2177 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
2178 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp)
2179 0x90 // nop
2182 sample_range = AddressRange(0x1000, sizeof(data));
2184 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2185 data, sizeof(data), sample_range, unwind_plan));
2187 row_sp = unwind_plan.GetRowForFunctionOffset(12);
2188 EXPECT_EQ(12ull, row_sp->GetOffset());
2189 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2190 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2192 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
2193 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2194 EXPECT_EQ(-344, regloc.GetOffset());
2196 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
2197 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2198 EXPECT_EQ(-40, regloc.GetOffset());
2201 TEST_F(Testx86AssemblyInspectionEngine, TestSpArithx86_64Augmented) {
2202 UnwindPlan::Row::RegisterLocation regloc;
2203 UnwindPlan::RowSP row_sp;
2204 AddressRange sample_range;
2205 UnwindPlan unwind_plan(eRegisterKindLLDB);
2206 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2208 uint8_t data[] = {
2209 0x55, // pushq %rbp
2210 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2212 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2213 // has a bug where it can't augment a function that is just
2214 // prologue+epilogue - it needs at least one other instruction
2215 // in between.
2217 0x90, // nop
2218 0x48, 0x81, 0xec, 0x88, 0, 0, 0, // subq $0x88, %rsp
2219 0x90, // nop
2220 0x48, 0x81, 0xc4, 0x88, 0, 0, 0, // addq $0x88, %rsp
2222 0x5d, // popq %rbp
2223 0xc3 // retq
2226 sample_range = AddressRange(0x1000, sizeof(data));
2228 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2229 unwind_plan.SetPlanValidAddressRange(sample_range);
2230 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2232 row_sp = std::make_shared<UnwindPlan::Row>();
2234 // Describe offset 0
2235 row_sp->SetOffset(0);
2236 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
2238 regloc.SetAtCFAPlusOffset(-8);
2239 row_sp->SetRegisterInfo(k_rip, regloc);
2241 unwind_plan.AppendRow(row_sp);
2243 // Allocate a new Row, populate it with the existing Row contents.
2244 UnwindPlan::Row *new_row = new UnwindPlan::Row;
2245 *new_row = *row_sp.get();
2246 row_sp.reset(new_row);
2248 // Describe offset 1
2249 row_sp->SetOffset(1);
2250 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
2251 regloc.SetAtCFAPlusOffset(-16);
2252 row_sp->SetRegisterInfo(k_rbp, regloc);
2253 unwind_plan.AppendRow(row_sp);
2255 // Allocate a new Row, populate it with the existing Row contents.
2256 new_row = new UnwindPlan::Row;
2257 *new_row = *row_sp.get();
2258 row_sp.reset(new_row);
2260 // Describe offset 4
2261 row_sp->SetOffset(4);
2262 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
2263 unwind_plan.AppendRow(row_sp);
2265 RegisterContextSP reg_ctx_sp;
2266 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2267 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2269 // Before we touch the stack pointer, we should still refer to the
2270 // row from after the prologue.
2271 row_sp = unwind_plan.GetRowForFunctionOffset(5);
2272 EXPECT_EQ(4ull, row_sp->GetOffset());
2274 // Check the first stack pointer update.
2275 row_sp = unwind_plan.GetRowForFunctionOffset(12);
2276 EXPECT_EQ(12ull, row_sp->GetOffset());
2277 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2278 EXPECT_EQ(152, row_sp->GetCFAValue().GetOffset());
2280 // After the nop, we should still refer to the same row.
2281 row_sp = unwind_plan.GetRowForFunctionOffset(13);
2282 EXPECT_EQ(12ull, row_sp->GetOffset());
2284 // Check that the second stack pointer update is reflected in the
2285 // unwind plan.
2286 row_sp = unwind_plan.GetRowForFunctionOffset(20);
2287 EXPECT_EQ(20ull, row_sp->GetOffset());
2288 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2289 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2292 TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {
2293 UnwindPlan::Row::RegisterLocation regloc;
2294 UnwindPlan::RowSP row_sp;
2295 AddressRange sample_range;
2296 UnwindPlan unwind_plan(eRegisterKindLLDB);
2297 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2299 uint8_t data[] = {
2300 0x55, // pushq %rbp
2301 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2303 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2304 // has a bug where it can't augment a function that is just
2305 // prologue+epilogue - it needs at least one other instruction
2306 // in between.
2307 0x90, // nop
2309 0x5d, // popq %rbp
2310 0xc3 // retq
2313 sample_range = AddressRange(0x1000, sizeof(data));
2315 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2316 unwind_plan.SetPlanValidAddressRange(sample_range);
2317 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2319 row_sp = std::make_shared<UnwindPlan::Row>();
2321 // Describe offset 0
2322 row_sp->SetOffset(0);
2323 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
2325 regloc.SetAtCFAPlusOffset(-8);
2326 row_sp->SetRegisterInfo(k_rip, regloc);
2328 unwind_plan.AppendRow(row_sp);
2330 // Allocate a new Row, populate it with the existing Row contents.
2331 UnwindPlan::Row *new_row = new UnwindPlan::Row;
2332 *new_row = *row_sp.get();
2333 row_sp.reset(new_row);
2335 // Describe offset 1
2336 row_sp->SetOffset(1);
2337 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
2338 regloc.SetAtCFAPlusOffset(-16);
2339 row_sp->SetRegisterInfo(k_rbp, regloc);
2340 unwind_plan.AppendRow(row_sp);
2342 // Allocate a new Row, populate it with the existing Row contents.
2343 new_row = new UnwindPlan::Row;
2344 *new_row = *row_sp.get();
2345 row_sp.reset(new_row);
2347 // Describe offset 4
2348 row_sp->SetOffset(4);
2349 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rbp, 16);
2350 unwind_plan.AppendRow(row_sp);
2352 RegisterContextSP reg_ctx_sp;
2353 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2354 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2356 row_sp = unwind_plan.GetRowForFunctionOffset(6);
2357 EXPECT_EQ(6ull, row_sp->GetOffset());
2358 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2359 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2361 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2362 // doesn't track register restores (pop'ing a reg value back from
2363 // the stack) - it was just written to make stepping work correctly.
2364 // Technically we should be able to do the following test, but it
2365 // won't work today - the unwind plan will still say that the caller's
2366 // rbp is on the stack.
2367 // EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2370 TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) {
2371 UnwindPlan::Row::RegisterLocation regloc;
2372 UnwindPlan::RowSP row_sp;
2373 AddressRange sample_range;
2374 UnwindPlan unwind_plan(eRegisterKindLLDB);
2375 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2377 uint8_t data[] = {
2378 0x55, // pushl %ebp
2379 0x89, 0xe5, // movl %esp, %ebp
2381 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2382 // has a bug where it can't augment a function that is just
2383 // prologue+epilogue - it needs at least one other instruction
2384 // in between.
2385 0x90, // nop
2387 0x5d, // popl %ebp
2388 0xc3 // retl
2391 sample_range = AddressRange(0x1000, sizeof(data));
2393 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2394 unwind_plan.SetPlanValidAddressRange(sample_range);
2395 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2397 row_sp = std::make_shared<UnwindPlan::Row>();
2399 // Describe offset 0
2400 row_sp->SetOffset(0);
2401 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 4);
2403 regloc.SetAtCFAPlusOffset(-4);
2404 row_sp->SetRegisterInfo(k_eip, regloc);
2406 unwind_plan.AppendRow(row_sp);
2408 // Allocate a new Row, populate it with the existing Row contents.
2409 UnwindPlan::Row *new_row = new UnwindPlan::Row;
2410 *new_row = *row_sp.get();
2411 row_sp.reset(new_row);
2413 // Describe offset 1
2414 row_sp->SetOffset(1);
2415 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 8);
2416 regloc.SetAtCFAPlusOffset(-8);
2417 row_sp->SetRegisterInfo(k_ebp, regloc);
2418 unwind_plan.AppendRow(row_sp);
2420 // Allocate a new Row, populate it with the existing Row contents.
2421 new_row = new UnwindPlan::Row;
2422 *new_row = *row_sp.get();
2423 row_sp.reset(new_row);
2425 // Describe offset 3
2426 row_sp->SetOffset(3);
2427 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_ebp, 8);
2428 unwind_plan.AppendRow(row_sp);
2430 RegisterContextSP reg_ctx_sp;
2431 EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite(
2432 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2434 row_sp = unwind_plan.GetRowForFunctionOffset(5);
2435 EXPECT_EQ(5ull, row_sp->GetOffset());
2436 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2437 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2439 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2440 // doesn't track register restores (pop'ing a reg value back from
2441 // the stack) - it was just written to make stepping work correctly.
2442 // Technically we should be able to do the following test, but it
2443 // won't work today - the unwind plan will still say that the caller's
2444 // ebp is on the stack.
2445 // EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2448 // Check that the i386 disassembler disassembles past an opcode that
2449 // is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler
2450 // stops
2451 // disassembling at that point (long-mode).
2452 TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {
2453 UnwindPlan::Row::RegisterLocation regloc;
2454 UnwindPlan::RowSP row_sp;
2455 AddressRange sample_range;
2456 UnwindPlan unwind_plan(eRegisterKindLLDB);
2457 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2458 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2460 uint8_t data[] = {
2461 0x43, // incl $ebx --- an invalid opcode in 64-bit mode
2462 0x55, // pushl %ebp
2463 0x90 // nop
2466 sample_range = AddressRange(0x1000, sizeof(data));
2468 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2469 data, sizeof(data), sample_range, unwind_plan));
2471 row_sp = unwind_plan.GetRowForFunctionOffset(2);
2472 EXPECT_EQ(2ull, row_sp->GetOffset());
2473 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2474 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2475 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2477 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
2478 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2479 EXPECT_EQ(-8, regloc.GetOffset());
2481 unwind_plan.Clear();
2483 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2484 data, sizeof(data), sample_range, unwind_plan));
2486 row_sp = unwind_plan.GetRowForFunctionOffset(2);
2487 EXPECT_EQ(0ull, row_sp->GetOffset());
2488 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2489 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2490 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2492 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2495 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {
2496 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2498 uint8_t data[] = {
2499 0x55, // pushl %ebp
2500 0x89, 0xe5, // movl %esp, %ebp
2501 0x53, // pushl %ebx
2502 0x83, 0xe4, 0xf0, // andl $-16, %esp
2503 0x83, 0xec, 0x10, // subl $16, %esp
2504 0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp
2505 0x5b, // popl %ebx
2506 0x5d, // popl %ebp
2507 0xc3, // retl
2510 AddressRange sample_range(0x1000, sizeof(data));
2511 UnwindPlan plan(eRegisterKindLLDB);
2512 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2513 sample_range, plan));
2515 UnwindPlan::Row::FAValue esp_plus_4, esp_plus_8, ebp_plus_8;
2516 esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
2517 esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
2518 ebp_plus_8.SetIsRegisterPlusOffset(k_ebp, 8);
2520 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2521 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2522 for (size_t i = 3; i < sizeof(data) - 2; ++i)
2523 EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2524 << "i: " << i;
2525 EXPECT_EQ(esp_plus_4,
2526 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
2529 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
2530 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
2532 uint8_t data[] = {
2533 0x55, // pushq %rbp
2534 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2535 0x53, // pushl %rbx
2536 0x48, 0x83, 0xe4, 0xf0, // andq $-16, %rsp
2537 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp
2538 0x48, 0x8d, 0x65, 0xf8, // leaq -8(%rbp), %rsp
2539 0x5b, // popq %rbx
2540 0x5d, // popq %rbp
2541 0xc3, // retq
2544 AddressRange sample_range(0x1000, sizeof(data));
2545 UnwindPlan plan(eRegisterKindLLDB);
2546 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2547 sample_range, plan));
2549 UnwindPlan::Row::FAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
2550 rsp_plus_8.SetIsRegisterPlusOffset(k_rsp, 8);
2551 rsp_plus_16.SetIsRegisterPlusOffset(k_rsp, 16);
2552 rbp_plus_16.SetIsRegisterPlusOffset(k_rbp, 16);
2554 EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2555 EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2556 for (size_t i = 4; i < sizeof(data) - 2; ++i)
2557 EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2558 << "i: " << i;
2559 EXPECT_EQ(rsp_plus_8,
2560 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
2563 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealignMSVC_i386) {
2564 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2566 uint8_t data[] = {
2567 0x53, // offset 00 -- pushl %ebx
2568 0x8b, 0xdc, // offset 01 -- movl %esp, %ebx
2569 0x83, 0xec, 0x08, // offset 03 -- subl $8, %esp
2570 0x81, 0xe4, 0x00, 0xff, 0xff, 0xff, // offset 06 -- andl $-256, %esp
2571 0x83, 0xc4, 0x04, // offset 12 -- addl $4, %esp
2572 0x55, // offset 15 -- pushl %ebp
2573 0x8b, 0xec, // offset 16 -- movl %esp, %ebp
2574 0x81, 0xec, 0x00, 0x02, 0x00, 0x00, // offset 18 -- subl $512, %esp
2575 0x89, 0x7d, 0xfc, // offset 24 -- movl %edi, -4(%ebp)
2576 0x8b, 0xe5, // offset 27 -- movl %ebp, %esp
2577 0x5d, // offset 29 -- popl %ebp
2578 0x8b, 0xe3, // offset 30 -- movl %ebx, %esp
2579 0x5b, // offset 32 -- popl %ebx
2580 0xc3 // offset 33 -- retl
2583 AddressRange sample_range(0x1000, sizeof(data));
2584 UnwindPlan plan(eRegisterKindLLDB);
2585 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2586 sample_range, plan));
2588 UnwindPlan::Row::FAValue esp_minus_4, esp_plus_0, esp_plus_4, esp_plus_8,
2589 ebx_plus_8, ebp_plus_0;
2590 esp_minus_4.SetIsRegisterPlusOffset(k_esp, -4);
2591 esp_plus_0.SetIsRegisterPlusOffset(k_esp, 0);
2592 esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
2593 esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
2594 ebx_plus_8.SetIsRegisterPlusOffset(k_ebx, 8);
2595 ebp_plus_0.SetIsRegisterPlusOffset(k_ebp, 0);
2597 // Test CFA
2598 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2599 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2600 for (size_t i = 3; i < 33; ++i)
2601 EXPECT_EQ(ebx_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2602 << "i: " << i;
2603 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(33)->GetCFAValue());
2605 // Test AFA
2606 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(12)->GetAFAValue());
2607 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(15)->GetAFAValue());
2608 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(16)->GetAFAValue());
2609 for (size_t i = 18; i < 30; ++i)
2610 EXPECT_EQ(ebp_plus_0, plan.GetRowForFunctionOffset(i)->GetAFAValue())
2611 << "i: " << i;
2612 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(30)->GetAFAValue());
2614 // Test saved register
2615 UnwindPlan::Row::RegisterLocation reg_loc;
2616 EXPECT_TRUE(
2617 plan.GetRowForFunctionOffset(27)->GetRegisterInfo(k_edi, reg_loc));
2618 EXPECT_TRUE(reg_loc.IsAtAFAPlusOffset());
2619 EXPECT_EQ(-4, reg_loc.GetOffset());
2622 // Give the disassembler random bytes to test that it doesn't exceed
2623 // the bounds of the array when run under clang's address sanitizer.
2624 TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) {
2625 AddressRange sample_range;
2626 UnwindPlan unwind_plan(eRegisterKindLLDB);
2627 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2628 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2630 uint8_t data[] = {
2631 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
2632 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
2634 sample_range = AddressRange(0x1000, sizeof(data));
2636 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2637 data, sizeof(data), sample_range, unwind_plan));
2639 unwind_plan.Clear();
2641 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2642 data, sizeof(data), sample_range, unwind_plan));
2646 TEST_F(Testx86AssemblyInspectionEngine, TestReturnDetect) {
2647 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
2649 // Single fragment with all four return forms.
2650 // We want to verify that the unwind state is reset after each ret.
2651 uint8_t data[] = {
2652 0x55, // offset 0 -- pushq %rbp
2653 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
2654 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
2655 0x5d, // offset 6 -- popq %rbp
2656 0xc3, // offset 7 -- retq
2657 0x31, 0xc0, // offset 8 -- xorl %eax, %eax
2658 0x5d, // offset 10 -- popq %rbp
2659 0xcb, // offset 11 -- retf
2660 0x31, 0xc0, // offset 12 -- xorl %eax, %eax
2661 0x5d, // offset 14 -- popq %rbp
2662 0xc2, 0x22, 0x11, // offset 15 -- retq 0x1122
2663 0x31, 0xc0, // offset 18 -- xorl %eax, %eax
2664 0x5d, // offset 20 -- popq %rbp
2665 0xca, 0x44, 0x33, // offset 21 -- retf 0x3344
2666 0x31, 0xc0, // offset 24 -- xorl %eax, %eax
2669 AddressRange sample_range(0x1000, sizeof(data));
2671 UnwindPlan unwind_plan(eRegisterKindLLDB);
2672 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2673 data, sizeof(data), sample_range, unwind_plan));
2675 // Expect following unwind rows:
2676 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2677 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2678 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2679 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2680 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2681 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2682 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2683 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2684 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2685 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2686 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2688 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
2689 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
2690 eLazyBoolYes);
2691 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
2693 UnwindPlan::Row::RegisterLocation regloc;
2695 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2696 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
2697 EXPECT_EQ(0ull, row_sp->GetOffset());
2698 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2699 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2700 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2702 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2703 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2704 EXPECT_EQ(-8, regloc.GetOffset());
2706 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2707 row_sp = unwind_plan.GetRowForFunctionOffset(1);
2708 EXPECT_EQ(1ull, row_sp->GetOffset());
2709 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2710 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2711 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2713 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2714 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2715 EXPECT_EQ(-8, regloc.GetOffset());
2717 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2718 row_sp = unwind_plan.GetRowForFunctionOffset(4);
2719 EXPECT_EQ(4ull, row_sp->GetOffset());
2720 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2721 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2722 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2724 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2725 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2726 EXPECT_EQ(-8, regloc.GetOffset());
2728 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2729 row_sp = unwind_plan.GetRowForFunctionOffset(7);
2730 EXPECT_EQ(7ull, row_sp->GetOffset());
2731 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2732 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2733 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2735 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2736 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2737 EXPECT_EQ(-8, regloc.GetOffset());
2739 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2740 row_sp = unwind_plan.GetRowForFunctionOffset(8);
2741 EXPECT_EQ(8ull, row_sp->GetOffset());
2742 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2743 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2744 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2746 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2747 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2748 EXPECT_EQ(-8, regloc.GetOffset());
2750 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2751 row_sp = unwind_plan.GetRowForFunctionOffset(11);
2752 EXPECT_EQ(11ull, row_sp->GetOffset());
2753 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2754 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2755 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2757 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2758 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2759 EXPECT_EQ(-8, regloc.GetOffset());
2761 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2762 row_sp = unwind_plan.GetRowForFunctionOffset(12);
2763 EXPECT_EQ(12ull, row_sp->GetOffset());
2764 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2765 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2766 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2768 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2769 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2770 EXPECT_EQ(-8, regloc.GetOffset());
2772 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2773 row_sp = unwind_plan.GetRowForFunctionOffset(15);
2774 EXPECT_EQ(15ull, row_sp->GetOffset());
2775 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2776 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2777 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2779 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2780 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2781 EXPECT_EQ(-8, regloc.GetOffset());
2783 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2784 row_sp = unwind_plan.GetRowForFunctionOffset(18);
2785 EXPECT_EQ(18ull, row_sp->GetOffset());
2786 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2787 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2788 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2790 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2791 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2792 EXPECT_EQ(-8, regloc.GetOffset());
2794 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2795 row_sp = unwind_plan.GetRowForFunctionOffset(21);
2796 EXPECT_EQ(21ull, row_sp->GetOffset());
2797 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2798 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2799 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2801 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2802 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2803 EXPECT_EQ(-8, regloc.GetOffset());
2805 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2806 row_sp = unwind_plan.GetRowForFunctionOffset(24);
2807 EXPECT_EQ(24ull, row_sp->GetOffset());
2808 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2809 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2810 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2812 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2813 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2814 EXPECT_EQ(-8, regloc.GetOffset());
2818 // Test mid-function epilogues - the unwind state post-prologue
2819 // should be re-instated.
2821 TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {
2822 AddressRange sample_range;
2823 UnwindPlan unwind_plan(eRegisterKindLLDB);
2824 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2825 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2827 uint8_t data[] = {
2828 0x55, // <+0>: pushq %rbp
2829 0x48, 0x89, 0xe5, // <+1>: movq %rsp, %rbp
2830 0x48, 0x83, 0xec, 0x70, // <+4>: subq $0x70, %rsp
2831 0x90, // <+8>: nop // prologue set up
2833 0x74, 0x7, // <+9>: je 7 <+18>
2834 0x48, 0x83, 0xc4, 0x70, // <+11>: addq $0x70, %rsp
2835 0x5d, // <+15>: popq %rbp
2836 0xff, 0xe0, // <+16>: jmpq *%rax // epilogue completed
2838 0x90, // <+18>: nop // prologue setup back
2840 0x74, 0x7, // <+19>: je 6 <+27>
2841 0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp
2842 0x5d, // <+25>: popq %rbp
2843 0xc3, // <+26>: retq // epilogue completed
2845 0x90, // <+27>: nop // prologue setup back
2847 0x48, 0x83, 0xc4, 0x70, // <+28>: addq $0x70, %rsp
2848 0x5d, // <+32>: popq %rbp
2849 0xc3, // <+33>: retq // epilogue completed
2853 sample_range = AddressRange(0x1000, sizeof(data));
2855 int wordsize = 4;
2856 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2857 data, sizeof(data), sample_range, unwind_plan));
2859 // Check that we've unwound the stack after the first mid-function epilogue
2860 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
2861 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(16);
2862 EXPECT_EQ(16ull, row_sp->GetOffset());
2863 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2864 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2865 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2867 // Check that we've reinstated the stack frame setup
2868 // unwind instructions after a jmpq *%eax
2869 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
2870 row_sp = unwind_plan.GetRowForFunctionOffset(18);
2871 EXPECT_EQ(18ull, row_sp->GetOffset());
2872 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
2873 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2874 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2876 // Check that we've reinstated the stack frame setup
2877 // unwind instructions after a mid-function retq
2878 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
2879 row_sp = unwind_plan.GetRowForFunctionOffset(27);
2880 EXPECT_EQ(27ull, row_sp->GetOffset());
2881 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
2882 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2883 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2885 // After last instruction in the function, verify that
2886 // the stack frame has been unwound
2887 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
2888 row_sp = unwind_plan.GetRowForFunctionOffset(33);
2889 EXPECT_EQ(33ull, row_sp->GetOffset());
2890 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2891 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2892 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2895 unwind_plan.Clear();
2897 wordsize = 8;
2898 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2899 data, sizeof(data), sample_range, unwind_plan));
2901 // Check that we've unwound the stack after the first mid-function epilogue
2902 // row: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2903 row_sp = unwind_plan.GetRowForFunctionOffset(16);
2904 EXPECT_EQ(16ull, row_sp->GetOffset());
2905 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2906 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2907 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2909 // Check that we've reinstated the stack frame setup
2910 // unwind instructions after a jmpq *%eax
2911 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
2912 row_sp = unwind_plan.GetRowForFunctionOffset(18);
2913 EXPECT_EQ(18ull, row_sp->GetOffset());
2914 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2915 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2916 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2918 // Check that we've reinstated the stack frame setup
2919 // unwind instructions after a mid-function retq
2920 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
2921 row_sp = unwind_plan.GetRowForFunctionOffset(27);
2922 EXPECT_EQ(27ull, row_sp->GetOffset());
2923 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2924 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2925 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2927 // After last instruction in the function, verify that
2928 // the stack frame has been unwound
2929 // row: CFA=rsp +8 => esp=CFA+0 rip=[CFA-8]
2930 row_sp = unwind_plan.GetRowForFunctionOffset(33);
2931 EXPECT_EQ(33ull, row_sp->GetOffset());
2932 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2933 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2934 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());