brintos

brintos / llvm-project-archived public Read only

0
0
Text · 44.3 KiB · 6c74860 Raw
1074 lines · cpp
1//===-- TestArm64InstEmulation.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 <vector>13 14#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"15 16#include "lldb/Core/Address.h"17#include "lldb/Core/AddressRange.h"18#include "lldb/Symbol/UnwindPlan.h"19#include "lldb/Target/UnwindAssembly.h"20#include "lldb/Utility/ArchSpec.h"21 22#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"23#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"24#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"25#include "llvm/Support/TargetSelect.h"26 27using namespace lldb;28using namespace lldb_private;29 30class TestArm64InstEmulation : public testing::Test {31public:32  static void SetUpTestCase();33  static void TearDownTestCase();34 35  //  virtual void SetUp() override { }36  //  virtual void TearDown() override { }37 38protected:39};40 41void TestArm64InstEmulation::SetUpTestCase() {42  llvm::InitializeAllTargets();43  llvm::InitializeAllAsmPrinters();44  llvm::InitializeAllTargetMCs();45  llvm::InitializeAllDisassemblers();46  DisassemblerLLVMC::Initialize();47  EmulateInstructionARM64::Initialize();48}49 50void TestArm64InstEmulation::TearDownTestCase() {51  DisassemblerLLVMC::Terminate();52  EmulateInstructionARM64::Terminate();53}54 55TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {56  ArchSpec arch("arm64-apple-ios10");57  std::unique_ptr<UnwindAssemblyInstEmulation> engine(58      static_cast<UnwindAssemblyInstEmulation *>(59          UnwindAssemblyInstEmulation::CreateInstance(arch)));60  ASSERT_NE(nullptr, engine);61 62  const UnwindPlan::Row *row;63  AddressRange sample_range;64  UnwindPlan unwind_plan(eRegisterKindLLDB);65  UnwindPlan::Row::AbstractRegisterLocation regloc;66 67  // 'int main() { }' compiled for arm64-apple-ios with clang68  uint8_t data[] = {69      0xfd, 0x7b, 0xbf, 0xa9, // 0xa9bf7bfd :  stp x29, x30, [sp, #-0x10]!70      0xfd, 0x03, 0x00, 0x91, // 0x910003fd :  mov x29, sp71      0xff, 0x43, 0x00, 0xd1, // 0xd10043ff :  sub sp, sp, #0x1072 73      0xbf, 0x03, 0x00, 0x91, // 0x910003bf :  mov sp, x2974      0xfd, 0x7b, 0xc1, 0xa8, // 0xa8c17bfd :  ldp x29, x30, [sp], #1675      0xc0, 0x03, 0x5f, 0xd6, // 0xd65f03c0 :  ret76  };77 78  // UnwindPlan we expect:79 80  // row[0]:    0: CFA=sp +0 => fp= <same> lr= <same>81  // row[1]:    4: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]82  // row[2]:    8: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]83  // row[2]:   16: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]84  // row[3]:   20: CFA=sp +0 => fp= <same> lr= <same>85 86  sample_range = AddressRange(0x1000, sizeof(data));87 88  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(89      sample_range, data, sizeof(data), unwind_plan));90 91  // CFA=sp +0 => fp= <same> lr= <same>92  row = unwind_plan.GetRowForFunctionOffset(0);93  EXPECT_EQ(0, row->GetOffset());94  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);95  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);96  EXPECT_EQ(0, row->GetCFAValue().GetOffset());97 98  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));99  EXPECT_TRUE(regloc.IsSame());100 101  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));102  EXPECT_TRUE(regloc.IsSame());103 104  // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]105  row = unwind_plan.GetRowForFunctionOffset(4);106  EXPECT_EQ(4, row->GetOffset());107  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);108  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);109  EXPECT_EQ(16, row->GetCFAValue().GetOffset());110 111  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));112  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());113  EXPECT_EQ(-16, regloc.GetOffset());114 115  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));116  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());117  EXPECT_EQ(-8, regloc.GetOffset());118 119  // CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]120  row = unwind_plan.GetRowForFunctionOffset(8);121  EXPECT_EQ(8, row->GetOffset());122  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);123  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);124  EXPECT_EQ(16, row->GetCFAValue().GetOffset());125 126  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));127  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());128  EXPECT_EQ(-16, regloc.GetOffset());129 130  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));131  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());132  EXPECT_EQ(-8, regloc.GetOffset());133 134  // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]135  row = unwind_plan.GetRowForFunctionOffset(16);136  EXPECT_EQ(16, row->GetOffset());137  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);138  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);139  EXPECT_EQ(16, row->GetCFAValue().GetOffset());140 141  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));142  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());143  EXPECT_EQ(-16, regloc.GetOffset());144 145  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));146  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());147  EXPECT_EQ(-8, regloc.GetOffset());148 149  // CFA=sp +0 => fp= <same> lr= <same>150  row = unwind_plan.GetRowForFunctionOffset(20);151  EXPECT_EQ(20, row->GetOffset());152  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);153  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);154  EXPECT_EQ(0, row->GetCFAValue().GetOffset());155 156  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));157  EXPECT_TRUE(regloc.IsSame());158 159  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));160  EXPECT_TRUE(regloc.IsSame());161}162 163TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {164  ArchSpec arch("arm64-apple-ios10");165  std::unique_ptr<UnwindAssemblyInstEmulation> engine(166      static_cast<UnwindAssemblyInstEmulation *>(167          UnwindAssemblyInstEmulation::CreateInstance(arch)));168  ASSERT_NE(nullptr, engine);169 170  const UnwindPlan::Row *row;171  AddressRange sample_range;172  UnwindPlan unwind_plan(eRegisterKindLLDB);173  UnwindPlan::Row::AbstractRegisterLocation regloc;174 175  // disassembly of -[NSPlaceholderString initWithBytes:length:encoding:]176  // from Foundation for iOS.177  uint8_t data[] = {178      0xf6, 0x57, 0xbd, 0xa9, // 0:  0xa9bd57f6 stp x22, x21, [sp, #-48]!179      0xf4, 0x4f, 0x01, 0xa9, // 4:  0xa9014ff4 stp x20, x19, [sp, #16]180      0xfd, 0x7b, 0x02, 0xa9, // 8:  0xa9027bfd stp x29, x30, [sp, #32]181      0xfd, 0x83, 0x00, 0x91, // 12: 0x910083fd add x29, sp, #32182      0xff, 0x43, 0x00, 0xd1, // 16: 0xd10043ff sub sp, sp, #16183 184      // [... function body ...]185      0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop186 187      0xbf, 0x83, 0x00, 0xd1, // 24: 0xd10083bf sub sp, x29, #32188      0xfd, 0x7b, 0x42, 0xa9, // 28: 0xa9427bfd ldp x29, x30, [sp, #32]189      0xf4, 0x4f, 0x41, 0xa9, // 32: 0xa9414ff4 ldp x20, x19, [sp, #16]190      0xf6, 0x57, 0xc3, 0xa8, // 36: 0xa8c357f6 ldp x22, x21, [sp], #48191      0x01, 0x16, 0x09, 0x14, // 40: 0x14091601 b   0x18f640524 ; symbol stub192                              // for: CFStringCreateWithBytes193  };194 195  // UnwindPlan we expect:196  //  0: CFA=sp +0 =>197  //  4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]198  //  8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]199  // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]200  // fp=[CFA-16] lr=[CFA-8]201  // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]202  // fp=[CFA-16] lr=[CFA-8]203 204  // [... function body ...]205 206  // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]207  // fp=[CFA-16] lr=[CFA-8]208  // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=209  // <same> lr= <same>210  // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=211  // <same> lr= <same>212  // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>213  // lr= <same>214 215  sample_range = AddressRange(0x1000, sizeof(data));216 217  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(218      sample_range, data, sizeof(data), unwind_plan));219 220  // 0: CFA=sp +0 =>221  row = unwind_plan.GetRowForFunctionOffset(0);222  EXPECT_EQ(0, row->GetOffset());223  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);224  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);225  EXPECT_EQ(0, row->GetCFAValue().GetOffset());226 227  // 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]228  row = unwind_plan.GetRowForFunctionOffset(4);229  EXPECT_EQ(4, row->GetOffset());230  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);231  EXPECT_EQ(48, row->GetCFAValue().GetOffset());232 233  EXPECT_TRUE(row->GetRegisterInfo(gpr_x21_arm64, regloc));234  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());235  EXPECT_EQ(-40, regloc.GetOffset());236 237  EXPECT_TRUE(row->GetRegisterInfo(gpr_x22_arm64, regloc));238  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());239  EXPECT_EQ(-48, regloc.GetOffset());240 241  // 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]242  row = unwind_plan.GetRowForFunctionOffset(8);243  EXPECT_EQ(8, row->GetOffset());244  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);245  EXPECT_EQ(48, row->GetCFAValue().GetOffset());246 247  EXPECT_TRUE(row->GetRegisterInfo(gpr_x19_arm64, regloc));248  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());249  EXPECT_EQ(-24, regloc.GetOffset());250 251  EXPECT_TRUE(row->GetRegisterInfo(gpr_x20_arm64, regloc));252  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());253  EXPECT_EQ(-32, regloc.GetOffset());254 255  // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]256  // fp=[CFA-16] lr=[CFA-8]257  row = unwind_plan.GetRowForFunctionOffset(12);258  EXPECT_EQ(12, row->GetOffset());259  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);260  EXPECT_EQ(48, row->GetCFAValue().GetOffset());261 262  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));263  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());264  EXPECT_EQ(-16, regloc.GetOffset());265 266  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));267  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());268  EXPECT_EQ(-8, regloc.GetOffset());269 270  // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]271  // fp=[CFA-16] lr=[CFA-8]272  row = unwind_plan.GetRowForFunctionOffset(16);273  EXPECT_EQ(16, row->GetOffset());274  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);275  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);276  EXPECT_EQ(16, row->GetCFAValue().GetOffset());277 278  // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]279  // fp=[CFA-16] lr=[CFA-8]280  row = unwind_plan.GetRowForFunctionOffset(28);281  EXPECT_EQ(28, row->GetOffset());282  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);283  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);284  EXPECT_EQ(48, row->GetCFAValue().GetOffset());285 286  // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=287  // <same> lr= <same>288  row = unwind_plan.GetRowForFunctionOffset(32);289  EXPECT_EQ(32, row->GetOffset());290 291  // I'd prefer if these restored registers were cleared entirely instead of set292  // to IsSame...293  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));294  EXPECT_TRUE(regloc.IsSame());295 296  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));297  EXPECT_TRUE(regloc.IsSame());298 299  // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=300  // <same> lr= <same>301  row = unwind_plan.GetRowForFunctionOffset(36);302  EXPECT_EQ(36, row->GetOffset());303 304  EXPECT_TRUE(row->GetRegisterInfo(gpr_x19_arm64, regloc));305  EXPECT_TRUE(regloc.IsSame());306 307  EXPECT_TRUE(row->GetRegisterInfo(gpr_x20_arm64, regloc));308  EXPECT_TRUE(regloc.IsSame());309 310  // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>311  // lr= <same>312  row = unwind_plan.GetRowForFunctionOffset(40);313  EXPECT_EQ(40, row->GetOffset());314  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);315  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);316  EXPECT_EQ(0, row->GetCFAValue().GetOffset());317 318  EXPECT_TRUE(row->GetRegisterInfo(gpr_x21_arm64, regloc));319  EXPECT_TRUE(regloc.IsSame());320 321  EXPECT_TRUE(row->GetRegisterInfo(gpr_x22_arm64, regloc));322  EXPECT_TRUE(regloc.IsSame());323}324 325TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) {326  ArchSpec arch("arm64-apple-ios10");327  std::unique_ptr<UnwindAssemblyInstEmulation> engine(328      static_cast<UnwindAssemblyInstEmulation *>(329          UnwindAssemblyInstEmulation::CreateInstance(arch)));330  ASSERT_NE(nullptr, engine);331 332  const UnwindPlan::Row *row;333  AddressRange sample_range;334  UnwindPlan unwind_plan(eRegisterKindLLDB);335  UnwindPlan::Row::AbstractRegisterLocation regloc;336 337  // disassembly of JSC::ARM64LogicalImmediate::findBitRange<16u>338  // from JavaScriptcore for iOS.339  uint8_t data[] = {340      0x08, 0x3c, 0x0f, 0x53, //  0: 0x530f3c08 ubfx   w8, w0, #15, #1341      0x68, 0x00, 0x00, 0x39, //  4: 0x39000068 strb   w8, [x3]342      0x08, 0x3c, 0x40, 0xd2, //  8: 0xd2403c08 eor    x8, x0, #0xffff343      0x1f, 0x00, 0x71, 0xf2, // 12: 0xf271001f tst    x0, #0x8000344 345      // [...]346 347      0x3f, 0x01, 0x0c, 0xeb, // 16: 0xeb0c013f cmp    x9, x12348      0x81, 0x00, 0x00, 0x54, // 20: 0x54000081 b.ne +34349      0x5f, 0x00, 0x00, 0xb9, // 24: 0xb900005f str    wzr, [x2]350      0xe0, 0x03, 0x00, 0x32, // 28: 0x320003e0 orr    w0, wzr, #0x1351      0xc0, 0x03, 0x5f, 0xd6, // 32: 0xd65f03c0 ret352      0x89, 0x01, 0x09, 0xca, // 36: 0xca090189 eor    x9, x12, x9353 354      // [...]355 356      0x08, 0x05, 0x00, 0x11, // 40: 0x11000508 add    w8, w8, #0x1357      0x48, 0x00, 0x00, 0xb9, // 44: 0xb9000048 str    w8, [x2]358      0xe0, 0x03, 0x00, 0x32, // 48: 0x320003e0 orr    w0, wzr, #0x1359      0xc0, 0x03, 0x5f, 0xd6, // 52: 0xd65f03c0 ret360      0x00, 0x00, 0x80, 0x52, // 56: 0x52800000 mov    w0, #0x0361      0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret362 363  };364 365  // UnwindPlan we expect:366  //  0: CFA=sp +0 =>367  // (possibly with additional rows at offsets 36 and 56 saying the same thing)368 369  sample_range = AddressRange(0x1000, sizeof(data));370 371  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(372      sample_range, data, sizeof(data), unwind_plan));373 374  // 0: CFA=sp +0 =>375  row = unwind_plan.GetRowForFunctionOffset(0);376  EXPECT_EQ(0, row->GetOffset());377  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);378  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);379  EXPECT_EQ(0, row->GetCFAValue().GetOffset());380 381  row = unwind_plan.GetRowForFunctionOffset(32);382  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);383  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);384  EXPECT_EQ(0, row->GetCFAValue().GetOffset());385 386  EXPECT_FALSE(row->GetRegisterInfo(gpr_x19_arm64, regloc));387  EXPECT_FALSE(row->GetRegisterInfo(gpr_x20_arm64, regloc));388  EXPECT_FALSE(row->GetRegisterInfo(gpr_x21_arm64, regloc));389  EXPECT_FALSE(row->GetRegisterInfo(gpr_x22_arm64, regloc));390  EXPECT_FALSE(row->GetRegisterInfo(gpr_x23_arm64, regloc));391  EXPECT_FALSE(row->GetRegisterInfo(gpr_x24_arm64, regloc));392  EXPECT_FALSE(row->GetRegisterInfo(gpr_x25_arm64, regloc));393  EXPECT_FALSE(row->GetRegisterInfo(gpr_x26_arm64, regloc));394  EXPECT_FALSE(row->GetRegisterInfo(gpr_x27_arm64, regloc));395  EXPECT_FALSE(row->GetRegisterInfo(gpr_x28_arm64, regloc));396 397  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));398  EXPECT_TRUE(regloc.IsSame());399 400  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));401  EXPECT_TRUE(regloc.IsSame());402 403  row = unwind_plan.GetRowForFunctionOffset(36);404  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);405  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);406  EXPECT_EQ(0, row->GetCFAValue().GetOffset());407 408  row = unwind_plan.GetRowForFunctionOffset(52);409  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);410  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);411  EXPECT_EQ(0, row->GetCFAValue().GetOffset());412 413  row = unwind_plan.GetRowForFunctionOffset(56);414  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);415  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);416  EXPECT_EQ(0, row->GetCFAValue().GetOffset());417 418  row = unwind_plan.GetRowForFunctionOffset(60);419  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);420  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);421  EXPECT_EQ(0, row->GetCFAValue().GetOffset());422}423 424TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) {425  ArchSpec arch("arm64-apple-ios10");426  std::unique_ptr<UnwindAssemblyInstEmulation> engine(427      static_cast<UnwindAssemblyInstEmulation *>(428          UnwindAssemblyInstEmulation::CreateInstance(arch)));429  ASSERT_NE(nullptr, engine);430 431  const UnwindPlan::Row *row;432  AddressRange sample_range;433  UnwindPlan unwind_plan(eRegisterKindLLDB);434  UnwindPlan::Row::AbstractRegisterLocation regloc;435 436  // disassembly of mach_msg_sever_once from libsystem_kernel.dylib for iOS.437  uint8_t data[] = {438 439      0xfc, 0x6f, 0xba, 0xa9, //  0: 0xa9ba6ffc stp  x28, x27, [sp, #-0x60]!440      0xfa, 0x67, 0x01, 0xa9, //  4: 0xa90167fa stp  x26, x25, [sp, #0x10]441      0xf8, 0x5f, 0x02, 0xa9, //  8: 0xa9025ff8 stp  x24, x23, [sp, #0x20]442      0xf6, 0x57, 0x03, 0xa9, // 12: 0xa90357f6 stp  x22, x21, [sp, #0x30]443      0xf4, 0x4f, 0x04, 0xa9, // 16: 0xa9044ff4 stp  x20, x19, [sp, #0x40]444      0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp  x29, x30, [sp, #0x50]445      0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add  x29, sp, #0x50446      0xff, 0xc3, 0x00, 0xd1, // 28: 0xd100c3ff sub  sp, sp, #0x30447 448      // mid-function, store x20 & x24 on the stack at a different location.449      // this should not show up in the unwind plan; caller's values are not450      // being saved to stack.451      0xf8, 0x53, 0x01, 0xa9, // 32: 0xa90153f8 stp    x24, x20, [sp, #0x10]452 453      // mid-function, copy x20 and x19 off of the stack -- but not from454      // their original locations.  unwind plan should ignore this.455      0xf4, 0x4f, 0x41, 0xa9, // 36: 0xa9414ff4 ldp  x20, x19, [sp, #0x10]456 457      // epilogue458      0xbf, 0x43, 0x01, 0xd1, // 40: 0xd10143bf sub  sp, x29, #0x50459      0xfd, 0x7b, 0x45, 0xa9, // 44: 0xa9457bfd ldp  x29, x30, [sp, #0x50]460      0xf4, 0x4f, 0x44, 0xa9, // 48: 0xa9444ff4 ldp  x20, x19, [sp, #0x40]461      0xf6, 0x57, 0x43, 0xa9, // 52: 0xa94357f6 ldp  x22, x21, [sp, #0x30]462      0xf8, 0x5f, 0x42, 0xa9, // 56: 0xa9425ff8 ldp  x24, x23, [sp, #0x20]463      0xfa, 0x67, 0x41, 0xa9, // 60: 0xa94167fa ldp  x26, x25, [sp, #0x10]464      0xfc, 0x6f, 0xc6, 0xa8, // 64: 0xa8c66ffc ldp  x28, x27, [sp], #0x60465      0xc0, 0x03, 0x5f, 0xd6, // 68: 0xd65f03c0 ret466  };467 468  // UnwindPlan we expect:469  //   0: CFA=sp +0 =>470  //   4: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96]471  //   8: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]472  //  12: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]473  //  x27=[CFA-88] x28=[CFA-96]474  //  16: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]475  //  x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]476  //  20: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]477  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]478  //  x28=[CFA-96]479  //  24: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]480  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]481  //  x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]482  //  28: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]483  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]484  //  x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]485 486  //  44: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]487  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]488  //  x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]489  //  48: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]490  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]491  //  x28=[CFA-96]492  //  52: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]493  //  x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]494  //  56: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]495  //  x27=[CFA-88] x28=[CFA-96]496  //  60: CFA=sp+96 =>  x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]497  //  64: CFA=sp+96 =>  x27=[CFA-88] x28=[CFA-96]498  //  68: CFA=sp +0 =>499 500  sample_range = AddressRange(0x1000, sizeof(data));501 502  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(503      sample_range, data, sizeof(data), unwind_plan));504 505  row = unwind_plan.GetRowForFunctionOffset(36);506  EXPECT_EQ(28, row->GetOffset());507  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);508  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);509  EXPECT_EQ(16, row->GetCFAValue().GetOffset());510 511  EXPECT_TRUE(row->GetRegisterInfo(gpr_x20_arm64, regloc));512  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());513  EXPECT_EQ(-32, regloc.GetOffset());514 515  row = unwind_plan.GetRowForFunctionOffset(40);516  EXPECT_EQ(28, row->GetOffset());517  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);518  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);519  EXPECT_EQ(16, row->GetCFAValue().GetOffset());520 521  EXPECT_TRUE(row->GetRegisterInfo(gpr_x20_arm64, regloc));522  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());523  EXPECT_EQ(-32, regloc.GetOffset());524}525 526TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) {527  ArchSpec arch("arm64-apple-ios10");528  std::unique_ptr<UnwindAssemblyInstEmulation> engine(529      static_cast<UnwindAssemblyInstEmulation *>(530          UnwindAssemblyInstEmulation::CreateInstance(arch)));531  ASSERT_NE(nullptr, engine);532 533  const UnwindPlan::Row *row;534  AddressRange sample_range;535  UnwindPlan unwind_plan(eRegisterKindLLDB);536  UnwindPlan::Row::AbstractRegisterLocation regloc;537 538  // this file built with clang for iOS arch arm64 optimization -Os539  // #include <stdio.h>540  // double foo(double in) {541  // double arr[32];542  // for (int i = 0; i < 32; i++)543  //   arr[i] = in + i;544  // for (int i = 2; i < 30; i++)545  //   arr[i] = ((((arr[i - 1] * arr[i - 2] * 0.2) + (0.7 * arr[i])) /546  //   ((((arr[i] * 0.73) + 0.65) * (arr[i - 1] + 0.2)) - ((arr[i + 1] + (arr[i]547  //   * 0.32) + 0.52) / 0.3) + (0.531 * arr[i - 2]))) + ((arr[i - 1] + 5) /548  //   ((arr[i + 2] + 0.4) / arr[i])) + (arr[5] * (0.17 + arr[7] * arr[i])) +549  //   ((i > 5 ? (arr[i - 3]) : arr[i - 1]) * 0.263) + (((arr[i - 2] + arr[i -550  //   1]) * 0.3252) + 3.56) - (arr[i + 1] * 0.852311)) * ((arr[i] * 85234.1345)551  //   + (77342.451324 / (arr[i - 2] + arr[i - 1] - 73425341.33455))) + (arr[i]552  //   * 875712013.55) - (arr[i - 1] * 0.5555) - ((arr[i] * (arr[i + 1] +553  //   17342834.44) / 8688200123.555)) + (arr[i - 2] + 8888.888);554  // return arr[16];555  //}556  // int main(int argc, char **argv) { printf("%g\n", foo(argc)); }557 558  // so function foo() uses enough registers that it spills the callee-saved559  // floating point registers.560  uint8_t data[] = {561      // prologue562      0xef, 0x3b, 0xba, 0x6d, //  0: 0x6dba3bef   stp    d15, d14, [sp, #-0x60]!563      0xed, 0x33, 0x01, 0x6d, //  4: 0x6d0133ed   stp    d13, d12, [sp, #0x10]564      0xeb, 0x2b, 0x02, 0x6d, //  8: 0x6d022beb   stp    d11, d10, [sp, #0x20]565      0xe9, 0x23, 0x03, 0x6d, // 12: 0x6d0323e9   stp    d9, d8, [sp, #0x30]566      0xfc, 0x6f, 0x04, 0xa9, // 16: 0xa9046ffc   stp    x28, x27, [sp, #0x40]567      0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd   stp    x29, x30, [sp, #0x50]568      0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd   add    x29, sp, #0x50569      0xff, 0x43, 0x04, 0xd1, // 28: 0xd10443ff   sub    sp, sp, #0x110570 571      // epilogue572      0xbf, 0x43, 0x01, 0xd1, // 32: 0xd10143bf   sub    sp, x29, #0x50573      0xfd, 0x7b, 0x45, 0xa9, // 36: 0xa9457bfd   ldp    x29, x30, [sp, #0x50]574      0xfc, 0x6f, 0x44, 0xa9, // 40: 0xa9446ffc   ldp    x28, x27, [sp, #0x40]575      0xe9, 0x23, 0x43, 0x6d, // 44: 0x6d4323e9   ldp    d9, d8, [sp, #0x30]576      0xeb, 0x2b, 0x42, 0x6d, // 48: 0x6d422beb   ldp    d11, d10, [sp, #0x20]577      0xed, 0x33, 0x41, 0x6d, // 52: 0x6d4133ed   ldp    d13, d12, [sp, #0x10]578      0xef, 0x3b, 0xc6, 0x6c, // 56: 0x6cc63bef   ldp    d15, d14, [sp], #0x60579      0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0   ret580  };581 582  // UnwindPlan we expect:583  //   0: CFA=sp +0 =>584  //   4: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]585  //   8: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]586  //  12: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]587  //  d14=[CFA-88] d15=[CFA-96]588  //  16: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]589  //  d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]590  //  20: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]591  //  d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]592  //  d15=[CFA-96]593  //  24: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]594  //  d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]595  //  d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]596  //  28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]597  //  d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]598  //  d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]599  //  36: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]600  //  d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]601  //  d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]602  //  40: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]603  //  d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]604  //  d15=[CFA-96]605  //  44: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]606  //  d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]607  //  48: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]608  //  d14=[CFA-88] d15=[CFA-96]609  //  52: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]610  //  56: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]611  //  60: CFA=sp +0 =>612 613  sample_range = AddressRange(0x1000, sizeof(data));614 615  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(616      sample_range, data, sizeof(data), unwind_plan));617 618  //  28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]619  //  d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]620  //  d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]621  row = unwind_plan.GetRowForFunctionOffset(28);622  EXPECT_EQ(28, row->GetOffset());623  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);624  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);625  EXPECT_EQ(16, row->GetCFAValue().GetOffset());626 627  EXPECT_TRUE(row->GetRegisterInfo(fpu_d15_arm64, regloc));628  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());629  EXPECT_EQ(-96, regloc.GetOffset());630 631  EXPECT_TRUE(row->GetRegisterInfo(fpu_d14_arm64, regloc));632  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());633  EXPECT_EQ(-88, regloc.GetOffset());634 635  EXPECT_TRUE(row->GetRegisterInfo(fpu_d13_arm64, regloc));636  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());637  EXPECT_EQ(-80, regloc.GetOffset());638 639  EXPECT_TRUE(row->GetRegisterInfo(fpu_d12_arm64, regloc));640  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());641  EXPECT_EQ(-72, regloc.GetOffset());642 643  EXPECT_TRUE(row->GetRegisterInfo(fpu_d11_arm64, regloc));644  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());645  EXPECT_EQ(-64, regloc.GetOffset());646 647  EXPECT_TRUE(row->GetRegisterInfo(fpu_d10_arm64, regloc));648  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());649  EXPECT_EQ(-56, regloc.GetOffset());650 651  EXPECT_TRUE(row->GetRegisterInfo(fpu_d9_arm64, regloc));652  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());653  EXPECT_EQ(-48, regloc.GetOffset());654 655  EXPECT_TRUE(row->GetRegisterInfo(fpu_d8_arm64, regloc));656  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());657  EXPECT_EQ(-40, regloc.GetOffset());658 659  //  60: CFA=sp +0 =>660  row = unwind_plan.GetRowForFunctionOffset(60);661  EXPECT_EQ(60, row->GetOffset());662  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);663  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);664  EXPECT_EQ(0, row->GetCFAValue().GetOffset());665 666  if (row->GetRegisterInfo(fpu_d8_arm64, regloc)) {667    EXPECT_TRUE(regloc.IsSame());668  }669  if (row->GetRegisterInfo(fpu_d9_arm64, regloc)) {670    EXPECT_TRUE(regloc.IsSame());671  }672  if (row->GetRegisterInfo(fpu_d10_arm64, regloc)) {673    EXPECT_TRUE(regloc.IsSame());674  }675  if (row->GetRegisterInfo(fpu_d11_arm64, regloc)) {676    EXPECT_TRUE(regloc.IsSame());677  }678  if (row->GetRegisterInfo(fpu_d12_arm64, regloc)) {679    EXPECT_TRUE(regloc.IsSame());680  }681  if (row->GetRegisterInfo(fpu_d13_arm64, regloc)) {682    EXPECT_TRUE(regloc.IsSame());683  }684  if (row->GetRegisterInfo(fpu_d14_arm64, regloc)) {685    EXPECT_TRUE(regloc.IsSame());686  }687  if (row->GetRegisterInfo(fpu_d15_arm64, regloc)) {688    EXPECT_TRUE(regloc.IsSame());689  }690  if (row->GetRegisterInfo(gpr_x27_arm64, regloc)) {691    EXPECT_TRUE(regloc.IsSame());692  }693  if (row->GetRegisterInfo(gpr_x28_arm64, regloc)) {694    EXPECT_TRUE(regloc.IsSame());695  }696}697 698TEST_F(TestArm64InstEmulation, TestCFARegisterTrackedAcrossJumps) {699  ArchSpec arch("arm64-apple-ios10");700  std::unique_ptr<UnwindAssemblyInstEmulation> engine(701      static_cast<UnwindAssemblyInstEmulation *>(702          UnwindAssemblyInstEmulation::CreateInstance(arch)));703  ASSERT_NE(nullptr, engine);704 705  const UnwindPlan::Row *row;706  AddressRange sample_range;707  UnwindPlan unwind_plan(eRegisterKindLLDB);708  UnwindPlan::Row::AbstractRegisterLocation regloc;709 710  uint8_t data[] = {711      // prologue712      0xf4, 0x4f, 0xbe, 0xa9, //  0: 0xa9be4ff4 stp x20, x19, [sp, #-0x20]!713      0xfd, 0x7b, 0x01, 0xa9, //  4: 0xa9017bfd stp x29, x30, [sp, #0x10]714      0xfd, 0x43, 0x00, 0x91, //  8: 0x910043fd add x29, sp, #0x10715      0xff, 0x43, 0x00, 0xd1, // 12: 0xd10043ff sub sp, sp, #0x10716      // conditional branch over a mid-function epilogue717      0xeb, 0x00, 0x00, 0x54, // 16: 0x540000eb b.lt <+44>718      // mid-function epilogue719      0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f   nop720      0xe0, 0x03, 0x13, 0xaa, // 24: 0xaa1303e0   mov    x0, x19721      0xbf, 0x43, 0x00, 0xd1, // 28: 0xd10043bf   sub    sp, x29, #0x10722      0xfd, 0x7b, 0x41, 0xa9, // 32: 0xa9417bfd   ldp    x29, x30, [sp, #0x10]723      0xf4, 0x4f, 0xc2, 0xa8, // 36: 0xa8c24ff4   ldp    x20, x19, [sp], #0x20724      0xc0, 0x03, 0x5f, 0xd6, // 40: 0xd65f03c0   ret725      // unwind state restored, we're using a frame pointer, let's change the726      // stack pointer and see no change in how the CFA is computed727      0x1f, 0x20, 0x03, 0xd5, // 44: 0xd503201f   nop728      0xff, 0x43, 0x00, 0xd1, // 48: 0xd10043ff   sub    sp, sp, #0x10729      0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f   nop730      // final epilogue731      0xe0, 0x03, 0x13, 0xaa, // 56: 0xaa1303e0   mov    x0, x19732      0xbf, 0x43, 0x00, 0xd1, // 60: 0xd10043bf   sub    sp, x29, #0x10733      0xfd, 0x7b, 0x41, 0xa9, // 64: 0xa9417bfd   ldp    x29, x30, [sp, #0x10]734      0xf4, 0x4f, 0xc2, 0xa8, // 68: 0xa8c24ff4   ldp    x20, x19, [sp], #0x20735      0xc0, 0x03, 0x5f, 0xd6, // 72: 0xd65f03c0   ret736 737      0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f   nop738  };739 740  // UnwindPlan we expect:741  // row[0]:    0: CFA=sp +0 =>742  // row[1]:    4: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32]743  // row[2]:    8: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]744  // row[3]:   12: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]745  // row[4]:   32: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]746  // row[5]:   36: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same>747  // row[6]:   40: CFA=sp +0 => x19= <same> x20= <same> fp= <same> lr= <same> 748  // row[7]:   44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] 749  // row[8]:   64: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] 750  // row[9]:   68: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same> 751  // row[10]:  72: CFA=sp +0 => x19= <same> x20= <same> fp= <same> lr= <same> 752 753  // The specific bug we're looking for is this incorrect CFA definition, 754  // where the InstEmulation is using the $sp value mixed in with $fp, 755  // it looks like this:756  //757  // row[7]:   44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]758  // row[8]:   52: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]759  // row[9]:   68: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same>760 761  sample_range = AddressRange(0x1000, sizeof(data));762 763  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(764      sample_range, data, sizeof(data), unwind_plan));765 766  // Confirm CFA at mid-func epilogue 'ret' is $sp+0767  row = unwind_plan.GetRowForFunctionOffset(40);768  EXPECT_EQ(40, row->GetOffset());769  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);770  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);771  EXPECT_EQ(0, row->GetCFAValue().GetOffset());772 773  // After the 'ret', confirm we're back to the correct CFA of $fp+16774  row = unwind_plan.GetRowForFunctionOffset(44);775  EXPECT_EQ(44, row->GetOffset());776  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);777  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);778  EXPECT_EQ(16, row->GetCFAValue().GetOffset());779 780  // Confirm that we have no additional UnwindPlan rows before the 781  // real epilogue -- we still get the Row at offset 44.782  row = unwind_plan.GetRowForFunctionOffset(60);783  EXPECT_EQ(44, row->GetOffset());784  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);785  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);786  EXPECT_EQ(16, row->GetCFAValue().GetOffset());787 788  // And in the epilogue, confirm that we start by switching back to 789  // defining the CFA in terms of $sp.790  row = unwind_plan.GetRowForFunctionOffset(64);791  EXPECT_EQ(64, row->GetOffset());792  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);793  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);794  EXPECT_EQ(32, row->GetCFAValue().GetOffset());795}796 797TEST_F(TestArm64InstEmulation, TestCFAResetToSP) {798  ArchSpec arch("arm64-apple-ios15");799  std::unique_ptr<UnwindAssemblyInstEmulation> engine(800      static_cast<UnwindAssemblyInstEmulation *>(801          UnwindAssemblyInstEmulation::CreateInstance(arch)));802  ASSERT_NE(nullptr, engine);803 804  const UnwindPlan::Row *row;805  AddressRange sample_range;806  UnwindPlan unwind_plan(eRegisterKindLLDB);807  UnwindPlan::Row::AbstractRegisterLocation regloc;808 809  // The called_from_nodebug() from TestStepNoDebug.py810  // Most of the previous unit tests have $sp being set as811  // $fp plus an offset, and the unwinder recognizes that812  // as a CFA change.  This codegen overwrites $fp and we813  // need to know that CFA is now in terms of $sp.814  uint8_t data[] = {815      // prologue816      0xff, 0x83, 0x00, 0xd1, //  0: 0xd10083ff sub sp, sp, #0x20817      0xfd, 0x7b, 0x01, 0xa9, //  4: 0xa9017bfd stp x29, x30, [sp, #0x10]818      0xfd, 0x43, 0x00, 0x91, //  8: 0x910043fd add x29, sp, #0x10819 820      // epilogue821      0xfd, 0x7b, 0x41, 0xa9, // 12: 0xa9417bfd ldp x29, x30, [sp, #0x10]822      0xff, 0x83, 0x00, 0x91, // 16: 0x910083ff add sp, sp, #0x20823      0xc0, 0x03, 0x5f, 0xd6, // 20: 0xd65f03c0 ret824  };825 826  // UnwindPlan we expect:827  // row[0]:    0: CFA=sp +0 =>828  // row[1]:    4: CFA=sp+32 =>829  // row[2]:    8: CFA=sp+32 => fp=[CFA-16] lr=[CFA-8]830  // row[3]:   12: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]831  // row[4]:   16: CFA=sp+32 => x0= <same> fp= <same> lr= <same>832  // row[5]:   20: CFA=sp +0 => x0= <same> fp= <same> lr= <same>833 834  // The specific issue we're testing for is after the835  // ldp x29, x30, [sp, #0x10]836  // when $fp and $lr have been restored to the original values,837  // the CFA is now set in terms of the stack pointer.  If it is838  // left as being in terms of the frame pointer, $fp now has the839  // caller function's $fp value and our StackID will be wrong etc.840 841  sample_range = AddressRange(0x1000, sizeof(data));842 843  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(844      sample_range, data, sizeof(data), unwind_plan));845 846  // Confirm CFA before epilogue instructions is in terms of $fp847  row = unwind_plan.GetRowForFunctionOffset(12);848  EXPECT_EQ(12, row->GetOffset());849  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);850  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);851 852  // Confirm that after restoring $fp to caller's value, CFA is now in853  // terms of $sp854  row = unwind_plan.GetRowForFunctionOffset(16);855  EXPECT_EQ(16, row->GetOffset());856  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);857  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);858}859 860TEST_F(TestArm64InstEmulation, TestPrologueStartsWithStrD8) {861  ArchSpec arch("aarch64");862  std::unique_ptr<UnwindAssemblyInstEmulation> engine(863      static_cast<UnwindAssemblyInstEmulation *>(864          UnwindAssemblyInstEmulation::CreateInstance(arch)));865  ASSERT_NE(nullptr, engine);866 867  const UnwindPlan::Row *row;868  AddressRange sample_range;869  UnwindPlan unwind_plan(eRegisterKindLLDB);870  UnwindPlan::Row::AbstractRegisterLocation regloc;871 872  // The sample function is built with 'clang --target aarch64 -O1':873  //874  //   int bar(float x);875  //   int foo(float x) {876  //     return bar(x) + bar(x);877  //   }878  //879  // The function uses one floating point register and spills it with880  // 'str d8, [sp, #-0x20]!'.881 882  // clang-format off883  uint8_t data[] = {884      // prologue885      0xe8, 0x0f, 0x1e, 0xfc, //  0: fc1e0fe8    str  d8, [sp, #-0x20]!886      0xfd, 0xfb, 0x00, 0xa9, //  4: a900fbfd    stp  x29, x30, [sp, #0x8]887      0xf3, 0x0f, 0x00, 0xf9, //  8: f9000ff3    str  x19, [sp, #0x18]888      0xfd, 0x23, 0x00, 0x91, // 12: 910023fd    add  x29, sp, #0x8889 890      // epilogue891      0xfd, 0xfb, 0x40, 0xa9, // 16: a940fbfd    ldp  x29, x30, [sp, #0x8]892      0xf3, 0x0f, 0x40, 0xf9, // 20: f9400ff3    ldr  x19, [sp, #0x18]893      0xe8, 0x07, 0x42, 0xfc, // 24: fc4207e8    ldr  d8, [sp], #0x20894      0xc0, 0x03, 0x5f, 0xd6, // 28: d65f03c0    ret895  };896  // clang-format on897 898  // UnwindPlan we expect:899  //   0: CFA=sp +0 =>900  //   4: CFA=sp+32 => d8=[CFA-32]901  //   8: CFA=sp+32 => fp=[CFA-24] lr=[CFA-16] d8=[CFA-32]902  //  12: CFA=sp+32 => x19=[CFA-8] fp=[CFA-24] lr=[CFA-16] d8=[CFA-32]903  //  16: CFA=fp+24 => x19=[CFA-8] fp=[CFA-24] lr=[CFA-16] d8=[CFA-32]904  //  20: CFA=sp+32 => x19=[CFA-8] fp=<same> lr=<same> d8=[CFA-32]905  //  24: CFA=sp+32 => x19=<same> fp=<same> lr=<same> d8=[CFA-32]906  //  28: CFA=sp +0 => x19=<same> fp=<same> lr=<same> d8=<same>907 908  sample_range = AddressRange(0x1000, sizeof(data));909 910  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(911      sample_range, data, sizeof(data), unwind_plan));912 913  //   4: CFA=sp+32 => d8=[CFA-32]914  row = unwind_plan.GetRowForFunctionOffset(4);915  EXPECT_EQ(4, row->GetOffset());916  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);917  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);918  EXPECT_EQ(32, row->GetCFAValue().GetOffset());919 920  EXPECT_TRUE(row->GetRegisterInfo(fpu_d8_arm64, regloc));921  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());922  EXPECT_EQ(-32, regloc.GetOffset());923 924  //  16: CFA=fp+24 => x19=[CFA-8] fp=[CFA-24] lr=[CFA-16] d8=[CFA-32]925  row = unwind_plan.GetRowForFunctionOffset(16);926  EXPECT_EQ(16, row->GetOffset());927  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);928  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);929  EXPECT_EQ(24, row->GetCFAValue().GetOffset());930 931  EXPECT_TRUE(row->GetRegisterInfo(gpr_x19_arm64, regloc));932  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());933  EXPECT_EQ(-8, regloc.GetOffset());934 935  EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));936  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());937  EXPECT_EQ(-24, regloc.GetOffset());938 939  EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));940  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());941  EXPECT_EQ(-16, regloc.GetOffset());942 943  EXPECT_TRUE(row->GetRegisterInfo(fpu_d8_arm64, regloc));944  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());945  EXPECT_EQ(-32, regloc.GetOffset());946 947  //  28: CFA=sp +0 => x19=<same> fp=<same> lr=<same> d8=<same>948  row = unwind_plan.GetRowForFunctionOffset(28);949  EXPECT_EQ(28, row->GetOffset());950  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);951  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);952  EXPECT_EQ(0, row->GetCFAValue().GetOffset());953 954  if (row->GetRegisterInfo(gpr_x19_arm64, regloc)) {955    EXPECT_TRUE(regloc.IsSame());956  }957  if (row->GetRegisterInfo(gpr_fp_arm64, regloc)) {958    EXPECT_TRUE(regloc.IsSame());959  }960  if (row->GetRegisterInfo(gpr_lr_arm64, regloc)) {961    EXPECT_TRUE(regloc.IsSame());962  }963  if (row->GetRegisterInfo(fpu_d8_arm64, regloc)) {964    EXPECT_TRUE(regloc.IsSame());965  }966}967 968TEST_F(TestArm64InstEmulation, TestMidFunctionEpilogueAndBackwardsJump) {969  ArchSpec arch("arm64-apple-ios15");970  std::unique_ptr<UnwindAssemblyInstEmulation> engine(971      static_cast<UnwindAssemblyInstEmulation *>(972          UnwindAssemblyInstEmulation::CreateInstance(arch)));973  ASSERT_NE(nullptr, engine);974 975  const UnwindPlan::Row *row;976  AddressRange sample_range;977  UnwindPlan unwind_plan(eRegisterKindLLDB);978  UnwindPlan::Row::AbstractRegisterLocation regloc;979 980  // clang-format off981  uint8_t data[] = {982      0xff, 0xc3, 0x00, 0xd1, // <+0>:  sub    sp, sp, #0x30983      0xfd, 0x7b, 0x02, 0xa9, // <+4>:  stp    x29, x30, [sp, #0x20]984      0xfd, 0x83, 0x00, 0x91, // <+8>:  add    x29, sp, #0x20985      0x1f, 0x04, 0x00, 0xf1, // <+12>: cmp    x0, #0x1986      0x21, 0x01, 0x00, 0x54, // <+16>: b.ne   ; <+52> DO_SOMETHING_AND_GOTO_AFTER_EPILOGUE987      0xfd, 0x7b, 0x42, 0xa9, // <+20>: ldp    x29, x30, [sp, #0x20]988      0xff, 0xc3, 0x00, 0x91, // <+24>: add    sp, sp, #0x30989      0xc0, 0x03, 0x5f, 0xd6, // <+28>: ret990      // AFTER_EPILOGUE:  LLDB computes the next 5 unwind states incorrectly.991      0x37, 0x00, 0x80, 0xd2, // <+32>: mov    x23, #0x1992      0xf6, 0x5f, 0x41, 0xa9, // <+36>: ldp    x22, x23, [sp, #0x10]993      0xfd, 0x7b, 0x42, 0xa9, // <+40>: ldp    x29, x30, [sp, #0x20]994      0xff, 0xc3, 0x00, 0x91, // <+44>: add    sp, sp, #0x30995      0xc0, 0x03, 0x5f, 0xd6, // <+48>: ret996      // DO_SOMETHING_AND_GOTO_AFTER_EPILOGUE997      0xf6, 0x5f, 0x01, 0xa9, // <+52>: stp    x22, x23, [sp, #0x10]998      0x36, 0x00, 0x80, 0xd2, // <+56>: mov    x22, #0x1999      0x37, 0x00, 0x80, 0xd2, // <+60>: mov    x23, #0x11000      0xf8, 0xff, 0xff, 0x17, // <+64>: b      ; <+32> AFTER_EPILOGUE1001  };1002 1003  // UnwindPlan we expect:1004  // row[0]:    0: CFA=sp +0 =>1005  // row[1]:    4: CFA=sp+48 =>1006  // row[2]:    8: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]1007  // row[3]:   12: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]1008  // row[4]:   24: CFA=sp+48 => fp=<same>   lr=<same>1009  //1010  // This must come from +561011  // row[5]:   32: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8] x22=[CFA-32], x23=[CFA-24]1012  // row[6]:   40: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8] x22=same,     x23 = same1013  // row[6]:   44: CFA=sp+48 => fp=same     lr=same    x22=same,     x23 = same1014  // row[6]:   48: CFA=sp0   => fp=same     lr=same    x22=same,     x23 = same1015  //1016  // row[x]:   52: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]1017  // row[x]:   56: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8] x22=[CFA-32], x23=[CFA-24]1018  // clang-format on1019 1020  sample_range = AddressRange(0x1000, sizeof(data));1021 1022  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(1023      sample_range, data, sizeof(data), unwind_plan));1024 1025  // At the end of prologue (+12), CFA = fp + 16.1026  // <+0>:  sub    sp, sp, #0x301027  // <+4>:  stp    x29, x30, [sp, #0x20]1028  // <+8>:  add    x29, sp, #0x201029  row = unwind_plan.GetRowForFunctionOffset(12);1030  EXPECT_EQ(12, row->GetOffset());1031  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset());1032  EXPECT_EQ(row->GetCFAValue().GetRegisterNumber(), gpr_fp_arm64);1033  EXPECT_EQ(row->GetCFAValue().GetOffset(), 16);1034 1035  // +16 and +20 are the same as +12.1036  // <+12>: cmp    x0, #0x11037  // <+16>: b.ne   ; <+52> DO_SOMETHING_AND_GOTO_AFTER_EPILOGUE1038  EXPECT_EQ(12, unwind_plan.GetRowForFunctionOffset(16)->GetOffset());1039  EXPECT_EQ(12, unwind_plan.GetRowForFunctionOffset(20)->GetOffset());1040 1041  // After restoring $fp to caller's value, CFA = $sp + 481042  // <+20>: ldp    x29, x30, [sp, #0x20]1043  row = unwind_plan.GetRowForFunctionOffset(24);1044  EXPECT_EQ(24, row->GetOffset());1045  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset());1046  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);1047  EXPECT_EQ(row->GetCFAValue().GetOffset(), 48);1048 1049  // $sp has been restored1050  // <+24>: add    sp, sp, #0x301051  row = unwind_plan.GetRowForFunctionOffset(28);1052  EXPECT_EQ(28, row->GetOffset());1053  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset());1054  EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);1055  EXPECT_EQ(row->GetCFAValue().GetOffset(), 0);1056 1057  // FIXME: Row for offset +32 incorrectly inherits the state of the `ret`1058  // instruction, but +32 _never_ executes after the `ret`.1059  // <+28>: ret1060  // <+32>: mov    x23, #0x11061  row = unwind_plan.GetRowForFunctionOffset(32);1062  // FIXME: EXPECT_NE(28, row->GetOffset());1063 1064  // Check that the state of this branch1065  // <+16>: b.ne   ; <+52> DO_SOMETHING_AND_GOTO_AFTER_EPILOGUE1066  // was forwarded to the branch target:1067  // <+52>: stp    x22, x23, [sp, #0x10]1068  row = unwind_plan.GetRowForFunctionOffset(52);1069  EXPECT_EQ(52, row->GetOffset());1070  EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset());1071  EXPECT_EQ(row->GetCFAValue().GetRegisterNumber(), gpr_fp_arm64);1072  EXPECT_EQ(row->GetCFAValue().GetOffset(), 16);1073}1074