1 //===-- Testx86AssemblyInspectionEngine.cpp -------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #include "gtest/gtest.h"
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"
25 using namespace lldb_private
;
27 class Testx86AssemblyInspectionEngine
: public testing::Test
{
29 static void SetUpTestCase();
31 // static void TearDownTestCase() { }
33 // virtual void SetUp() override { }
35 // virtual void TearDown() override { }
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
50 // names should match the constants below. These will be the eRegisterKindLLDB
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"};
77 // names should match the constants below. These will be the eRegisterKindLLDB
80 const char *i386_reg_names
[] = {"eax", "ecx", "edx", "ebx", "esp",
81 "ebp", "esi", "edi", "eip"};
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
;
103 for (const auto &name
: x86_64_reg_names
) {
104 x86AssemblyInspectionEngine::lldb_reg_info ri
;
106 ri
.lldb_regnum
= i
++;
107 lldb_regnums
.push_back(ri
);
110 engine
->Initialize(lldb_regnums
);
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
;
122 for (const auto &name
: i386_reg_names
) {
123 x86AssemblyInspectionEngine::lldb_reg_info ri
;
125 ri
.lldb_regnum
= i
++;
126 lldb_regnums
.push_back(ri
);
129 engine
->Initialize(lldb_regnums
);
133 namespace lldb_private
{
134 static std::ostream
&operator<<(std::ostream
&OS
,
135 const UnwindPlan::Row::FAValue
&CFA
) {
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
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() ==
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
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() ==
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();
299 // #include <stdio.h>
300 // int main (int argc, char **argv)
303 // const int arrsize = 60;
304 // int buf[arrsize * arrsize];
306 // for (int i = 0; i < arrsize; i++)
307 // for (int j = 0; j < arrsize; j++)
309 // if (i > 0 && j > 0)
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;
318 // buf[i*j] = accum++;
321 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
325 // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx
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
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]
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]
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();
465 // #include <stdio.h>
466 // int main (int argc, char **argv)
469 // const int arrsize = 60;
470 // int buf[arrsize * arrsize];
472 // for (int i = 0; i < arrsize; i++)
473 // for (int j = 0; j < arrsize; j++)
475 // if (i > 0 && j > 0)
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;
484 // buf[i*j] = accum++;
487 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
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
497 // .section __TEXT,__text,regular,pure_instructions
498 // .macosx_version_min 10, 12
508 // subl $0x386c, %esp
512 // movl %ecx, 0x8(%esp)
519 // addl $0x386c, %esp
526 // .section __TEXT,__cstring,cstring_literals
531 // .subsections_via_symbols
535 // offset 0 -- pushl %ebp
538 // offset 1 -- pushl %ebx
541 // offset 2 -- pushl %edi
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
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)
563 // offset 20 -- subl $0x8, %esp
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
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
580 // offset 36 -- incl %ebx
584 0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00,
585 // offset 37 -- addl $0x386c, %esp
588 // offset 43 -- popl %esi
591 // offset 44 -- popl %edi
594 // offset 45 -- popl %ebx
597 // offset 46 -- popl %ebp
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
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]
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]
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
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();
761 // #include <stdio.h>
766 // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx
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
779 // offset 13 -- xorl %ecx, %ecx
781 0x89, 0x44, 0x24, 0x04,
782 // offset 15 -- movl %eax, 0x4(%rsp)
785 // offset 19 -- movl %ecx, %eax
788 // offset 21 -- popq %rcx
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();
858 // #include <stdio.h>
863 // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx
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
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
880 // offset 15 -- movl %eax, (%esp)
882 0xe8, 0x0d, 0x00, 0x00, 0x00,
883 // offset 18 -- calll 0x1f94 (puts)
886 // offset 23 -- xorl %ecx, %ecx
888 0x89, 0x44, 0x24, 0x08,
889 // offset 25 -- movl %eax, 0x8(%esp)
892 // offset 29 -- movl %ecx, %eax
895 // offset 31 -- addl $0xc, %esp
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
;
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
;
1012 0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
1013 0x6a, 0x7d, // pushl $0x7d
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
;
1061 0x6a, 0x00, // pushq $0
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
;
1092 0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp)
1093 0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl 0xf001ce(%esi)
1094 0xff, 0x30, // pushl (%eax)
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
;
1140 0x41, 0x57, // pushq %r15
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
;
1168 0x41, 0x56, // pushq %r14
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
;
1196 0x41, 0x55, // pushq %r13
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
;
1224 0x41, 0x54, // pushq %r13
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
;
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();
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();
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();
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();
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();
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
;
1423 0x40, 0x55, // pushq %rbp
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();
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();
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
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
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
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
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();
1582 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp
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());
1598 0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp
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();
1622 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp
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());
1638 0x83, 0xec, 0x10, // subq $0x10, %esp
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();
1662 0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp
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());
1678 0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp
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();
1702 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
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());
1718 0x83, 0xc4, 0x10, // addq $0x10, %esp
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();
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();
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();
1796 0x41, 0x54, // pushq %r12
1797 0x41, 0x5c, // popq %r12
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();
1822 0x41, 0x55, // pushq %r13
1823 0x41, 0x5d, // popq %r13
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();
1848 0x41, 0x56, // pushq %r14
1849 0x41, 0x5e, // popq %r14
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();
1874 0x41, 0x57, // pushq %r15
1875 0x41, 0x5f, // popq %r15
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();
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();
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();
1952 0x40, 0x55, // pushq %rbp
1953 0x40, 0x5d, // popq %rbp
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();
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();
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();
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();
2071 0x55, // push %rbp/ebp
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();
2111 0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
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();
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)
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();
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)
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();
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
2218 0x48, 0x81, 0xec, 0x88, 0, 0, 0, // subq $0x88, %rsp
2220 0x48, 0x81, 0xc4, 0x88, 0, 0, 0, // addq $0x88, %rsp
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
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();
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
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();
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
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
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();
2461 0x43, // incl $ebx --- an invalid opcode in 64-bit mode
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();
2500 0x89, 0xe5, // movl %esp, %ebp
2502 0x83, 0xe4, 0xf0, // andl $-16, %esp
2503 0x83, 0xec, 0x10, // subl $16, %esp
2504 0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp
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())
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();
2534 0x48, 0x89, 0xe5, // movq %rsp, %rbp
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
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())
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();
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);
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())
2603 EXPECT_EQ(esp_plus_4
, plan
.GetRowForFunctionOffset(33)->GetCFAValue());
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())
2612 EXPECT_EQ(esp_minus_4
, plan
.GetRowForFunctionOffset(30)->GetAFAValue());
2614 // Test saved register
2615 UnwindPlan::Row::RegisterLocation reg_loc
;
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();
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.
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() ==
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();
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
));
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();
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());