2925 lines · cpp
1//===-- Testx86AssemblyInspectionEngine.cpp -------------------------------===//2 3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10#include "gtest/gtest.h"11 12#include <memory>13#include <vector>14 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"21 22#include "llvm/Support/TargetSelect.h"23 24using namespace lldb;25using namespace lldb_private;26 27class Testx86AssemblyInspectionEngine : public testing::Test {28public:29 static void SetUpTestCase();30 31 // static void TearDownTestCase() { }32 33 // virtual void SetUp() override { }34 35 // virtual void TearDown() override { }36 37protected:38};39 40void Testx86AssemblyInspectionEngine::SetUpTestCase() {41 llvm::InitializeAllTargets();42 llvm::InitializeAllAsmPrinters();43 llvm::InitializeAllTargetMCs();44 llvm::InitializeAllDisassemblers();45}46 47// only defining the register names / numbers that the unwinder is actually48// using today49 50// names should match the constants below. These will be the eRegisterKindLLDB51// register numbers.52 53const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",54 "rsi", "rdi", "r8", "r9", "r10", "r11",55 "r12", "r13", "r14", "r15", "rip"};56 57enum x86_64_regs {58 k_rax = 0,59 k_rbx = 1,60 k_rcx = 2,61 k_rdx = 3,62 k_rsp = 4,63 k_rbp = 5,64 k_rsi = 6,65 k_rdi = 7,66 k_r8 = 8,67 k_r9 = 9,68 k_r10 = 10,69 k_r11 = 11,70 k_r12 = 12,71 k_r13 = 13,72 k_r14 = 14,73 k_r15 = 15,74 k_rip = 1675};76 77// names should match the constants below. These will be the eRegisterKindLLDB78// register numbers.79 80const char *i386_reg_names[] = {"eax", "ecx", "edx", "ebx", "esp",81 "ebp", "esi", "edi", "eip"};82 83enum i386_regs {84 k_eax = 0,85 k_ecx = 1,86 k_edx = 2,87 k_ebx = 3,88 k_esp = 4,89 k_ebp = 5,90 k_esi = 6,91 k_edi = 7,92 k_eip = 893};94 95std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {96 97 ArchSpec arch("x86_64-apple-macosx");98 std::unique_ptr<x86AssemblyInspectionEngine> engine(99 new x86AssemblyInspectionEngine(arch));100 101 std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;102 int i = 0;103 for (const auto &name : x86_64_reg_names) {104 x86AssemblyInspectionEngine::lldb_reg_info ri;105 ri.name = name;106 ri.lldb_regnum = i++;107 lldb_regnums.push_back(ri);108 }109 110 engine->Initialize(lldb_regnums);111 return engine;112}113 114std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {115 116 ArchSpec arch("i386-apple-macosx");117 std::unique_ptr<x86AssemblyInspectionEngine> engine(118 new x86AssemblyInspectionEngine(arch));119 120 std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;121 int i = 0;122 for (const auto &name : i386_reg_names) {123 x86AssemblyInspectionEngine::lldb_reg_info ri;124 ri.name = name;125 ri.lldb_regnum = i++;126 lldb_regnums.push_back(ri);127 }128 129 engine->Initialize(lldb_regnums);130 return engine;131}132 133namespace lldb_private {134static std::ostream &operator<<(std::ostream &OS,135 const UnwindPlan::Row::FAValue &CFA) {136 StreamString S;137 CFA.Dump(S, nullptr, nullptr);138 return OS << S.GetData();139}140} // namespace lldb_private141 142TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {143 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();144 145 // 'int main() { }' compiled for x86_64-apple-macosx with clang146 uint8_t data[] = {147 0x55, // offset 0 -- pushq %rbp148 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp149 0x31, 0xc0, // offset 4 -- xorl %eax, %eax150 0x5d, // offset 6 -- popq %rbp151 0xc3 // offset 7 -- retq152 };153 154 AddressRange sample_range(0x1000, sizeof(data));155 156 UnwindPlan unwind_plan(eRegisterKindLLDB);157 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(158 data, sizeof(data), sample_range, unwind_plan));159 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]165 166 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);167 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==168 eLazyBoolYes);169 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);170 171 UnwindPlan::Row::AbstractRegisterLocation regloc;172 173 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]174 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(0);175 EXPECT_EQ(0, row->GetOffset());176 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);177 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);178 EXPECT_EQ(8, row->GetCFAValue().GetOffset());179 180 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));181 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());182 EXPECT_EQ(-8, regloc.GetOffset());183 184 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]185 row = unwind_plan.GetRowForFunctionOffset(1);186 EXPECT_EQ(1, row->GetOffset());187 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);188 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);189 EXPECT_EQ(16, row->GetCFAValue().GetOffset());190 191 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));192 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());193 EXPECT_EQ(-8, regloc.GetOffset());194 195 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]196 row = unwind_plan.GetRowForFunctionOffset(4);197 EXPECT_EQ(4, row->GetOffset());198 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);199 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);200 EXPECT_EQ(16, row->GetCFAValue().GetOffset());201 202 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));203 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());204 EXPECT_EQ(-8, regloc.GetOffset());205 206 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]207 row = unwind_plan.GetRowForFunctionOffset(7);208 EXPECT_EQ(7, row->GetOffset());209 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);210 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);211 EXPECT_EQ(8, row->GetCFAValue().GetOffset());212 213 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));214 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());215 EXPECT_EQ(-8, regloc.GetOffset());216}217 218TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) {219 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();220 221 // 'int main() { }' compiled for i386-apple-macosx with clang222 uint8_t data[] = {223 0x55, // offset 0 -- pushl %ebp224 0x89, 0xe5, // offset 1 -- movl %esp, %ebp225 0x31, 0xc0, // offset 3 -- xorl %eax, %eax226 0x5d, // offset 5 -- popl %ebp227 0xc3 // offset 6 -- retl228 };229 230 AddressRange sample_range(0x1000, sizeof(data));231 232 UnwindPlan unwind_plan(eRegisterKindLLDB);233 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(234 data, sizeof(data), sample_range, unwind_plan));235 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]241 242 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_esp);243 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==244 eLazyBoolYes);245 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);246 247 UnwindPlan::Row::AbstractRegisterLocation regloc;248 249 // offset 0 -- pushl %ebp250 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(0);251 EXPECT_EQ(0, row->GetOffset());252 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);253 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);254 EXPECT_EQ(4, row->GetCFAValue().GetOffset());255 256 EXPECT_TRUE(row->GetRegisterInfo(k_eip, regloc));257 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());258 EXPECT_TRUE(regloc.GetOffset() == -4);259 260 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]261 row = unwind_plan.GetRowForFunctionOffset(1);262 EXPECT_EQ(1, row->GetOffset());263 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);264 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);265 EXPECT_EQ(8, row->GetCFAValue().GetOffset());266 267 EXPECT_TRUE(row->GetRegisterInfo(k_eip, regloc));268 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());269 EXPECT_EQ(-4, regloc.GetOffset());270 271 // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]272 row = unwind_plan.GetRowForFunctionOffset(3);273 EXPECT_EQ(3, row->GetOffset());274 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);275 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);276 EXPECT_EQ(8, row->GetCFAValue().GetOffset());277 278 EXPECT_TRUE(row->GetRegisterInfo(k_eip, regloc));279 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());280 EXPECT_EQ(-4, regloc.GetOffset());281 282 // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]283 row = unwind_plan.GetRowForFunctionOffset(6);284 EXPECT_EQ(6, row->GetOffset());285 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);286 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);287 EXPECT_EQ(4, row->GetCFAValue().GetOffset());288 289 EXPECT_TRUE(row->GetRegisterInfo(k_eip, regloc));290 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());291 EXPECT_EQ(-4, regloc.GetOffset());292}293 294TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) {295 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();296 297 // this source file:298 //299 // #include <stdio.h>300 // int main (int argc, char **argv)301 // {302 //303 // const int arrsize = 60;304 // int buf[arrsize * arrsize];305 // int accum = argc;306 // for (int i = 0; i < arrsize; i++)307 // for (int j = 0; j < arrsize; j++)308 // {309 // if (i > 0 && j > 0)310 // {311 // int n = buf[(i-1) * (j-1)] * 2;312 // int m = buf[(i-1) * (j-1)] / 2;313 // int j = buf[(i-1) * (j-1)] + 2;314 // int k = buf[(i-1) * (j-1)] - 2;315 // printf ("%d ", n + m + j + k);316 // buf[(i-1) * (j-1)] += n - m + j - k;317 // }318 // buf[i*j] = accum++;319 // }320 //321 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *322 // arrsize) - 3]);323 // }324 //325 // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx326 327 uint8_t data[] = {328 0x55, // offset 0 -- pushq %rbp329 0x41, 0x57, // offset 1 -- pushq %r15330 0x41, 0x56, // offset 3 -- pushq %r14331 0x41, 0x55, // offset 5 -- pushq %r13332 0x41, 0x54, // offset 7 -- pushq %r12333 0x53, // offset 9 -- pushq %rbx334 0x48, 0x81, 0xec, 0x68, 0x38, 0x00,335 0x00, // offset 10 -- subq $0x3868, %rsp336 337 // ....338 339 0x48, 0x81, 0xc4, 0x68, 0x38, 0x00,340 0x00, // offset 17 -- addq $0x3868, %rsp341 0x5b, // offset 24 -- popq %rbx342 0x41, 0x5c, // offset 25 -- popq %r12343 0x41, 0x5d, // offset 27 -- popq %r13344 0x41, 0x5e, // offset 29 -- popq %r14345 0x41, 0x5f, // offset 31 -- popq %r15346 0x5d, // offset 33 -- popq %rbp347 0xc3, // offset 34 -- retq348 0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever349 };350 351 AddressRange sample_range(0x1000, sizeof(data));352 353 UnwindPlan unwind_plan(eRegisterKindLLDB);354 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(355 data, sizeof(data), sample_range, unwind_plan));356 357 // Unwind rules should look like358 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]359 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]360 // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]361 // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]362 // rip=[CFA-8363 // 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]371 372 // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]373 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]374 // 25: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]375 // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]376 // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]377 // r15=[CFA-24] rip=[CFA-8]378 // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]379 // rip=[CFA-8]380 // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]381 // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]382 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]383 384 UnwindPlan::Row::AbstractRegisterLocation regloc;385 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]389 390 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(17);391 392 EXPECT_EQ(17, row->GetOffset());393 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);394 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);395 EXPECT_EQ(14496, row->GetCFAValue().GetOffset());396 397 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));398 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());399 EXPECT_EQ(-8, regloc.GetOffset());400 401 EXPECT_TRUE(row->GetRegisterInfo(k_rbp, regloc));402 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());403 EXPECT_EQ(-16, regloc.GetOffset());404 405 EXPECT_TRUE(row->GetRegisterInfo(k_r15, regloc));406 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());407 EXPECT_EQ(-24, regloc.GetOffset());408 409 EXPECT_TRUE(row->GetRegisterInfo(k_r14, regloc));410 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());411 EXPECT_EQ(-32, regloc.GetOffset());412 413 EXPECT_TRUE(row->GetRegisterInfo(k_r13, regloc));414 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());415 EXPECT_EQ(-40, regloc.GetOffset());416 417 EXPECT_TRUE(row->GetRegisterInfo(k_r12, regloc));418 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());419 EXPECT_EQ(-48, regloc.GetOffset());420 421 EXPECT_TRUE(row->GetRegisterInfo(k_rbx, regloc));422 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());423 EXPECT_EQ(-56, regloc.GetOffset());424 425 // grab the Row for when the epilogue has finished executing:426 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]427 428 row = unwind_plan.GetRowForFunctionOffset(34);429 430 EXPECT_EQ(34, row->GetOffset());431 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);432 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);433 EXPECT_EQ(8, row->GetCFAValue().GetOffset());434 435 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));436 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());437 EXPECT_EQ(-8, regloc.GetOffset());438 439 // these could be set to IsSame and be valid -- meaning that the440 // register value is the same as the caller's -- but I'd rather441 // they not be mentioned at all.442 443 EXPECT_FALSE(row->GetRegisterInfo(k_rax, regloc));444 EXPECT_FALSE(row->GetRegisterInfo(k_rbx, regloc));445 EXPECT_FALSE(row->GetRegisterInfo(k_rcx, regloc));446 EXPECT_FALSE(row->GetRegisterInfo(k_rdx, regloc));447 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));448 EXPECT_FALSE(row->GetRegisterInfo(k_rsi, regloc));449 EXPECT_FALSE(row->GetRegisterInfo(k_rdi, regloc));450 EXPECT_FALSE(row->GetRegisterInfo(k_r8, regloc));451 EXPECT_FALSE(row->GetRegisterInfo(k_r9, regloc));452 EXPECT_FALSE(row->GetRegisterInfo(k_r10, regloc));453 EXPECT_FALSE(row->GetRegisterInfo(k_r11, regloc));454 EXPECT_FALSE(row->GetRegisterInfo(k_r12, regloc));455 EXPECT_FALSE(row->GetRegisterInfo(k_r13, regloc));456 EXPECT_FALSE(row->GetRegisterInfo(k_r14, regloc));457 EXPECT_FALSE(row->GetRegisterInfo(k_r15, regloc));458}459 460TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessBigStackFrame) {461 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();462 463 // this source file:464 //465 // #include <stdio.h>466 // int main (int argc, char **argv)467 // {468 //469 // const int arrsize = 60;470 // int buf[arrsize * arrsize];471 // int accum = argc;472 // for (int i = 0; i < arrsize; i++)473 // for (int j = 0; j < arrsize; j++)474 // {475 // if (i > 0 && j > 0)476 // {477 // int n = buf[(i-1) * (j-1)] * 2;478 // int m = buf[(i-1) * (j-1)] / 2;479 // int j = buf[(i-1) * (j-1)] + 2;480 // int k = buf[(i-1) * (j-1)] - 2;481 // printf ("%d ", n + m + j + k);482 // buf[(i-1) * (j-1)] += n - m + j - k;483 // }484 // buf[i*j] = accum++;485 // }486 //487 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *488 // arrsize) - 3]);489 // }490 //491 // compiled 'clang -arch i386 -fomit-frame-pointer -Os' for i386-apple-macosx492 493 // simplified assembly version of the above function, which is used as the494 // input495 // data:496 //497 // .section __TEXT,__text,regular,pure_instructions498 // .macosx_version_min 10, 12499 // .globl _main500 // .align 4, 0x90501 // _main: ## @main502 // ## BB#0:503 // pushl %ebp504 // pushl %ebx505 // pushl %edi506 // pushl %esi507 // L0$pb:508 // subl $0x386c, %esp509 // calll L1510 // L1:511 // popl %ecx512 // movl %ecx, 0x8(%esp)513 // subl $0x8, %esp514 // pushl %eax515 // pushl 0x20(%esp)516 // calll _puts517 // addl $0x10, %esp518 // incl %ebx519 // addl $0x386c, %esp520 // popl %esi521 // popl %edi522 // popl %ebx523 // popl %ebp524 // retl525 //526 // .section __TEXT,__cstring,cstring_literals527 // L_.str: ## @.str528 // .asciz "HI"529 //530 //531 // .subsections_via_symbols532 533 uint8_t data[] = {534 0x55,535 // offset 0 -- pushl %ebp536 537 0x53,538 // offset 1 -- pushl %ebx539 540 0x57,541 // offset 2 -- pushl %edi542 543 0x56,544 // offset 3 -- pushl %esi545 546 0x81, 0xec, 0x6c, 0x38, 0x00, 0x00,547 // offset 4 -- subl $0x386c, %esp548 549 0xe8, 0x00, 0x00, 0x00, 0x00,550 // offset 10 -- calll 0551 // call the next instruction, to put the pc on the stack552 553 0x59,554 // offset 15 -- popl %ecx555 // pop the saved pc address into ecx556 557 0x89, 0x4c, 0x24, 0x08,558 // offset 16 -- movl %ecx, 0x8(%esp)559 560 // ....561 562 0x83, 0xec, 0x08,563 // offset 20 -- subl $0x8, %esp564 565 0x50,566 // offset 23 -- pushl %eax567 568 0xff, 0x74, 0x24, 0x20,569 // offset 24 -- pushl 0x20(%esp)570 571 0xe8, 0x8c, 0x00, 0x00, 0x00,572 // offset 28 -- calll puts573 574 0x83, 0xc4, 0x10,575 // offset 33 -- addl $0x10, %esp576 // get esp back to the value it was before the577 // alignment & argument saves for the puts call578 579 0x43,580 // offset 36 -- incl %ebx581 582 // ....583 584 0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00,585 // offset 37 -- addl $0x386c, %esp586 587 0x5e,588 // offset 43 -- popl %esi589 590 0x5f,591 // offset 44 -- popl %edi592 593 0x5b,594 // offset 45 -- popl %ebx595 596 0x5d,597 // offset 46 -- popl %ebp598 599 0xc3,600 // offset 47 -- retl601 602 0xe8, 0x12, 0x34, 0x56, 0x78,603 // offset 48 -- calll __stack_chk_fail604 };605 606 AddressRange sample_range(0x1000, sizeof(data));607 608 UnwindPlan unwind_plan(eRegisterKindLLDB);609 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(610 data, sizeof(data), sample_range, unwind_plan));611 612 // Unwind rules should look like613 //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+0618 // eip=[CFA-4]619 // 4: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]620 // esp=CFA+0 eip=[CFA-4]621 // 10: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]622 // esp=CFA+0 eip=[CFA-4]623 // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]624 // esp=CFA+0 eip=[CFA-4]625 // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]626 // esp=CFA+0 eip=[CFA-4]627 //628 // ....629 //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]638 //639 // .....640 //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+0646 // eip=[CFA-4]647 // 45: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]648 // 46: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]649 // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]650 // 48: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]651 // esp=CFA+0 eip=[CFA-4]652 653 UnwindPlan::Row::AbstractRegisterLocation regloc;654 const UnwindPlan::Row *row;655 656 // Check that we get the CFA correct for the pic base setup sequence657 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 = unwind_plan.GetRowForFunctionOffset(10);661 EXPECT_EQ(10, row->GetOffset());662 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);663 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);664 EXPECT_EQ(14464, row->GetCFAValue().GetOffset());665 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 = unwind_plan.GetRowForFunctionOffset(15);669 EXPECT_EQ(15, row->GetOffset());670 EXPECT_EQ(14468, row->GetCFAValue().GetOffset());671 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 = unwind_plan.GetRowForFunctionOffset(16);675 EXPECT_EQ(16, row->GetOffset());676 EXPECT_EQ(14464, row->GetCFAValue().GetOffset());677 678 // Check that the row for offset 16 has the registers saved that we expect679 680 EXPECT_TRUE(row->GetRegisterInfo(k_eip, regloc));681 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());682 EXPECT_EQ(-4, regloc.GetOffset());683 684 EXPECT_TRUE(row->GetRegisterInfo(k_ebp, regloc));685 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());686 EXPECT_EQ(-8, regloc.GetOffset());687 688 EXPECT_TRUE(row->GetRegisterInfo(k_ebx, regloc));689 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());690 EXPECT_EQ(-12, regloc.GetOffset());691 692 EXPECT_TRUE(row->GetRegisterInfo(k_edi, regloc));693 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());694 EXPECT_EQ(-16, regloc.GetOffset());695 696 EXPECT_TRUE(row->GetRegisterInfo(k_esi, regloc));697 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());698 EXPECT_EQ(-20, regloc.GetOffset());699 700 //701 // Check the pushing & popping around the call printf instruction702 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 = unwind_plan.GetRowForFunctionOffset(23);706 EXPECT_EQ(23, row->GetOffset());707 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);708 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);709 EXPECT_EQ(14472, row->GetCFAValue().GetOffset());710 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 = unwind_plan.GetRowForFunctionOffset(24);714 EXPECT_EQ(24, row->GetOffset());715 EXPECT_EQ(14476, row->GetCFAValue().GetOffset());716 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 = unwind_plan.GetRowForFunctionOffset(28);720 EXPECT_EQ(28, row->GetOffset());721 EXPECT_EQ(14480, row->GetCFAValue().GetOffset());722 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 = unwind_plan.GetRowForFunctionOffset(36);726 EXPECT_EQ(36, row->GetOffset());727 EXPECT_EQ(14464, row->GetCFAValue().GetOffset());728 729 // Check that the epilogue gets us back to the original unwind state730 731 // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]732 row = unwind_plan.GetRowForFunctionOffset(47);733 EXPECT_EQ(47, row->GetOffset());734 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);735 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);736 EXPECT_EQ(4, row->GetCFAValue().GetOffset());737 738 EXPECT_TRUE(row->GetRegisterInfo(k_eip, regloc));739 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());740 EXPECT_EQ(-4, regloc.GetOffset());741 742 EXPECT_TRUE(row->GetRegisterInfo(k_esp, regloc));743 EXPECT_TRUE(regloc.IsCFAPlusOffset());744 EXPECT_EQ(0, regloc.GetOffset());745 746 // Check that no unexpected registers were saved747 748 EXPECT_FALSE(row->GetRegisterInfo(k_eax, regloc));749 EXPECT_FALSE(row->GetRegisterInfo(k_ebx, regloc));750 EXPECT_FALSE(row->GetRegisterInfo(k_ecx, regloc));751 EXPECT_FALSE(row->GetRegisterInfo(k_edx, regloc));752 EXPECT_FALSE(row->GetRegisterInfo(k_esi, regloc));753 EXPECT_FALSE(row->GetRegisterInfo(k_edi, regloc));754 EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));755}756 757TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessSmallStackFrame) {758 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();759 760 // this source file:761 // #include <stdio.h>762 // int main () {763 // puts ("HI");764 // }765 //766 // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx767 768 uint8_t data[] = {769 0x50,770 // offset 0 -- pushq %rax771 772 0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00,773 // offset 1 -- leaq 0x32(%rip), %rdi ; "HI"774 775 0xe8, 0x0b, 0x00, 0x00, 0x00,776 // offset 8 -- callq 0x100000f58 ; puts777 778 0x31, 0xc9,779 // offset 13 -- xorl %ecx, %ecx780 781 0x89, 0x44, 0x24, 0x04,782 // offset 15 -- movl %eax, 0x4(%rsp)783 784 0x89, 0xc8,785 // offset 19 -- movl %ecx, %eax786 787 0x59,788 // offset 21 -- popq %rcx789 790 0xc3791 // offset 22 -- retq792 };793 794 AddressRange sample_range(0x1000, sizeof(data));795 796 UnwindPlan unwind_plan(eRegisterKindLLDB);797 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(798 data, sizeof(data), sample_range, unwind_plan));799 800 // Unwind rules should look like801 // 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]804 805 UnwindPlan::Row::AbstractRegisterLocation regloc;806 807 // grab the Row for when the prologue has finished executing:808 // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]809 810 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(13);811 812 EXPECT_EQ(1, row->GetOffset());813 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);814 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);815 EXPECT_EQ(16, row->GetCFAValue().GetOffset());816 817 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));818 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());819 EXPECT_EQ(-8, regloc.GetOffset());820 821 // none of these were spilled822 823 EXPECT_FALSE(row->GetRegisterInfo(k_rax, regloc));824 EXPECT_FALSE(row->GetRegisterInfo(k_rbx, regloc));825 EXPECT_FALSE(row->GetRegisterInfo(k_rcx, regloc));826 EXPECT_FALSE(row->GetRegisterInfo(k_rdx, regloc));827 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));828 EXPECT_FALSE(row->GetRegisterInfo(k_rsi, regloc));829 EXPECT_FALSE(row->GetRegisterInfo(k_rdi, regloc));830 EXPECT_FALSE(row->GetRegisterInfo(k_r8, regloc));831 EXPECT_FALSE(row->GetRegisterInfo(k_r9, regloc));832 EXPECT_FALSE(row->GetRegisterInfo(k_r10, regloc));833 EXPECT_FALSE(row->GetRegisterInfo(k_r11, regloc));834 EXPECT_FALSE(row->GetRegisterInfo(k_r12, regloc));835 EXPECT_FALSE(row->GetRegisterInfo(k_r13, regloc));836 EXPECT_FALSE(row->GetRegisterInfo(k_r14, regloc));837 EXPECT_FALSE(row->GetRegisterInfo(k_r15, regloc));838 839 // grab the Row for when the epilogue has finished executing:840 // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]841 842 row = unwind_plan.GetRowForFunctionOffset(22);843 844 EXPECT_EQ(22, row->GetOffset());845 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);846 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);847 EXPECT_EQ(8, row->GetCFAValue().GetOffset());848 849 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));850 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());851 EXPECT_EQ(-8, regloc.GetOffset());852}853 854TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) {855 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();856 857 // this source file:858 // #include <stdio.h>859 // int main () {860 // puts ("HI");861 // }862 //863 // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx864 865 uint8_t data[] = {866 0x83, 0xec, 0x0c,867 // offset 0 -- subl $0xc, %esp868 869 0xe8, 0x00, 0x00, 0x00, 0x00,870 // offset 3 -- calll 0 {call the next instruction, to put the pc on871 // the stack}872 873 0x58,874 // offset 8 -- popl %eax {pop the saved pc value off stack, into eax}875 876 0x8d, 0x80, 0x3a, 0x00, 0x00, 0x00,877 // offset 9 -- leal 0x3a(%eax),%eax878 879 0x89, 0x04, 0x24,880 // offset 15 -- movl %eax, (%esp)881 882 0xe8, 0x0d, 0x00, 0x00, 0x00,883 // offset 18 -- calll 0x1f94 (puts)884 885 0x31, 0xc9,886 // offset 23 -- xorl %ecx, %ecx887 888 0x89, 0x44, 0x24, 0x08,889 // offset 25 -- movl %eax, 0x8(%esp)890 891 0x89, 0xc8,892 // offset 29 -- movl %ecx, %eax893 894 0x83, 0xc4, 0x0c,895 // offset 31 -- addl $0xc, %esp896 897 0xc3898 // offset 34 -- retl899 };900 901 AddressRange sample_range(0x1000, sizeof(data));902 903 UnwindPlan unwind_plan(eRegisterKindLLDB);904 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(905 data, sizeof(data), sample_range, unwind_plan));906 907 // Unwind rules should look like908 // 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]913 914 UnwindPlan::Row::AbstractRegisterLocation regloc;915 916 // Check unwind state before we set up the picbase register917 // 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]918 919 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(3);920 921 EXPECT_EQ(3, row->GetOffset());922 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);923 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);924 EXPECT_EQ(16, row->GetCFAValue().GetOffset());925 926 // Check unwind state after we call the next instruction927 // 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]928 929 row = unwind_plan.GetRowForFunctionOffset(8);930 EXPECT_EQ(8, row->GetOffset());931 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);932 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);933 EXPECT_EQ(20, row->GetCFAValue().GetOffset());934 935 // Check unwind state after we pop the pic base value off the stack936 // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]937 938 row = unwind_plan.GetRowForFunctionOffset(9);939 EXPECT_EQ(9, row->GetOffset());940 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);941 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);942 EXPECT_EQ(16, row->GetCFAValue().GetOffset());943 944 // Check that no unexpected registers were saved945 946 EXPECT_FALSE(row->GetRegisterInfo(k_eax, regloc));947 EXPECT_FALSE(row->GetRegisterInfo(k_ebx, regloc));948 EXPECT_FALSE(row->GetRegisterInfo(k_ecx, regloc));949 EXPECT_FALSE(row->GetRegisterInfo(k_edx, regloc));950 EXPECT_FALSE(row->GetRegisterInfo(k_esi, regloc));951 EXPECT_FALSE(row->GetRegisterInfo(k_edi, regloc));952 EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));953 954 // verify that we get back to the original unwind state before the ret955 // 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]956 957 row = unwind_plan.GetRowForFunctionOffset(34);958 EXPECT_EQ(34, row->GetOffset());959 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);960 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);961 EXPECT_EQ(4, row->GetCFAValue().GetOffset());962}963 964TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {965 UnwindPlan::Row::AbstractRegisterLocation regloc;966 const UnwindPlan::Row *row;967 968 uint8_t data[] = {969 0x55, // pushq %rbp970 0x90 // nop971 };972 973 AddressRange sample_range(0x1000, sizeof(data));974 UnwindPlan unwind_plan(eRegisterKindLLDB);975 976 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();977 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(978 data, sizeof(data), sample_range, unwind_plan));979 980 row = unwind_plan.GetRowForFunctionOffset(1);981 982 EXPECT_EQ(1, row->GetOffset());983 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);984 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);985 EXPECT_EQ(16, row->GetCFAValue().GetOffset());986 987 EXPECT_TRUE(row->GetRegisterInfo(k_rbp, regloc));988 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());989 EXPECT_EQ(-16, regloc.GetOffset());990 991 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();992 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(993 data, sizeof(data), sample_range, unwind_plan));994 995 row = unwind_plan.GetRowForFunctionOffset(1);996 997 EXPECT_EQ(1, row->GetOffset());998 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);999 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1000 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1001 1002 EXPECT_TRUE(row->GetRegisterInfo(k_rbp, regloc));1003 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1004 EXPECT_EQ(-8, regloc.GetOffset());1005}1006 1007TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {1008 UnwindPlan::Row::AbstractRegisterLocation regloc;1009 const UnwindPlan::Row *row;1010 1011 uint8_t data[] = {1012 0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff1013 0x6a, 0x7d, // pushl $0x7d1014 0x90 // nop1015 };1016 1017 AddressRange sample_range(0x1000, sizeof(data));1018 UnwindPlan unwind_plan(eRegisterKindLLDB);1019 1020 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1021 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1022 data, sizeof(data), sample_range, unwind_plan));1023 1024 row = unwind_plan.GetRowForFunctionOffset(5);1025 EXPECT_EQ(5, row->GetOffset());1026 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1027 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1028 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1029 1030 row = unwind_plan.GetRowForFunctionOffset(7);1031 EXPECT_EQ(7, row->GetOffset());1032 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1033 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1034 EXPECT_EQ(24, row->GetCFAValue().GetOffset());1035 1036 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1037 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1038 data, sizeof(data), sample_range, unwind_plan));1039 1040 row = unwind_plan.GetRowForFunctionOffset(5);1041 EXPECT_EQ(5, row->GetOffset());1042 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1043 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1044 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1045 1046 row = unwind_plan.GetRowForFunctionOffset(7);1047 EXPECT_EQ(7, row->GetOffset());1048 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1049 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1050 EXPECT_EQ(12, row->GetCFAValue().GetOffset());1051}1052 1053// We treat 'pushq $0' / 'pushl $0' specially - this shows up1054// in the first function called in a new thread and it needs to1055// put a 0 as the saved pc. We pretend it didn't change the CFA.1056TEST_F(Testx86AssemblyInspectionEngine, TestPush0) {1057 UnwindPlan::Row::AbstractRegisterLocation regloc;1058 const UnwindPlan::Row *row;1059 1060 uint8_t data[] = {1061 0x6a, 0x00, // pushq $01062 0x90 // nop1063 };1064 1065 AddressRange sample_range(0x1000, sizeof(data));1066 UnwindPlan unwind_plan(eRegisterKindLLDB);1067 1068 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1069 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1070 data, sizeof(data), sample_range, unwind_plan));1071 1072 row = unwind_plan.GetRowForFunctionOffset(2);1073 1074 // We're verifying that no row was created for the 'pushq $0'1075 EXPECT_EQ(0, row->GetOffset());1076 1077 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1078 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1079 data, sizeof(data), sample_range, unwind_plan));1080 1081 row = unwind_plan.GetRowForFunctionOffset(2);1082 1083 // We're verifying that no row was created for the 'pushq $0'1084 EXPECT_EQ(0, row->GetOffset());1085}1086 1087TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {1088 UnwindPlan::Row::AbstractRegisterLocation regloc;1089 const UnwindPlan::Row *row;1090 1091 uint8_t data[] = {1092 0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp)1093 0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl 0xf001ce(%esi)1094 0xff, 0x30, // pushl (%eax)1095 0x90 // nop1096 };1097 1098 AddressRange sample_range(0x1000, sizeof(data));1099 UnwindPlan unwind_plan(eRegisterKindLLDB);1100 1101 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1102 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1103 data, sizeof(data), sample_range, unwind_plan));1104 1105 row = unwind_plan.GetRowForFunctionOffset(4);1106 1107 EXPECT_EQ(4, row->GetOffset());1108 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1109 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1110 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1111 1112 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1113 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1114 data, sizeof(data), sample_range, unwind_plan));1115 1116 row = unwind_plan.GetRowForFunctionOffset(4);1117 EXPECT_EQ(4, row->GetOffset());1118 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1119 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1120 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1121 1122 row = unwind_plan.GetRowForFunctionOffset(10);1123 EXPECT_EQ(10, row->GetOffset());1124 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1125 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1126 EXPECT_EQ(12, row->GetCFAValue().GetOffset());1127 1128 row = unwind_plan.GetRowForFunctionOffset(12);1129 EXPECT_EQ(12, row->GetOffset());1130 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1131 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1132 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1133}1134 1135TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {1136 UnwindPlan::Row::AbstractRegisterLocation regloc;1137 const UnwindPlan::Row *row;1138 1139 uint8_t data[] = {1140 0x41, 0x57, // pushq %r151141 0x90 // nop1142 };1143 1144 AddressRange sample_range(0x1000, sizeof(data));1145 UnwindPlan unwind_plan(eRegisterKindLLDB);1146 1147 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1148 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1149 data, sizeof(data), sample_range, unwind_plan));1150 1151 row = unwind_plan.GetRowForFunctionOffset(2);1152 1153 EXPECT_EQ(2, row->GetOffset());1154 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1155 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1156 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1157 1158 EXPECT_TRUE(row->GetRegisterInfo(k_r15, regloc));1159 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1160 EXPECT_EQ(-16, regloc.GetOffset());1161}1162 1163TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {1164 UnwindPlan::Row::AbstractRegisterLocation regloc;1165 const UnwindPlan::Row *row;1166 1167 uint8_t data[] = {1168 0x41, 0x56, // pushq %r141169 0x90 // nop1170 };1171 1172 AddressRange sample_range(0x1000, sizeof(data));1173 UnwindPlan unwind_plan(eRegisterKindLLDB);1174 1175 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1176 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1177 data, sizeof(data), sample_range, unwind_plan));1178 1179 row = unwind_plan.GetRowForFunctionOffset(2);1180 1181 EXPECT_EQ(2, row->GetOffset());1182 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1183 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1184 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1185 1186 EXPECT_TRUE(row->GetRegisterInfo(k_r14, regloc));1187 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1188 EXPECT_EQ(-16, regloc.GetOffset());1189}1190 1191TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {1192 UnwindPlan::Row::AbstractRegisterLocation regloc;1193 const UnwindPlan::Row *row;1194 1195 uint8_t data[] = {1196 0x41, 0x55, // pushq %r131197 0x90 // nop1198 };1199 1200 AddressRange sample_range(0x1000, sizeof(data));1201 UnwindPlan unwind_plan(eRegisterKindLLDB);1202 1203 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1204 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1205 data, sizeof(data), sample_range, unwind_plan));1206 1207 row = unwind_plan.GetRowForFunctionOffset(2);1208 1209 EXPECT_EQ(2, row->GetOffset());1210 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1211 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1212 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1213 1214 EXPECT_TRUE(row->GetRegisterInfo(k_r13, regloc));1215 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1216 EXPECT_EQ(-16, regloc.GetOffset());1217}1218 1219TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {1220 UnwindPlan::Row::AbstractRegisterLocation regloc;1221 const UnwindPlan::Row *row;1222 1223 uint8_t data[] = {1224 0x41, 0x54, // pushq %r131225 0x90 // nop1226 };1227 1228 AddressRange sample_range(0x1000, sizeof(data));1229 UnwindPlan unwind_plan(eRegisterKindLLDB);1230 1231 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1232 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1233 data, sizeof(data), sample_range, unwind_plan));1234 1235 row = unwind_plan.GetRowForFunctionOffset(2);1236 1237 EXPECT_EQ(2, row->GetOffset());1238 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1239 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1240 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1241 1242 EXPECT_TRUE(row->GetRegisterInfo(k_r12, regloc));1243 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1244 EXPECT_EQ(-16, regloc.GetOffset());1245}1246 1247TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {1248 UnwindPlan::Row::AbstractRegisterLocation regloc;1249 const UnwindPlan::Row *row;1250 1251 uint8_t data[] = {1252 0x53, // pushq %rbx1253 0x90 // nop1254 };1255 1256 AddressRange sample_range(0x1000, sizeof(data));1257 UnwindPlan unwind_plan(eRegisterKindLLDB);1258 1259 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1260 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1261 data, sizeof(data), sample_range, unwind_plan));1262 1263 row = unwind_plan.GetRowForFunctionOffset(1);1264 1265 EXPECT_EQ(1, row->GetOffset());1266 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1267 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1268 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1269 1270 EXPECT_TRUE(row->GetRegisterInfo(k_rbx, regloc));1271 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1272 EXPECT_EQ(-16, regloc.GetOffset());1273}1274 1275// The ABI is hardcoded in x86AssemblyInspectionEngine such that1276// eax, ecx, edx are all considered volatile and push/pops of them are1277// not tracked (except to keep track of stack pointer movement)1278TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) {1279 UnwindPlan::Row::AbstractRegisterLocation regloc;1280 const UnwindPlan::Row *row;1281 AddressRange sample_range;1282 UnwindPlan unwind_plan(eRegisterKindLLDB);1283 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1284 1285 uint8_t data[] = {1286 0x50, // pushl %eax1287 0x90 // nop1288 };1289 1290 sample_range = AddressRange(0x1000, sizeof(data));1291 1292 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1293 data, sizeof(data), sample_range, unwind_plan));1294 1295 row = unwind_plan.GetRowForFunctionOffset(1);1296 EXPECT_EQ(1, row->GetOffset());1297 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);1298 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1299 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1300 1301 EXPECT_FALSE(row->GetRegisterInfo(k_eax, regloc));1302}1303 1304// The ABI is hardcoded in x86AssemblyInspectionEngine such that1305// eax, ecx, edx are all considered volatile and push/pops of them are1306// not tracked (except to keep track of stack pointer movement)1307TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) {1308 UnwindPlan::Row::AbstractRegisterLocation regloc;1309 const UnwindPlan::Row *row;1310 AddressRange sample_range;1311 UnwindPlan unwind_plan(eRegisterKindLLDB);1312 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1313 1314 uint8_t data[] = {1315 0x51, // pushl %ecx1316 0x90 // nop1317 };1318 1319 sample_range = AddressRange(0x1000, sizeof(data));1320 1321 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1322 data, sizeof(data), sample_range, unwind_plan));1323 1324 row = unwind_plan.GetRowForFunctionOffset(1);1325 EXPECT_EQ(1, row->GetOffset());1326 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);1327 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1328 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1329 1330 EXPECT_FALSE(row->GetRegisterInfo(k_ecx, regloc));1331}1332 1333// The ABI is hardcoded in x86AssemblyInspectionEngine such that1334// eax, ecx, edx are all considered volatile and push/pops of them are1335// not tracked (except to keep track of stack pointer movement)1336TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) {1337 UnwindPlan::Row::AbstractRegisterLocation regloc;1338 const UnwindPlan::Row *row;1339 AddressRange sample_range;1340 UnwindPlan unwind_plan(eRegisterKindLLDB);1341 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1342 1343 uint8_t data[] = {1344 0x52, // pushl %edx1345 0x90 // nop1346 };1347 1348 sample_range = AddressRange(0x1000, sizeof(data));1349 1350 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1351 data, sizeof(data), sample_range, unwind_plan));1352 1353 row = unwind_plan.GetRowForFunctionOffset(1);1354 EXPECT_EQ(1, row->GetOffset());1355 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);1356 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1357 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1358 1359 EXPECT_FALSE(row->GetRegisterInfo(k_edx, regloc));1360}1361 1362TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {1363 UnwindPlan::Row::AbstractRegisterLocation regloc;1364 const UnwindPlan::Row *row;1365 AddressRange sample_range;1366 UnwindPlan unwind_plan(eRegisterKindLLDB);1367 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1368 1369 uint8_t data[] = {1370 0x53, // pushl %ebx1371 0x90 // nop1372 };1373 1374 sample_range = AddressRange(0x1000, sizeof(data));1375 1376 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1377 data, sizeof(data), sample_range, unwind_plan));1378 1379 row = unwind_plan.GetRowForFunctionOffset(1);1380 EXPECT_EQ(1, row->GetOffset());1381 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);1382 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1383 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1384 1385 EXPECT_TRUE(row->GetRegisterInfo(k_ebx, regloc));1386 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1387 EXPECT_EQ(-8, regloc.GetOffset());1388}1389 1390TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {1391 UnwindPlan::Row::AbstractRegisterLocation regloc;1392 const UnwindPlan::Row *row;1393 AddressRange sample_range;1394 UnwindPlan unwind_plan(eRegisterKindLLDB);1395 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1396 1397 uint8_t data[] = {1398 0x55, // pushl %ebp1399 0x90 // nop1400 };1401 1402 sample_range = AddressRange(0x1000, sizeof(data));1403 1404 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1405 data, sizeof(data), sample_range, unwind_plan));1406 1407 row = unwind_plan.GetRowForFunctionOffset(1);1408 EXPECT_EQ(1, row->GetOffset());1409 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);1410 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1411 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1412 1413 EXPECT_TRUE(row->GetRegisterInfo(k_ebp, regloc));1414 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1415 EXPECT_EQ(-8, regloc.GetOffset());1416}1417 1418TEST_F(Testx86AssemblyInspectionEngine, TestPushRBPWithREX) {1419 UnwindPlan::Row::AbstractRegisterLocation regloc;1420 const UnwindPlan::Row *row;1421 1422 uint8_t data[] = {1423 0x40, 0x55, // pushq %rbp1424 0x90 // nop1425 };1426 1427 AddressRange sample_range(0x1000, sizeof(data));1428 UnwindPlan unwind_plan(eRegisterKindLLDB);1429 1430 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1431 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1432 data, sizeof(data), sample_range, unwind_plan));1433 1434 row = unwind_plan.GetRowForFunctionOffset(2);1435 1436 EXPECT_EQ(2, row->GetOffset());1437 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1438 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1439 EXPECT_EQ(16, row->GetCFAValue().GetOffset());1440 1441 EXPECT_TRUE(row->GetRegisterInfo(k_rbp, regloc));1442 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1443 EXPECT_EQ(-16, regloc.GetOffset());1444}1445 1446TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {1447 UnwindPlan::Row::AbstractRegisterLocation regloc;1448 const UnwindPlan::Row *row;1449 AddressRange sample_range;1450 UnwindPlan unwind_plan(eRegisterKindLLDB);1451 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1452 1453 uint8_t data[] = {1454 0x56, // pushl %esi1455 0x90 // nop1456 };1457 1458 sample_range = AddressRange(0x1000, sizeof(data));1459 1460 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1461 data, sizeof(data), sample_range, unwind_plan));1462 1463 row = unwind_plan.GetRowForFunctionOffset(1);1464 EXPECT_EQ(1, row->GetOffset());1465 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);1466 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1467 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1468 1469 EXPECT_TRUE(row->GetRegisterInfo(k_esi, regloc));1470 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1471 EXPECT_EQ(-8, regloc.GetOffset());1472}1473 1474TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {1475 UnwindPlan::Row::AbstractRegisterLocation regloc;1476 const UnwindPlan::Row *row;1477 AddressRange sample_range;1478 UnwindPlan unwind_plan(eRegisterKindLLDB);1479 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1480 1481 uint8_t data[] = {1482 0x57, // pushl %edi1483 0x90 // nop1484 };1485 1486 sample_range = AddressRange(0x1000, sizeof(data));1487 1488 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1489 data, sizeof(data), sample_range, unwind_plan));1490 1491 row = unwind_plan.GetRowForFunctionOffset(1);1492 EXPECT_EQ(1, row->GetOffset());1493 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);1494 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1495 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1496 1497 EXPECT_TRUE(row->GetRegisterInfo(k_edi, regloc));1498 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());1499 EXPECT_EQ(-8, regloc.GetOffset());1500}1501 1502TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {1503 UnwindPlan::Row::AbstractRegisterLocation regloc;1504 const UnwindPlan::Row *row;1505 1506 uint8_t data64_1[] = {1507 0x48, 0x8b, 0xec, // movq %rsp, %rbp1508 0x90 // nop1509 };1510 1511 AddressRange sample_range(0x1000, sizeof(data64_1));1512 UnwindPlan unwind_plan(eRegisterKindLLDB);1513 1514 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1515 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1516 data64_1, sizeof(data64_1), sample_range, unwind_plan));1517 1518 row = unwind_plan.GetRowForFunctionOffset(3);1519 1520 EXPECT_EQ(3, row->GetOffset());1521 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);1522 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1523 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1524 1525 uint8_t data64_2[] = {1526 0x48, 0x89, 0xe5, // movq %rsp, %rbp1527 0x90 // nop1528 };1529 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));1534 1535 row = unwind_plan.GetRowForFunctionOffset(3);1536 EXPECT_EQ(3, row->GetOffset());1537 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);1538 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1539 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1540 1541 uint8_t data32_1[] = {1542 0x8b, 0xec, // movl %rsp, %rbp1543 0x90 // nop1544 };1545 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));1550 1551 row = unwind_plan.GetRowForFunctionOffset(2);1552 EXPECT_EQ(2, row->GetOffset());1553 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);1554 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1555 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1556 1557 uint8_t data32_2[] = {1558 0x89, 0xe5, // movl %rsp, %rbp1559 0x90 // nop1560 };1561 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));1566 1567 row = unwind_plan.GetRowForFunctionOffset(2);1568 EXPECT_EQ(2, row->GetOffset());1569 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);1570 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1571 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1572}1573 1574TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {1575 UnwindPlan::Row::AbstractRegisterLocation regloc;1576 const UnwindPlan::Row *row;1577 AddressRange sample_range;1578 UnwindPlan unwind_plan(eRegisterKindLLDB);1579 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1580 1581 uint8_t data1[] = {1582 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp1583 0x90 // nop1584 };1585 1586 sample_range = AddressRange(0x1000, sizeof(data1));1587 1588 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1589 data1, sizeof(data1), sample_range, unwind_plan));1590 1591 row = unwind_plan.GetRowForFunctionOffset(7);1592 EXPECT_EQ(7, row->GetOffset());1593 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1594 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1595 EXPECT_EQ(264, row->GetCFAValue().GetOffset());1596 1597 uint8_t data2[] = {1598 0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp1599 0x90 // nop1600 };1601 1602 sample_range = AddressRange(0x1000, sizeof(data2));1603 1604 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1605 data2, sizeof(data2), sample_range, unwind_plan));1606 1607 row = unwind_plan.GetRowForFunctionOffset(4);1608 EXPECT_EQ(4, row->GetOffset());1609 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1610 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1611 EXPECT_EQ(24, row->GetCFAValue().GetOffset());1612}1613 1614TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {1615 UnwindPlan::Row::AbstractRegisterLocation regloc;1616 const UnwindPlan::Row *row;1617 AddressRange sample_range;1618 UnwindPlan unwind_plan(eRegisterKindLLDB);1619 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1620 1621 uint8_t data1[] = {1622 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp1623 0x90 // nop1624 };1625 1626 sample_range = AddressRange(0x1000, sizeof(data1));1627 1628 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1629 data1, sizeof(data1), sample_range, unwind_plan));1630 1631 row = unwind_plan.GetRowForFunctionOffset(6);1632 EXPECT_EQ(6, row->GetOffset());1633 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1634 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1635 EXPECT_EQ(260, row->GetCFAValue().GetOffset());1636 1637 uint8_t data2[] = {1638 0x83, 0xec, 0x10, // subq $0x10, %esp1639 0x90 // nop1640 };1641 1642 sample_range = AddressRange(0x1000, sizeof(data2));1643 1644 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1645 data2, sizeof(data2), sample_range, unwind_plan));1646 1647 row = unwind_plan.GetRowForFunctionOffset(3);1648 EXPECT_EQ(3, row->GetOffset());1649 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1650 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1651 EXPECT_EQ(20, row->GetCFAValue().GetOffset());1652}1653 1654TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {1655 UnwindPlan::Row::AbstractRegisterLocation regloc;1656 const UnwindPlan::Row *row;1657 AddressRange sample_range;1658 UnwindPlan unwind_plan(eRegisterKindLLDB);1659 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();1660 1661 uint8_t data1[] = {1662 0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp1663 0x90 // nop1664 };1665 1666 sample_range = AddressRange(0x1000, sizeof(data1));1667 1668 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1669 data1, sizeof(data1), sample_range, unwind_plan));1670 1671 row = unwind_plan.GetRowForFunctionOffset(7);1672 EXPECT_EQ(7, row->GetOffset());1673 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1674 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1675 EXPECT_EQ(8 - 256, row->GetCFAValue().GetOffset());1676 1677 uint8_t data2[] = {1678 0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp1679 0x90 // nop1680 };1681 1682 sample_range = AddressRange(0x1000, sizeof(data2));1683 1684 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(1685 data2, sizeof(data2), sample_range, unwind_plan));1686 1687 row = unwind_plan.GetRowForFunctionOffset(4);1688 EXPECT_EQ(4, row->GetOffset());1689 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1690 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1691 EXPECT_EQ(8 - 16, row->GetCFAValue().GetOffset());1692}1693 1694TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {1695 UnwindPlan::Row::AbstractRegisterLocation regloc;1696 const UnwindPlan::Row *row;1697 AddressRange sample_range;1698 UnwindPlan unwind_plan(eRegisterKindLLDB);1699 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();1700 1701 uint8_t data1[] = {1702 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp1703 0x90 // nop1704 };1705 1706 sample_range = AddressRange(0x1000, sizeof(data1));1707 1708 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1709 data1, sizeof(data1), sample_range, unwind_plan));1710 1711 row = unwind_plan.GetRowForFunctionOffset(6);1712 EXPECT_EQ(6, row->GetOffset());1713 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1714 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1715 EXPECT_EQ(4 - 256, row->GetCFAValue().GetOffset());1716 1717 uint8_t data2[] = {1718 0x83, 0xc4, 0x10, // addq $0x10, %esp1719 0x90 // nop1720 };1721 1722 sample_range = AddressRange(0x1000, sizeof(data2));1723 1724 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(1725 data2, sizeof(data2), sample_range, unwind_plan));1726 1727 row = unwind_plan.GetRowForFunctionOffset(3);1728 EXPECT_EQ(3, row->GetOffset());1729 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1730 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1731 EXPECT_EQ(4 - 16, row->GetCFAValue().GetOffset());1732}1733 1734TEST_F(Testx86AssemblyInspectionEngine, TestLEA_RSP_Pattern) {1735 UnwindPlan::Row::AbstractRegisterLocation regloc;1736 const UnwindPlan::Row *row;1737 AddressRange sample_range;1738 UnwindPlan unwind_plan(eRegisterKindLLDB);1739 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();1740 1741 uint8_t data[] = {1742 0x8d, 0x64, 0x24, 0x10, // lea rsp, [rsp + 0x10]1743 0x90 // nop1744 };1745 1746 sample_range = AddressRange(0x1000, sizeof(data));1747 1748 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1749 data, sizeof(data), sample_range, unwind_plan));1750 1751 row = unwind_plan.GetRowForFunctionOffset(0);1752 EXPECT_EQ(0, row->GetOffset());1753 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1754 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1755 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1756}1757 1758TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {1759 UnwindPlan::Row::AbstractRegisterLocation regloc;1760 const UnwindPlan::Row *row;1761 AddressRange sample_range;1762 UnwindPlan unwind_plan(eRegisterKindLLDB);1763 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();1764 1765 uint8_t data[] = {1766 0x53, // pushq %rbx1767 0x5b, // popq %rbx1768 0x90 // nop1769 };1770 1771 sample_range = AddressRange(0x1000, sizeof(data));1772 1773 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1774 data, sizeof(data), sample_range, unwind_plan));1775 1776 row = unwind_plan.GetRowForFunctionOffset(2);1777 EXPECT_EQ(2, row->GetOffset());1778 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1779 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1780 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1781 EXPECT_FALSE(row->GetRegisterInfo(k_rbx, regloc));1782}1783 1784TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {1785 UnwindPlan::Row::AbstractRegisterLocation regloc;1786 const UnwindPlan::Row *row;1787 AddressRange sample_range;1788 UnwindPlan unwind_plan(eRegisterKindLLDB);1789 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();1790 1791 uint8_t data[] = {1792 0x55, // pushq %rbp1793 0x5d, // popq %rbp1794 0x90 // nop1795 };1796 1797 sample_range = AddressRange(0x1000, sizeof(data));1798 1799 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1800 data, sizeof(data), sample_range, unwind_plan));1801 1802 row = unwind_plan.GetRowForFunctionOffset(2);1803 EXPECT_EQ(2, row->GetOffset());1804 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1805 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1806 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1807 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));1808}1809 1810TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {1811 UnwindPlan::Row::AbstractRegisterLocation regloc;1812 const UnwindPlan::Row *row;1813 AddressRange sample_range;1814 UnwindPlan unwind_plan(eRegisterKindLLDB);1815 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();1816 1817 uint8_t data[] = {1818 0x41, 0x54, // pushq %r121819 0x41, 0x5c, // popq %r121820 0x90 // nop1821 };1822 1823 sample_range = AddressRange(0x1000, sizeof(data));1824 1825 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1826 data, sizeof(data), sample_range, unwind_plan));1827 1828 row = unwind_plan.GetRowForFunctionOffset(4);1829 EXPECT_EQ(4, row->GetOffset());1830 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1831 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1832 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1833 EXPECT_FALSE(row->GetRegisterInfo(k_r12, regloc));1834}1835 1836TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {1837 UnwindPlan::Row::AbstractRegisterLocation regloc;1838 const UnwindPlan::Row *row;1839 AddressRange sample_range;1840 UnwindPlan unwind_plan(eRegisterKindLLDB);1841 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();1842 1843 uint8_t data[] = {1844 0x41, 0x55, // pushq %r131845 0x41, 0x5d, // popq %r131846 0x90 // nop1847 };1848 1849 sample_range = AddressRange(0x1000, sizeof(data));1850 1851 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1852 data, sizeof(data), sample_range, unwind_plan));1853 1854 row = unwind_plan.GetRowForFunctionOffset(4);1855 EXPECT_EQ(4, row->GetOffset());1856 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1857 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1858 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1859 EXPECT_FALSE(row->GetRegisterInfo(k_r13, regloc));1860}1861 1862TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {1863 UnwindPlan::Row::AbstractRegisterLocation regloc;1864 const UnwindPlan::Row *row;1865 AddressRange sample_range;1866 UnwindPlan unwind_plan(eRegisterKindLLDB);1867 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();1868 1869 uint8_t data[] = {1870 0x41, 0x56, // pushq %r141871 0x41, 0x5e, // popq %r141872 0x90 // nop1873 };1874 1875 sample_range = AddressRange(0x1000, sizeof(data));1876 1877 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1878 data, sizeof(data), sample_range, unwind_plan));1879 1880 row = unwind_plan.GetRowForFunctionOffset(4);1881 EXPECT_EQ(4, row->GetOffset());1882 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1883 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1884 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1885 EXPECT_FALSE(row->GetRegisterInfo(k_r14, regloc));1886}1887 1888TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {1889 UnwindPlan::Row::AbstractRegisterLocation regloc;1890 const UnwindPlan::Row *row;1891 AddressRange sample_range;1892 UnwindPlan unwind_plan(eRegisterKindLLDB);1893 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();1894 1895 uint8_t data[] = {1896 0x41, 0x57, // pushq %r151897 0x41, 0x5f, // popq %r151898 0x90 // nop1899 };1900 1901 sample_range = AddressRange(0x1000, sizeof(data));1902 1903 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1904 data, sizeof(data), sample_range, unwind_plan));1905 1906 row = unwind_plan.GetRowForFunctionOffset(4);1907 EXPECT_EQ(4, row->GetOffset());1908 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1909 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1910 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1911 EXPECT_FALSE(row->GetRegisterInfo(k_r15, regloc));1912}1913 1914TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {1915 UnwindPlan::Row::AbstractRegisterLocation regloc;1916 const UnwindPlan::Row *row;1917 AddressRange sample_range;1918 UnwindPlan unwind_plan(eRegisterKindLLDB);1919 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();1920 1921 uint8_t data[] = {1922 0x53, // pushl %ebx1923 0x5b, // popl %ebx1924 0x90 // nop1925 };1926 1927 sample_range = AddressRange(0x1000, sizeof(data));1928 1929 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1930 data, sizeof(data), sample_range, unwind_plan));1931 1932 row = unwind_plan.GetRowForFunctionOffset(2);1933 EXPECT_EQ(2, row->GetOffset());1934 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1935 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1936 EXPECT_EQ(4, row->GetCFAValue().GetOffset());1937 EXPECT_FALSE(row->GetRegisterInfo(k_ebx, regloc));1938}1939 1940TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {1941 UnwindPlan::Row::AbstractRegisterLocation regloc;1942 const UnwindPlan::Row *row;1943 AddressRange sample_range;1944 UnwindPlan unwind_plan(eRegisterKindLLDB);1945 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();1946 1947 uint8_t data[] = {1948 0x55, // pushl %ebp1949 0x5d, // popl %ebp1950 0x90 // nop1951 };1952 1953 sample_range = AddressRange(0x1000, sizeof(data));1954 1955 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1956 data, sizeof(data), sample_range, unwind_plan));1957 1958 row = unwind_plan.GetRowForFunctionOffset(2);1959 EXPECT_EQ(2, row->GetOffset());1960 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1961 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1962 EXPECT_EQ(4, row->GetCFAValue().GetOffset());1963 EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));1964}1965 1966TEST_F(Testx86AssemblyInspectionEngine, TestPopRBPWithREX) {1967 UnwindPlan::Row::AbstractRegisterLocation regloc;1968 const UnwindPlan::Row *row;1969 AddressRange sample_range;1970 UnwindPlan unwind_plan(eRegisterKindLLDB);1971 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();1972 1973 uint8_t data[] = {1974 0x40, 0x55, // pushq %rbp1975 0x40, 0x5d, // popq %rbp1976 0x90 // nop1977 };1978 1979 sample_range = AddressRange(0x1000, sizeof(data));1980 1981 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1982 data, sizeof(data), sample_range, unwind_plan));1983 1984 row = unwind_plan.GetRowForFunctionOffset(4);1985 EXPECT_EQ(4, row->GetOffset());1986 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);1987 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);1988 EXPECT_EQ(8, row->GetCFAValue().GetOffset());1989 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));1990}1991 1992TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {1993 UnwindPlan::Row::AbstractRegisterLocation regloc;1994 const UnwindPlan::Row *row;1995 AddressRange sample_range;1996 UnwindPlan unwind_plan(eRegisterKindLLDB);1997 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();1998 1999 uint8_t data[] = {2000 0x56, // pushl %esi2001 0x5e, // popl %esi2002 0x90 // nop2003 };2004 2005 sample_range = AddressRange(0x1000, sizeof(data));2006 2007 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(2008 data, sizeof(data), sample_range, unwind_plan));2009 2010 row = unwind_plan.GetRowForFunctionOffset(2);2011 EXPECT_EQ(2, row->GetOffset());2012 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2013 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2014 EXPECT_EQ(4, row->GetCFAValue().GetOffset());2015 EXPECT_FALSE(row->GetRegisterInfo(k_esi, regloc));2016}2017 2018TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {2019 UnwindPlan::Row::AbstractRegisterLocation regloc;2020 const UnwindPlan::Row *row;2021 AddressRange sample_range;2022 UnwindPlan unwind_plan(eRegisterKindLLDB);2023 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();2024 2025 uint8_t data[] = {2026 0x57, // pushl %edi2027 0x5f, // popl %edi2028 0x90 // nop2029 };2030 2031 sample_range = AddressRange(0x1000, sizeof(data));2032 2033 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(2034 data, sizeof(data), sample_range, unwind_plan));2035 2036 row = unwind_plan.GetRowForFunctionOffset(2);2037 EXPECT_EQ(2, row->GetOffset());2038 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2039 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2040 EXPECT_EQ(4, row->GetCFAValue().GetOffset());2041 EXPECT_FALSE(row->GetRegisterInfo(k_edi, regloc));2042}2043 2044// We don't track these registers, but make sure the CFA address is updated2045// if we're defining the CFA in term of esp.2046TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {2047 UnwindPlan::Row::AbstractRegisterLocation regloc;2048 const UnwindPlan::Row *row;2049 AddressRange sample_range;2050 UnwindPlan unwind_plan(eRegisterKindLLDB);2051 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();2052 2053 uint8_t data[] = {2054 0x0e, // push cs2055 0x16, // push ss2056 0x1e, // push ds2057 0x06, // push es2058 2059 0x07, // pop es2060 0x1f, // pop ds2061 0x17, // pop ss2062 2063 0x90 // nop2064 };2065 2066 sample_range = AddressRange(0x1000, sizeof(data));2067 2068 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(2069 data, sizeof(data), sample_range, unwind_plan));2070 2071 row = unwind_plan.GetRowForFunctionOffset(4);2072 EXPECT_EQ(4, row->GetOffset());2073 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2074 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2075 EXPECT_EQ(20, row->GetCFAValue().GetOffset());2076 2077 row = unwind_plan.GetRowForFunctionOffset(7);2078 EXPECT_EQ(7, row->GetOffset());2079 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2080 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2081 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2082}2083 2084TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {2085 UnwindPlan::Row::AbstractRegisterLocation regloc;2086 const UnwindPlan::Row *row;2087 AddressRange sample_range;2088 UnwindPlan unwind_plan(eRegisterKindLLDB);2089 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();2090 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();2091 2092 uint8_t data[] = {2093 0x55, // push %rbp/ebp2094 0xc9, // leave2095 0x90 // nop2096 };2097 2098 sample_range = AddressRange(0x1000, sizeof(data));2099 2100 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(2101 data, sizeof(data), sample_range, unwind_plan));2102 2103 row = unwind_plan.GetRowForFunctionOffset(2);2104 EXPECT_EQ(2, row->GetOffset());2105 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2106 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2107 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2108 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));2109 2110 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(2111 data, sizeof(data), sample_range, unwind_plan));2112 2113 row = unwind_plan.GetRowForFunctionOffset(2);2114 EXPECT_EQ(2, row->GetOffset());2115 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2116 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2117 EXPECT_EQ(4, row->GetCFAValue().GetOffset());2118 EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));2119}2120 2121// In i386, which lacks pc-relative addressing, a common code sequence2122// is to call the next instruction (i.e. call imm32, value of 0) which2123// pushes the addr of the next insn on the stack, and then pop that value2124// into a register (the "pic base" register).2125TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {2126 UnwindPlan::Row::AbstractRegisterLocation regloc;2127 const UnwindPlan::Row *row;2128 AddressRange sample_range;2129 UnwindPlan unwind_plan(eRegisterKindLLDB);2130 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();2131 2132 uint8_t data[] = {2133 0xe8, 0x00, 0x00, 0x00, 0x00, // call 02134 0x90 // nop2135 };2136 2137 sample_range = AddressRange(0x1000, sizeof(data));2138 2139 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(2140 data, sizeof(data), sample_range, unwind_plan));2141 2142 row = unwind_plan.GetRowForFunctionOffset(5);2143 EXPECT_EQ(5, row->GetOffset());2144 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2145 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2146 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2147 EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));2148}2149 2150TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {2151 UnwindPlan::Row::AbstractRegisterLocation regloc;2152 const UnwindPlan::Row *row;2153 AddressRange sample_range;2154 UnwindPlan unwind_plan(eRegisterKindLLDB);2155 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();2156 2157 uint8_t data[] = {2158 0x55, // pushq %rbp2159 0x48, 0x89, 0xe5, // movq %rsp, %rbp2160 0x4c, 0x89, 0x75, 0xc0, // movq %r14, -0x40(%rbp)2161 0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq %r15, -0x5d8(%rbp)2162 0x48, 0x89, 0x5d, 0xb8, // movq %rbx, -0x48(%rbp)2163 0x90 // nop2164 };2165 2166 sample_range = AddressRange(0x1000, sizeof(data));2167 2168 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(2169 data, sizeof(data), sample_range, unwind_plan));2170 2171 row = unwind_plan.GetRowForFunctionOffset(19);2172 EXPECT_EQ(19, row->GetOffset());2173 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2174 EXPECT_EQ(16, row->GetCFAValue().GetOffset());2175 2176 EXPECT_TRUE(row->GetRegisterInfo(k_r14, regloc));2177 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2178 EXPECT_EQ(-80, regloc.GetOffset());2179 2180 EXPECT_TRUE(row->GetRegisterInfo(k_r15, regloc));2181 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2182 EXPECT_EQ(-1512, regloc.GetOffset());2183 2184 EXPECT_TRUE(row->GetRegisterInfo(k_rbx, regloc));2185 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2186 EXPECT_EQ(-88, regloc.GetOffset());2187}2188 2189TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {2190 UnwindPlan::Row::AbstractRegisterLocation regloc;2191 const UnwindPlan::Row *row;2192 AddressRange sample_range;2193 UnwindPlan unwind_plan(eRegisterKindLLDB);2194 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();2195 2196 uint8_t data[] = {2197 0x55, // pushl %ebp2198 0x89, 0xe5, // movl %esp, %ebp2199 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)2200 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp)2201 0x90 // nop2202 };2203 2204 sample_range = AddressRange(0x1000, sizeof(data));2205 2206 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(2207 data, sizeof(data), sample_range, unwind_plan));2208 2209 row = unwind_plan.GetRowForFunctionOffset(12);2210 EXPECT_EQ(12, row->GetOffset());2211 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2212 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2213 2214 EXPECT_TRUE(row->GetRegisterInfo(k_ebx, regloc));2215 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2216 EXPECT_EQ(-344, regloc.GetOffset());2217 2218 EXPECT_TRUE(row->GetRegisterInfo(k_esi, regloc));2219 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2220 EXPECT_EQ(-40, regloc.GetOffset());2221}2222 2223TEST_F(Testx86AssemblyInspectionEngine, TestSpArithx86_64Augmented) {2224 UnwindPlan::Row::AbstractRegisterLocation regloc;2225 AddressRange sample_range;2226 UnwindPlan unwind_plan(eRegisterKindLLDB);2227 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();2228 2229 uint8_t data[] = {2230 0x55, // pushq %rbp2231 0x48, 0x89, 0xe5, // movq %rsp, %rbp2232 2233 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite2234 // has a bug where it can't augment a function that is just2235 // prologue+epilogue - it needs at least one other instruction2236 // in between.2237 2238 0x90, // nop2239 0x48, 0x81, 0xec, 0x88, 0, 0, 0, // subq $0x88, %rsp2240 0x90, // nop2241 0x48, 0x81, 0xc4, 0x88, 0, 0, 0, // addq $0x88, %rsp2242 2243 0x5d, // popq %rbp2244 0xc3 // retq2245 };2246 2247 sample_range = AddressRange(0x1000, sizeof(data));2248 2249 unwind_plan.SetSourceName("unit testing hand-created unwind plan");2250 unwind_plan.SetPlanValidAddressRanges({sample_range});2251 unwind_plan.SetRegisterKind(eRegisterKindLLDB);2252 2253 {2254 UnwindPlan::Row row;2255 2256 // Describe offset 02257 row.SetOffset(0);2258 row.GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);2259 regloc.SetAtCFAPlusOffset(-8);2260 row.SetRegisterInfo(k_rip, regloc);2261 unwind_plan.AppendRow(row);2262 2263 // Describe offset 12264 row.SetOffset(1);2265 row.GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);2266 regloc.SetAtCFAPlusOffset(-16);2267 row.SetRegisterInfo(k_rbp, regloc);2268 unwind_plan.AppendRow(row);2269 2270 // Describe offset 42271 row.SetOffset(4);2272 row.GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);2273 unwind_plan.AppendRow(row);2274 }2275 2276 RegisterContextSP reg_ctx_sp;2277 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(2278 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));2279 2280 // Before we touch the stack pointer, we should still refer to the2281 // row from after the prologue.2282 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(5);2283 EXPECT_EQ(4, row->GetOffset());2284 2285 // Check the first stack pointer update.2286 row = unwind_plan.GetRowForFunctionOffset(12);2287 EXPECT_EQ(12, row->GetOffset());2288 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2289 EXPECT_EQ(152, row->GetCFAValue().GetOffset());2290 2291 // After the nop, we should still refer to the same row.2292 row = unwind_plan.GetRowForFunctionOffset(13);2293 EXPECT_EQ(12, row->GetOffset());2294 2295 // Check that the second stack pointer update is reflected in the2296 // unwind plan.2297 row = unwind_plan.GetRowForFunctionOffset(20);2298 EXPECT_EQ(20, row->GetOffset());2299 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2300 EXPECT_EQ(16, row->GetCFAValue().GetOffset());2301}2302 2303TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {2304 UnwindPlan::Row::AbstractRegisterLocation regloc;2305 AddressRange sample_range;2306 UnwindPlan unwind_plan(eRegisterKindLLDB);2307 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();2308 2309 uint8_t data[] = {2310 0x55, // pushq %rbp2311 0x48, 0x89, 0xe5, // movq %rsp, %rbp2312 2313 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite2314 // has a bug where it can't augment a function that is just2315 // prologue+epilogue - it needs at least one other instruction2316 // in between.2317 0x90, // nop2318 2319 0x5d, // popq %rbp2320 0xc3 // retq2321 };2322 2323 sample_range = AddressRange(0x1000, sizeof(data));2324 2325 unwind_plan.SetSourceName("unit testing hand-created unwind plan");2326 unwind_plan.SetPlanValidAddressRanges({sample_range});2327 unwind_plan.SetRegisterKind(eRegisterKindLLDB);2328 2329 {2330 UnwindPlan::Row row;2331 2332 // Describe offset 02333 row.SetOffset(0);2334 row.GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);2335 regloc.SetAtCFAPlusOffset(-8);2336 row.SetRegisterInfo(k_rip, regloc);2337 unwind_plan.AppendRow(row);2338 2339 // Describe offset 12340 row.SetOffset(1);2341 row.GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);2342 regloc.SetAtCFAPlusOffset(-16);2343 row.SetRegisterInfo(k_rbp, regloc);2344 unwind_plan.AppendRow(row);2345 2346 // Describe offset 42347 row.SetOffset(4);2348 row.GetCFAValue().SetIsRegisterPlusOffset(k_rbp, 16);2349 unwind_plan.AppendRow(row);2350 }2351 2352 RegisterContextSP reg_ctx_sp;2353 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(2354 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));2355 2356 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(6);2357 EXPECT_EQ(6, row->GetOffset());2358 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2359 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2360 2361 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite2362 // doesn't track register restores (pop'ing a reg value back from2363 // the stack) - it was just written to make stepping work correctly.2364 // Technically we should be able to do the following test, but it2365 // won't work today - the unwind plan will still say that the caller's2366 // rbp is on the stack.2367 // EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));2368}2369 2370TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) {2371 UnwindPlan::Row::AbstractRegisterLocation regloc;2372 AddressRange sample_range;2373 UnwindPlan unwind_plan(eRegisterKindLLDB);2374 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();2375 2376 uint8_t data[] = {2377 0x55, // pushl %ebp2378 0x89, 0xe5, // movl %esp, %ebp2379 2380 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite2381 // has a bug where it can't augment a function that is just2382 // prologue+epilogue - it needs at least one other instruction2383 // in between.2384 0x90, // nop2385 2386 0x5d, // popl %ebp2387 0xc3 // retl2388 };2389 2390 sample_range = AddressRange(0x1000, sizeof(data));2391 2392 unwind_plan.SetSourceName("unit testing hand-created unwind plan");2393 unwind_plan.SetPlanValidAddressRanges({sample_range});2394 unwind_plan.SetRegisterKind(eRegisterKindLLDB);2395 2396 {2397 UnwindPlan::Row row;2398 2399 // Describe offset 02400 row.SetOffset(0);2401 row.GetCFAValue().SetIsRegisterPlusOffset(k_esp, 4);2402 regloc.SetAtCFAPlusOffset(-4);2403 row.SetRegisterInfo(k_eip, regloc);2404 unwind_plan.AppendRow(row);2405 2406 // Describe offset 12407 row.SetOffset(1);2408 row.GetCFAValue().SetIsRegisterPlusOffset(k_esp, 8);2409 regloc.SetAtCFAPlusOffset(-8);2410 row.SetRegisterInfo(k_ebp, regloc);2411 unwind_plan.AppendRow(row);2412 2413 // Describe offset 32414 row.SetOffset(3);2415 row.GetCFAValue().SetIsRegisterPlusOffset(k_ebp, 8);2416 unwind_plan.AppendRow(row);2417 }2418 2419 RegisterContextSP reg_ctx_sp;2420 EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite(2421 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));2422 2423 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(5);2424 EXPECT_EQ(5, row->GetOffset());2425 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);2426 EXPECT_EQ(4, row->GetCFAValue().GetOffset());2427 2428 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite2429 // doesn't track register restores (pop'ing a reg value back from2430 // the stack) - it was just written to make stepping work correctly.2431 // Technically we should be able to do the following test, but it2432 // won't work today - the unwind plan will still say that the caller's2433 // ebp is on the stack.2434 // EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));2435}2436 2437// Check that the i386 disassembler disassembles past an opcode that2438// is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler2439// stops2440// disassembling at that point (long-mode).2441TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {2442 UnwindPlan::Row::AbstractRegisterLocation regloc;2443 const UnwindPlan::Row *row;2444 AddressRange sample_range;2445 UnwindPlan unwind_plan(eRegisterKindLLDB);2446 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();2447 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();2448 2449 uint8_t data[] = {2450 0x43, // incl $ebx --- an invalid opcode in 64-bit mode2451 0x55, // pushl %ebp2452 0x90 // nop2453 };2454 2455 sample_range = AddressRange(0x1000, sizeof(data));2456 2457 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(2458 data, sizeof(data), sample_range, unwind_plan));2459 2460 row = unwind_plan.GetRowForFunctionOffset(2);2461 EXPECT_EQ(2, row->GetOffset());2462 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);2463 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2464 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2465 2466 EXPECT_TRUE(row->GetRegisterInfo(k_ebp, regloc));2467 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2468 EXPECT_EQ(-8, regloc.GetOffset());2469 2470 unwind_plan.Clear();2471 2472 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(2473 data, sizeof(data), sample_range, unwind_plan));2474 2475 row = unwind_plan.GetRowForFunctionOffset(2);2476 EXPECT_EQ(0, row->GetOffset());2477 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2478 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2479 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2480 2481 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));2482}2483 2484TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {2485 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();2486 2487 uint8_t data[] = {2488 0x55, // pushl %ebp2489 0x89, 0xe5, // movl %esp, %ebp2490 0x53, // pushl %ebx2491 0x83, 0xe4, 0xf0, // andl $-16, %esp2492 0x83, 0xec, 0x10, // subl $16, %esp2493 0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp2494 0x5b, // popl %ebx2495 0x5d, // popl %ebp2496 0xc3, // retl2497 };2498 2499 AddressRange sample_range(0x1000, sizeof(data));2500 UnwindPlan plan(eRegisterKindLLDB);2501 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),2502 sample_range, plan));2503 2504 UnwindPlan::Row::FAValue esp_plus_4, esp_plus_8, ebp_plus_8;2505 esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);2506 esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);2507 ebp_plus_8.SetIsRegisterPlusOffset(k_ebp, 8);2508 2509 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());2510 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());2511 for (size_t i = 3; i < sizeof(data) - 2; ++i)2512 EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())2513 << "i: " << i;2514 EXPECT_EQ(esp_plus_4,2515 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());2516}2517 2518TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {2519 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();2520 2521 uint8_t data[] = {2522 0x55, // pushq %rbp2523 0x48, 0x89, 0xe5, // movq %rsp, %rbp2524 0x53, // pushl %rbx2525 0x48, 0x83, 0xe4, 0xf0, // andq $-16, %rsp2526 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp2527 0x48, 0x8d, 0x65, 0xf8, // leaq -8(%rbp), %rsp2528 0x5b, // popq %rbx2529 0x5d, // popq %rbp2530 0xc3, // retq2531 };2532 2533 AddressRange sample_range(0x1000, sizeof(data));2534 UnwindPlan plan(eRegisterKindLLDB);2535 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),2536 sample_range, plan));2537 2538 UnwindPlan::Row::FAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;2539 rsp_plus_8.SetIsRegisterPlusOffset(k_rsp, 8);2540 rsp_plus_16.SetIsRegisterPlusOffset(k_rsp, 16);2541 rbp_plus_16.SetIsRegisterPlusOffset(k_rbp, 16);2542 2543 EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue());2544 EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue());2545 for (size_t i = 4; i < sizeof(data) - 2; ++i)2546 EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue())2547 << "i: " << i;2548 EXPECT_EQ(rsp_plus_8,2549 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());2550}2551 2552TEST_F(Testx86AssemblyInspectionEngine, TestStackRealignMSVC_i386) {2553 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();2554 2555 uint8_t data[] = {2556 0x53, // offset 00 -- pushl %ebx2557 0x8b, 0xdc, // offset 01 -- movl %esp, %ebx2558 0x83, 0xec, 0x08, // offset 03 -- subl $8, %esp2559 0x81, 0xe4, 0x00, 0xff, 0xff, 0xff, // offset 06 -- andl $-256, %esp2560 0x83, 0xc4, 0x04, // offset 12 -- addl $4, %esp2561 0x55, // offset 15 -- pushl %ebp2562 0x8b, 0xec, // offset 16 -- movl %esp, %ebp2563 0x81, 0xec, 0x00, 0x02, 0x00, 0x00, // offset 18 -- subl $512, %esp2564 0x89, 0x7d, 0xfc, // offset 24 -- movl %edi, -4(%ebp)2565 0x8b, 0xe5, // offset 27 -- movl %ebp, %esp2566 0x5d, // offset 29 -- popl %ebp2567 0x8b, 0xe3, // offset 30 -- movl %ebx, %esp2568 0x5b, // offset 32 -- popl %ebx2569 0xc3 // offset 33 -- retl2570 };2571 2572 AddressRange sample_range(0x1000, sizeof(data));2573 UnwindPlan plan(eRegisterKindLLDB);2574 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),2575 sample_range, plan));2576 2577 UnwindPlan::Row::FAValue esp_minus_4, esp_plus_0, esp_plus_4, esp_plus_8,2578 ebx_plus_8, ebp_plus_0;2579 esp_minus_4.SetIsRegisterPlusOffset(k_esp, -4);2580 esp_plus_0.SetIsRegisterPlusOffset(k_esp, 0);2581 esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);2582 esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);2583 ebx_plus_8.SetIsRegisterPlusOffset(k_ebx, 8);2584 ebp_plus_0.SetIsRegisterPlusOffset(k_ebp, 0);2585 2586 // Test CFA2587 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());2588 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());2589 for (size_t i = 3; i < 33; ++i)2590 EXPECT_EQ(ebx_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())2591 << "i: " << i;2592 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(33)->GetCFAValue());2593 2594 // Test AFA2595 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(12)->GetAFAValue());2596 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(15)->GetAFAValue());2597 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(16)->GetAFAValue());2598 for (size_t i = 18; i < 30; ++i)2599 EXPECT_EQ(ebp_plus_0, plan.GetRowForFunctionOffset(i)->GetAFAValue())2600 << "i: " << i;2601 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(30)->GetAFAValue());2602 2603 // Test saved register2604 UnwindPlan::Row::AbstractRegisterLocation reg_loc;2605 EXPECT_TRUE(2606 plan.GetRowForFunctionOffset(27)->GetRegisterInfo(k_edi, reg_loc));2607 EXPECT_TRUE(reg_loc.IsAtAFAPlusOffset());2608 EXPECT_EQ(-4, reg_loc.GetOffset());2609}2610 2611// Give the disassembler random bytes to test that it doesn't exceed2612// the bounds of the array when run under clang's address sanitizer.2613TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) {2614 AddressRange sample_range;2615 UnwindPlan unwind_plan(eRegisterKindLLDB);2616 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();2617 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();2618 2619 uint8_t data[] = {2620 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,2621 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };2622 2623 sample_range = AddressRange(0x1000, sizeof(data));2624 2625 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(2626 data, sizeof(data), sample_range, unwind_plan));2627 2628 unwind_plan.Clear();2629 2630 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(2631 data, sizeof(data), sample_range, unwind_plan));2632 2633}2634 2635TEST_F(Testx86AssemblyInspectionEngine, TestReturnDetect) {2636 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();2637 2638 // Single fragment with all four return forms.2639 // We want to verify that the unwind state is reset after each ret.2640 uint8_t data[] = {2641 0x55, // offset 0 -- pushq %rbp2642 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp2643 0x31, 0xc0, // offset 4 -- xorl %eax, %eax2644 0x5d, // offset 6 -- popq %rbp2645 0xc3, // offset 7 -- retq2646 0x31, 0xc0, // offset 8 -- xorl %eax, %eax2647 0x5d, // offset 10 -- popq %rbp2648 0xcb, // offset 11 -- retf2649 0x31, 0xc0, // offset 12 -- xorl %eax, %eax2650 0x5d, // offset 14 -- popq %rbp2651 0xc2, 0x22, 0x11, // offset 15 -- retq 0x11222652 0x31, 0xc0, // offset 18 -- xorl %eax, %eax2653 0x5d, // offset 20 -- popq %rbp2654 0xca, 0x44, 0x33, // offset 21 -- retf 0x33442655 0x31, 0xc0, // offset 24 -- xorl %eax, %eax2656 };2657 2658 AddressRange sample_range(0x1000, sizeof(data));2659 2660 UnwindPlan unwind_plan(eRegisterKindLLDB);2661 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(2662 data, sizeof(data), sample_range, unwind_plan));2663 2664 // Expect following unwind rows:2665 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2666 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2667 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2668 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2669 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2670 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2671 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2672 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2673 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2674 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2675 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2676 2677 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);2678 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==2679 eLazyBoolYes);2680 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);2681 2682 UnwindPlan::Row::AbstractRegisterLocation regloc;2683 2684 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2685 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(0);2686 EXPECT_EQ(0, row->GetOffset());2687 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2688 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2689 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2690 2691 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2692 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2693 EXPECT_EQ(-8, regloc.GetOffset());2694 2695 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2696 row = unwind_plan.GetRowForFunctionOffset(1);2697 EXPECT_EQ(1, row->GetOffset());2698 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2699 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2700 EXPECT_EQ(16, row->GetCFAValue().GetOffset());2701 2702 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2703 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2704 EXPECT_EQ(-8, regloc.GetOffset());2705 2706 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2707 row = unwind_plan.GetRowForFunctionOffset(4);2708 EXPECT_EQ(4, row->GetOffset());2709 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2710 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2711 EXPECT_EQ(16, row->GetCFAValue().GetOffset());2712 2713 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2714 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2715 EXPECT_EQ(-8, regloc.GetOffset());2716 2717 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2718 row = unwind_plan.GetRowForFunctionOffset(7);2719 EXPECT_EQ(7, row->GetOffset());2720 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2721 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2722 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2723 2724 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2725 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2726 EXPECT_EQ(-8, regloc.GetOffset());2727 2728 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2729 row = unwind_plan.GetRowForFunctionOffset(8);2730 EXPECT_EQ(8, row->GetOffset());2731 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2732 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2733 EXPECT_EQ(16, row->GetCFAValue().GetOffset());2734 2735 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2736 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2737 EXPECT_EQ(-8, regloc.GetOffset());2738 2739 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2740 row = unwind_plan.GetRowForFunctionOffset(11);2741 EXPECT_EQ(11, row->GetOffset());2742 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2743 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2744 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2745 2746 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2747 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2748 EXPECT_EQ(-8, regloc.GetOffset());2749 2750 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2751 row = unwind_plan.GetRowForFunctionOffset(12);2752 EXPECT_EQ(12, row->GetOffset());2753 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2754 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2755 EXPECT_EQ(16, row->GetCFAValue().GetOffset());2756 2757 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2758 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2759 EXPECT_EQ(-8, regloc.GetOffset());2760 2761 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2762 row = unwind_plan.GetRowForFunctionOffset(15);2763 EXPECT_EQ(15, row->GetOffset());2764 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2765 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2766 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2767 2768 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2769 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2770 EXPECT_EQ(-8, regloc.GetOffset());2771 2772 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2773 row = unwind_plan.GetRowForFunctionOffset(18);2774 EXPECT_EQ(18, row->GetOffset());2775 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2776 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2777 EXPECT_EQ(16, row->GetCFAValue().GetOffset());2778 2779 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2780 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2781 EXPECT_EQ(-8, regloc.GetOffset());2782 2783 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2784 row = unwind_plan.GetRowForFunctionOffset(21);2785 EXPECT_EQ(21, row->GetOffset());2786 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2787 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2788 EXPECT_EQ(8, row->GetCFAValue().GetOffset());2789 2790 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2791 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2792 EXPECT_EQ(-8, regloc.GetOffset());2793 2794 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]2795 row = unwind_plan.GetRowForFunctionOffset(24);2796 EXPECT_EQ(24, row->GetOffset());2797 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2798 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2799 EXPECT_EQ(16, row->GetCFAValue().GetOffset());2800 2801 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));2802 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());2803 EXPECT_EQ(-8, regloc.GetOffset());2804}2805 2806 2807// Test mid-function epilogues - the unwind state post-prologue2808// should be re-instated.2809 2810TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {2811 AddressRange sample_range;2812 UnwindPlan unwind_plan(eRegisterKindLLDB);2813 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();2814 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();2815 2816 uint8_t data[] = {2817 0x55, // <+0>: pushq %rbp2818 0x48, 0x89, 0xe5, // <+1>: movq %rsp, %rbp2819 0x48, 0x83, 0xec, 0x70, // <+4>: subq $0x70, %rsp2820 0x90, // <+8>: nop // prologue set up2821 2822 0x74, 0x7, // <+9>: je 7 <+18>2823 0x48, 0x83, 0xc4, 0x70, // <+11>: addq $0x70, %rsp2824 0x5d, // <+15>: popq %rbp2825 0xff, 0xe0, // <+16>: jmpq *%rax // epilogue completed2826 2827 0x90, // <+18>: nop // prologue setup back2828 2829 0x74, 0x8, // <+19>: je 7 <+28>2830 0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp2831 0x5d, // <+25>: popq %rbp2832 0x90, // <+26>: nop // mid-epilogue non-epilogue2833 0xc3, // <+27>: retq // epilogue completed2834 2835 0x90, // <+28>: nop // prologue setup back2836 2837 0x48, 0x83, 0xc4, 0x70, // <+29>: addq $0x70, %rsp2838 0x5d, // <+33>: popq %rbp2839 0xc3, // <+34>: retq // epilogue completed2840 2841 };2842 2843 sample_range = AddressRange(0x1000, sizeof(data));2844 2845 int wordsize = 4;2846 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(2847 data, sizeof(data), sample_range, unwind_plan));2848 2849 // Check that we've unwound the stack after the first mid-function epilogue2850 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]2851 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(16);2852 EXPECT_EQ(16, row->GetOffset());2853 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);2854 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2855 EXPECT_EQ(wordsize, row->GetCFAValue().GetOffset());2856 2857 // Check that we've reinstated the stack frame setup 2858 // unwind instructions after a jmpq *%eax2859 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]2860 row = unwind_plan.GetRowForFunctionOffset(18);2861 EXPECT_EQ(18, row->GetOffset());2862 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);2863 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2864 EXPECT_EQ(wordsize * 2, row->GetCFAValue().GetOffset());2865 2866 // Check that we've reinstated the stack frame setup 2867 // unwind instructions after a mid-function retq2868 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]2869 row = unwind_plan.GetRowForFunctionOffset(28);2870 EXPECT_EQ(28, row->GetOffset());2871 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);2872 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2873 EXPECT_EQ(wordsize * 2, row->GetCFAValue().GetOffset());2874 2875 // After last instruction in the function, verify that2876 // the stack frame has been unwound2877 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]2878 row = unwind_plan.GetRowForFunctionOffset(34);2879 EXPECT_EQ(34, row->GetOffset());2880 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);2881 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2882 EXPECT_EQ(wordsize, row->GetCFAValue().GetOffset());2883 2884 unwind_plan.Clear();2885 2886 wordsize = 8;2887 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(2888 data, sizeof(data), sample_range, unwind_plan));2889 2890 // Check that we've unwound the stack after the first mid-function epilogue2891 // row: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]2892 row = unwind_plan.GetRowForFunctionOffset(16);2893 EXPECT_EQ(16, row->GetOffset());2894 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2895 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2896 EXPECT_EQ(wordsize, row->GetCFAValue().GetOffset());2897 2898 // Check that we've reinstated the stack frame setup 2899 // unwind instructions after a jmpq *%eax2900 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]2901 row = unwind_plan.GetRowForFunctionOffset(18);2902 EXPECT_EQ(18, row->GetOffset());2903 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2904 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2905 EXPECT_EQ(wordsize * 2, row->GetCFAValue().GetOffset());2906 2907 // Check that we've reinstated the stack frame setup 2908 // unwind instructions after a mid-function retq2909 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]2910 row = unwind_plan.GetRowForFunctionOffset(28);2911 EXPECT_EQ(28, row->GetOffset());2912 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);2913 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2914 EXPECT_EQ(wordsize * 2, row->GetCFAValue().GetOffset());2915 2916 // After last instruction in the function, verify that2917 // the stack frame has been unwound2918 // row: CFA=rsp +8 => esp=CFA+0 rip=[CFA-8]2919 row = unwind_plan.GetRowForFunctionOffset(34);2920 EXPECT_EQ(34, row->GetOffset());2921 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);2922 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);2923 EXPECT_EQ(wordsize, row->GetCFAValue().GetOffset());2924}2925