15ffd83dbSDimitry Andric //===-- EmulateInstructionARM64.cpp ---------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "EmulateInstructionARM64.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "lldb/Core/Address.h" 120b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h" 130b57cec5SDimitry Andric #include "lldb/Symbol/UnwindPlan.h" 140b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h" 150b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h" 160b57cec5SDimitry Andric #include "lldb/Utility/Stream.h" 170b57cec5SDimitry Andric 185ffd83dbSDimitry Andric #include "llvm/Support/CheckedArithmetic.h" 195ffd83dbSDimitry Andric 200b57cec5SDimitry Andric #include "Plugins/Process/Utility/ARMDefines.h" 210b57cec5SDimitry Andric #include "Plugins/Process/Utility/ARMUtils.h" 220b57cec5SDimitry Andric #include "Plugins/Process/Utility/lldb-arm64-register-enums.h" 230b57cec5SDimitry Andric 2406c3fb27SDimitry Andric #include <algorithm> 255ffd83dbSDimitry Andric #include <cstdlib> 26bdd1243dSDimitry Andric #include <optional> 275ffd83dbSDimitry Andric 280b57cec5SDimitry Andric #define GPR_OFFSET(idx) ((idx)*8) 290b57cec5SDimitry Andric #define GPR_OFFSET_NAME(reg) 0 300b57cec5SDimitry Andric #define FPU_OFFSET(idx) ((idx)*16) 310b57cec5SDimitry Andric #define FPU_OFFSET_NAME(reg) 0 320b57cec5SDimitry Andric #define EXC_OFFSET_NAME(reg) 0 330b57cec5SDimitry Andric #define DBG_OFFSET_NAME(reg) 0 340b57cec5SDimitry Andric #define DBG_OFFSET_NAME(reg) 0 350b57cec5SDimitry Andric #define DEFINE_DBG(re, y) \ 360b57cec5SDimitry Andric "na", nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \ 370b57cec5SDimitry Andric {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ 380b57cec5SDimitry Andric LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, \ 3906c3fb27SDimitry Andric nullptr, nullptr, nullptr 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric #define DECLARE_REGISTER_INFOS_ARM64_STRUCT 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric #include "Plugins/Process/Utility/RegisterInfos_arm64.h" 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 460b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric #include "Plugins/Process/Utility/InstructionUtils.h" 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric using namespace lldb; 510b57cec5SDimitry Andric using namespace lldb_private; 520b57cec5SDimitry Andric 535ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM64, InstructionARM64) 545ffd83dbSDimitry Andric 55bdd1243dSDimitry Andric static std::optional<RegisterInfo> LLDBTableGetRegisterInfo(uint32_t reg_num) { 56bdd1243dSDimitry Andric if (reg_num >= std::size(g_register_infos_arm64_le)) 57bdd1243dSDimitry Andric return {}; 58bdd1243dSDimitry Andric return g_register_infos_arm64_le[reg_num]; 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric #define No_VFP 0 620b57cec5SDimitry Andric #define VFPv1 (1u << 1) 630b57cec5SDimitry Andric #define VFPv2 (1u << 2) 640b57cec5SDimitry Andric #define VFPv3 (1u << 3) 650b57cec5SDimitry Andric #define AdvancedSIMD (1u << 4) 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric #define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD) 680b57cec5SDimitry Andric #define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD) 690b57cec5SDimitry Andric #define VFPv2v3 (VFPv2 | VFPv3) 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric #define UInt(x) ((uint64_t)x) 720b57cec5SDimitry Andric #define SInt(x) ((int64_t)x) 730b57cec5SDimitry Andric #define bit bool 740b57cec5SDimitry Andric #define boolean bool 750b57cec5SDimitry Andric #define integer int64_t 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric static inline bool IsZero(uint64_t x) { return x == 0; } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric static inline uint64_t NOT(uint64_t x) { return ~x; } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric // LSL() 820b57cec5SDimitry Andric // ===== 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric static inline uint64_t LSL(uint64_t x, integer shift) { 850b57cec5SDimitry Andric if (shift == 0) 860b57cec5SDimitry Andric return x; 870b57cec5SDimitry Andric return x << shift; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric // ConstrainUnpredictable() 910b57cec5SDimitry Andric // ======================== 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric EmulateInstructionARM64::ConstraintType 940b57cec5SDimitry Andric ConstrainUnpredictable(EmulateInstructionARM64::Unpredictable which) { 950b57cec5SDimitry Andric EmulateInstructionARM64::ConstraintType result = 960b57cec5SDimitry Andric EmulateInstructionARM64::Constraint_UNKNOWN; 970b57cec5SDimitry Andric switch (which) { 980b57cec5SDimitry Andric case EmulateInstructionARM64::Unpredictable_WBOVERLAP: 990b57cec5SDimitry Andric case EmulateInstructionARM64::Unpredictable_LDPOVERLAP: 1000b57cec5SDimitry Andric // TODO: don't know what to really do here? Pseudo code says: 1010b57cec5SDimitry Andric // set result to one of above Constraint behaviours or UNDEFINED 1020b57cec5SDimitry Andric break; 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric return result; 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric // 1080b57cec5SDimitry Andric // EmulateInstructionARM implementation 1090b57cec5SDimitry Andric // 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric void EmulateInstructionARM64::Initialize() { 1120b57cec5SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 1130b57cec5SDimitry Andric GetPluginDescriptionStatic(), CreateInstance); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric void EmulateInstructionARM64::Terminate() { 1170b57cec5SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 120349cc55cSDimitry Andric llvm::StringRef EmulateInstructionARM64::GetPluginDescriptionStatic() { 1210b57cec5SDimitry Andric return "Emulate instructions for the ARM64 architecture."; 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric EmulateInstruction * 1250b57cec5SDimitry Andric EmulateInstructionARM64::CreateInstance(const ArchSpec &arch, 1260b57cec5SDimitry Andric InstructionType inst_type) { 1270b57cec5SDimitry Andric if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic( 1280b57cec5SDimitry Andric inst_type)) { 1299dba64beSDimitry Andric if (arch.GetTriple().getArch() == llvm::Triple::aarch64 || 1309dba64beSDimitry Andric arch.GetTriple().getArch() == llvm::Triple::aarch64_32) { 1310b57cec5SDimitry Andric return new EmulateInstructionARM64(arch); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric return nullptr; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric bool EmulateInstructionARM64::SetTargetTriple(const ArchSpec &arch) { 1390b57cec5SDimitry Andric if (arch.GetTriple().getArch() == llvm::Triple::arm) 1400b57cec5SDimitry Andric return true; 1410b57cec5SDimitry Andric else if (arch.GetTriple().getArch() == llvm::Triple::thumb) 1420b57cec5SDimitry Andric return true; 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric return false; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 147bdd1243dSDimitry Andric std::optional<RegisterInfo> 148bdd1243dSDimitry Andric EmulateInstructionARM64::GetRegisterInfo(RegisterKind reg_kind, 149bdd1243dSDimitry Andric uint32_t reg_num) { 1500b57cec5SDimitry Andric if (reg_kind == eRegisterKindGeneric) { 1510b57cec5SDimitry Andric switch (reg_num) { 1520b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_PC: 1530b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 1540b57cec5SDimitry Andric reg_num = gpr_pc_arm64; 1550b57cec5SDimitry Andric break; 1560b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_SP: 1570b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 1580b57cec5SDimitry Andric reg_num = gpr_sp_arm64; 1590b57cec5SDimitry Andric break; 1600b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_FP: 1610b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 1620b57cec5SDimitry Andric reg_num = gpr_fp_arm64; 1630b57cec5SDimitry Andric break; 1640b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_RA: 1650b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 1660b57cec5SDimitry Andric reg_num = gpr_lr_arm64; 1670b57cec5SDimitry Andric break; 1680b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_FLAGS: 1690b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 1700b57cec5SDimitry Andric reg_num = gpr_cpsr_arm64; 1710b57cec5SDimitry Andric break; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric default: 174bdd1243dSDimitry Andric return {}; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric if (reg_kind == eRegisterKindLLDB) 179bdd1243dSDimitry Andric return LLDBTableGetRegisterInfo(reg_num); 180bdd1243dSDimitry Andric return {}; 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric EmulateInstructionARM64::Opcode * 1840b57cec5SDimitry Andric EmulateInstructionARM64::GetOpcodeForInstruction(const uint32_t opcode) { 1850b57cec5SDimitry Andric static EmulateInstructionARM64::Opcode g_opcodes[] = { 1860b57cec5SDimitry Andric // Prologue instructions 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric // push register(s) 1890b57cec5SDimitry Andric {0xff000000, 0xd1000000, No_VFP, 1900b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateADDSUBImm, 1910b57cec5SDimitry Andric "SUB <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"}, 1920b57cec5SDimitry Andric {0xff000000, 0xf1000000, No_VFP, 1930b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateADDSUBImm, 1940b57cec5SDimitry Andric "SUBS <Xd>, <Xn|SP>, #<imm> {, <shift>}"}, 1950b57cec5SDimitry Andric {0xff000000, 0x91000000, No_VFP, 1960b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateADDSUBImm, 1970b57cec5SDimitry Andric "ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"}, 1980b57cec5SDimitry Andric {0xff000000, 0xb1000000, No_VFP, 1990b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateADDSUBImm, 2000b57cec5SDimitry Andric "ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}"}, 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric {0xff000000, 0x51000000, No_VFP, 2030b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateADDSUBImm, 2040b57cec5SDimitry Andric "SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"}, 2050b57cec5SDimitry Andric {0xff000000, 0x71000000, No_VFP, 2060b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateADDSUBImm, 2070b57cec5SDimitry Andric "SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"}, 2080b57cec5SDimitry Andric {0xff000000, 0x11000000, No_VFP, 2090b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateADDSUBImm, 2100b57cec5SDimitry Andric "ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"}, 2110b57cec5SDimitry Andric {0xff000000, 0x31000000, No_VFP, 2120b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateADDSUBImm, 2130b57cec5SDimitry Andric "ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"}, 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric {0xffc00000, 0x29000000, No_VFP, 2160b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2170b57cec5SDimitry Andric "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"}, 2180b57cec5SDimitry Andric {0xffc00000, 0xa9000000, No_VFP, 2190b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2200b57cec5SDimitry Andric "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"}, 2210b57cec5SDimitry Andric {0xffc00000, 0x2d000000, No_VFP, 2220b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2230b57cec5SDimitry Andric "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]"}, 2240b57cec5SDimitry Andric {0xffc00000, 0x6d000000, No_VFP, 2250b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2260b57cec5SDimitry Andric "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"}, 2270b57cec5SDimitry Andric {0xffc00000, 0xad000000, No_VFP, 2280b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2290b57cec5SDimitry Andric "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"}, 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric {0xffc00000, 0x29800000, No_VFP, 2320b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2330b57cec5SDimitry Andric "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"}, 2340b57cec5SDimitry Andric {0xffc00000, 0xa9800000, No_VFP, 2350b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2360b57cec5SDimitry Andric "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"}, 2370b57cec5SDimitry Andric {0xffc00000, 0x2d800000, No_VFP, 2380b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2390b57cec5SDimitry Andric "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"}, 2400b57cec5SDimitry Andric {0xffc00000, 0x6d800000, No_VFP, 2410b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2420b57cec5SDimitry Andric "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"}, 2430b57cec5SDimitry Andric {0xffc00000, 0xad800000, No_VFP, 2440b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2450b57cec5SDimitry Andric "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"}, 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric {0xffc00000, 0x28800000, No_VFP, 2480b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 2490b57cec5SDimitry Andric "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"}, 2500b57cec5SDimitry Andric {0xffc00000, 0xa8800000, No_VFP, 2510b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 2520b57cec5SDimitry Andric "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"}, 2530b57cec5SDimitry Andric {0xffc00000, 0x2c800000, No_VFP, 2540b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 2550b57cec5SDimitry Andric "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"}, 2560b57cec5SDimitry Andric {0xffc00000, 0x6c800000, No_VFP, 2570b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 2580b57cec5SDimitry Andric "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"}, 2590b57cec5SDimitry Andric {0xffc00000, 0xac800000, No_VFP, 2600b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 2610b57cec5SDimitry Andric "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"}, 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric {0xffc00000, 0x29400000, No_VFP, 2640b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2650b57cec5SDimitry Andric "LDP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"}, 2660b57cec5SDimitry Andric {0xffc00000, 0xa9400000, No_VFP, 2670b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2680b57cec5SDimitry Andric "LDP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"}, 2690b57cec5SDimitry Andric {0xffc00000, 0x2d400000, No_VFP, 2700b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2710b57cec5SDimitry Andric "LDP <St>, <St2>, [<Xn|SP>{, #<imm>}]"}, 2720b57cec5SDimitry Andric {0xffc00000, 0x6d400000, No_VFP, 2730b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2740b57cec5SDimitry Andric "LDP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"}, 2750b57cec5SDimitry Andric {0xffc00000, 0xad400000, No_VFP, 2760b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>, 2770b57cec5SDimitry Andric "LDP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"}, 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric {0xffc00000, 0x29c00000, No_VFP, 2800b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2810b57cec5SDimitry Andric "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"}, 2820b57cec5SDimitry Andric {0xffc00000, 0xa9c00000, No_VFP, 2830b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2840b57cec5SDimitry Andric "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"}, 2850b57cec5SDimitry Andric {0xffc00000, 0x2dc00000, No_VFP, 2860b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2870b57cec5SDimitry Andric "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"}, 2880b57cec5SDimitry Andric {0xffc00000, 0x6dc00000, No_VFP, 2890b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2900b57cec5SDimitry Andric "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"}, 2910b57cec5SDimitry Andric {0xffc00000, 0xadc00000, No_VFP, 2920b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>, 2930b57cec5SDimitry Andric "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"}, 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric {0xffc00000, 0x28c00000, No_VFP, 2960b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 2970b57cec5SDimitry Andric "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"}, 2980b57cec5SDimitry Andric {0xffc00000, 0xa8c00000, No_VFP, 2990b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 3000b57cec5SDimitry Andric "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"}, 3010b57cec5SDimitry Andric {0xffc00000, 0x2cc00000, No_VFP, 3020b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 3030b57cec5SDimitry Andric "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"}, 3040b57cec5SDimitry Andric {0xffc00000, 0x6cc00000, No_VFP, 3050b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 3060b57cec5SDimitry Andric "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"}, 3070b57cec5SDimitry Andric {0xffc00000, 0xacc00000, No_VFP, 3080b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>, 3090b57cec5SDimitry Andric "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"}, 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric {0xffe00c00, 0xb8000400, No_VFP, 3120b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>, 3130b57cec5SDimitry Andric "STR <Wt>, [<Xn|SP>], #<simm>"}, 3140b57cec5SDimitry Andric {0xffe00c00, 0xf8000400, No_VFP, 3150b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>, 3160b57cec5SDimitry Andric "STR <Xt>, [<Xn|SP>], #<simm>"}, 3170b57cec5SDimitry Andric {0xffe00c00, 0xb8000c00, No_VFP, 3180b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>, 3190b57cec5SDimitry Andric "STR <Wt>, [<Xn|SP>, #<simm>]!"}, 3200b57cec5SDimitry Andric {0xffe00c00, 0xf8000c00, No_VFP, 3210b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>, 3220b57cec5SDimitry Andric "STR <Xt>, [<Xn|SP>, #<simm>]!"}, 3230b57cec5SDimitry Andric {0xffc00000, 0xb9000000, No_VFP, 3240b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>, 3250b57cec5SDimitry Andric "STR <Wt>, [<Xn|SP>{, #<pimm>}]"}, 3260b57cec5SDimitry Andric {0xffc00000, 0xf9000000, No_VFP, 3270b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>, 3280b57cec5SDimitry Andric "STR <Xt>, [<Xn|SP>{, #<pimm>}]"}, 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric {0xffe00c00, 0xb8400400, No_VFP, 3310b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>, 3320b57cec5SDimitry Andric "LDR <Wt>, [<Xn|SP>], #<simm>"}, 3330b57cec5SDimitry Andric {0xffe00c00, 0xf8400400, No_VFP, 3340b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>, 3350b57cec5SDimitry Andric "LDR <Xt>, [<Xn|SP>], #<simm>"}, 3360b57cec5SDimitry Andric {0xffe00c00, 0xb8400c00, No_VFP, 3370b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>, 3380b57cec5SDimitry Andric "LDR <Wt>, [<Xn|SP>, #<simm>]!"}, 3390b57cec5SDimitry Andric {0xffe00c00, 0xf8400c00, No_VFP, 3400b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>, 3410b57cec5SDimitry Andric "LDR <Xt>, [<Xn|SP>, #<simm>]!"}, 3420b57cec5SDimitry Andric {0xffc00000, 0xb9400000, No_VFP, 3430b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>, 3440b57cec5SDimitry Andric "LDR <Wt>, [<Xn|SP>{, #<pimm>}]"}, 3450b57cec5SDimitry Andric {0xffc00000, 0xf9400000, No_VFP, 3460b57cec5SDimitry Andric &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>, 3470b57cec5SDimitry Andric "LDR <Xt>, [<Xn|SP>{, #<pimm>}]"}, 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric {0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB, 3500b57cec5SDimitry Andric "B <label>"}, 3510b57cec5SDimitry Andric {0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond, 3520b57cec5SDimitry Andric "B.<cond> <label>"}, 3530b57cec5SDimitry Andric {0x7f000000, 0x34000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ, 3540b57cec5SDimitry Andric "CBZ <Wt>, <label>"}, 3550b57cec5SDimitry Andric {0x7f000000, 0x35000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ, 3560b57cec5SDimitry Andric "CBNZ <Wt>, <label>"}, 3570b57cec5SDimitry Andric {0x7f000000, 0x36000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ, 3580b57cec5SDimitry Andric "TBZ <R><t>, #<imm>, <label>"}, 3590b57cec5SDimitry Andric {0x7f000000, 0x37000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ, 3600b57cec5SDimitry Andric "TBNZ <R><t>, #<imm>, <label>"}, 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric }; 363bdd1243dSDimitry Andric static const size_t k_num_arm_opcodes = std::size(g_opcodes); 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric for (size_t i = 0; i < k_num_arm_opcodes; ++i) { 3660b57cec5SDimitry Andric if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value) 3670b57cec5SDimitry Andric return &g_opcodes[i]; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric return nullptr; 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric bool EmulateInstructionARM64::ReadInstruction() { 3730b57cec5SDimitry Andric bool success = false; 3740b57cec5SDimitry Andric m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 3750b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &success); 3760b57cec5SDimitry Andric if (success) { 3770b57cec5SDimitry Andric Context read_inst_context; 3780b57cec5SDimitry Andric read_inst_context.type = eContextReadOpcode; 3790b57cec5SDimitry Andric read_inst_context.SetNoArgs(); 3800b57cec5SDimitry Andric m_opcode.SetOpcode32( 3810b57cec5SDimitry Andric ReadMemoryUnsigned(read_inst_context, m_addr, 4, 0, &success), 3820b57cec5SDimitry Andric GetByteOrder()); 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric if (!success) 3850b57cec5SDimitry Andric m_addr = LLDB_INVALID_ADDRESS; 3860b57cec5SDimitry Andric return success; 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) { 3900b57cec5SDimitry Andric const uint32_t opcode = m_opcode.GetOpcode32(); 3910b57cec5SDimitry Andric Opcode *opcode_data = GetOpcodeForInstruction(opcode); 3920b57cec5SDimitry Andric if (opcode_data == nullptr) 3930b57cec5SDimitry Andric return false; 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric const bool auto_advance_pc = 3960b57cec5SDimitry Andric evaluate_options & eEmulateInstructionOptionAutoAdvancePC; 3970b57cec5SDimitry Andric m_ignore_conditions = 3980b57cec5SDimitry Andric evaluate_options & eEmulateInstructionOptionIgnoreConditions; 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric bool success = false; 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric // Only return false if we are unable to read the CPSR if we care about 4030b57cec5SDimitry Andric // conditions 4040b57cec5SDimitry Andric if (!success && !m_ignore_conditions) 4050b57cec5SDimitry Andric return false; 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric uint32_t orig_pc_value = 0; 4080b57cec5SDimitry Andric if (auto_advance_pc) { 4090b57cec5SDimitry Andric orig_pc_value = 4100b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success); 4110b57cec5SDimitry Andric if (!success) 4120b57cec5SDimitry Andric return false; 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric // Call the Emulate... function. 4160b57cec5SDimitry Andric success = (this->*opcode_data->callback)(opcode); 4170b57cec5SDimitry Andric if (!success) 4180b57cec5SDimitry Andric return false; 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric if (auto_advance_pc) { 4210b57cec5SDimitry Andric uint32_t new_pc_value = 4220b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success); 4230b57cec5SDimitry Andric if (!success) 4240b57cec5SDimitry Andric return false; 4250b57cec5SDimitry Andric 4265ffd83dbSDimitry Andric if (new_pc_value == orig_pc_value) { 4270b57cec5SDimitry Andric EmulateInstruction::Context context; 4280b57cec5SDimitry Andric context.type = eContextAdvancePC; 4290b57cec5SDimitry Andric context.SetNoArgs(); 4300b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_arm64, 4310b57cec5SDimitry Andric orig_pc_value + 4)) 4320b57cec5SDimitry Andric return false; 4330b57cec5SDimitry Andric } 4340b57cec5SDimitry Andric } 4350b57cec5SDimitry Andric return true; 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric bool EmulateInstructionARM64::CreateFunctionEntryUnwind( 4390b57cec5SDimitry Andric UnwindPlan &unwind_plan) { 4400b57cec5SDimitry Andric unwind_plan.Clear(); 4410b57cec5SDimitry Andric unwind_plan.SetRegisterKind(eRegisterKindLLDB); 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric UnwindPlan::RowSP row(new UnwindPlan::Row); 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric // Our previous Call Frame Address is the stack pointer 4460b57cec5SDimitry Andric row->GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_arm64, 0); 447*0fca6ea1SDimitry Andric row->SetRegisterLocationToSame(gpr_lr_arm64, /*must_replace=*/false); 448*0fca6ea1SDimitry Andric row->SetRegisterLocationToSame(gpr_fp_arm64, /*must_replace=*/false); 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric unwind_plan.AppendRow(row); 4510b57cec5SDimitry Andric unwind_plan.SetSourceName("EmulateInstructionARM64"); 4520b57cec5SDimitry Andric unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); 4530b57cec5SDimitry Andric unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); 4549dba64beSDimitry Andric unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); 4550b57cec5SDimitry Andric unwind_plan.SetReturnAddressRegister(gpr_lr_arm64); 4560b57cec5SDimitry Andric return true; 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric uint32_t EmulateInstructionARM64::GetFramePointerRegisterNumber() const { 4600b57cec5SDimitry Andric if (m_arch.GetTriple().isAndroid()) 4610b57cec5SDimitry Andric return LLDB_INVALID_REGNUM; // Don't use frame pointer on android 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric return gpr_fp_arm64; 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric bool EmulateInstructionARM64::UsingAArch32() { 4670b57cec5SDimitry Andric bool aarch32 = m_opcode_pstate.RW == 1; 4680b57cec5SDimitry Andric // if !HaveAnyAArch32() then assert !aarch32; 4690b57cec5SDimitry Andric // if HighestELUsingAArch32() then assert aarch32; 4700b57cec5SDimitry Andric return aarch32; 4710b57cec5SDimitry Andric } 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N, 4740b57cec5SDimitry Andric addr_t target) { 4750b57cec5SDimitry Andric #if 0 4760b57cec5SDimitry Andric // Set program counter to a new address, with a branch reason hint for 4770b57cec5SDimitry Andric // possible use by hardware fetching the next instruction. 4780b57cec5SDimitry Andric BranchTo(bits(N) target, BranchType branch_type) 4790b57cec5SDimitry Andric Hint_Branch(branch_type); 4800b57cec5SDimitry Andric if N == 32 then 4810b57cec5SDimitry Andric assert UsingAArch32(); 4820b57cec5SDimitry Andric _PC = ZeroExtend(target); 4830b57cec5SDimitry Andric else 4840b57cec5SDimitry Andric assert N == 64 && !UsingAArch32(); 4850b57cec5SDimitry Andric // Remove the tag bits from a tagged target 4860b57cec5SDimitry Andric case PSTATE.EL of 4870b57cec5SDimitry Andric when EL0, EL1 4880b57cec5SDimitry Andric if target<55> == '1' && TCR_EL1.TBI1 == '1' then 4890b57cec5SDimitry Andric target<63:56> = '11111111'; 4900b57cec5SDimitry Andric if target<55> == '0' && TCR_EL1.TBI0 == '1' then 4910b57cec5SDimitry Andric target<63:56> = '00000000'; 4920b57cec5SDimitry Andric when EL2 4930b57cec5SDimitry Andric if TCR_EL2.TBI == '1' then 4940b57cec5SDimitry Andric target<63:56> = '00000000'; 4950b57cec5SDimitry Andric when EL3 4960b57cec5SDimitry Andric if TCR_EL3.TBI == '1' then 4970b57cec5SDimitry Andric target<63:56> = '00000000'; 4980b57cec5SDimitry Andric _PC = target<63:0>; 4990b57cec5SDimitry Andric return; 5000b57cec5SDimitry Andric #endif 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric addr_t addr; 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric // Hint_Branch(branch_type); 5050b57cec5SDimitry Andric if (N == 32) { 5060b57cec5SDimitry Andric if (!UsingAArch32()) 5070b57cec5SDimitry Andric return false; 5080b57cec5SDimitry Andric addr = target; 5090b57cec5SDimitry Andric } else if (N == 64) { 5100b57cec5SDimitry Andric if (UsingAArch32()) 5110b57cec5SDimitry Andric return false; 5120b57cec5SDimitry Andric // TODO: Remove the tag bits from a tagged target 5130b57cec5SDimitry Andric addr = target; 5140b57cec5SDimitry Andric } else 5150b57cec5SDimitry Andric return false; 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric return WriteRegisterUnsigned(context, eRegisterKindGeneric, 5180b57cec5SDimitry Andric LLDB_REGNUM_GENERIC_PC, addr); 5190b57cec5SDimitry Andric } 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric bool EmulateInstructionARM64::ConditionHolds(const uint32_t cond) { 5220b57cec5SDimitry Andric // If we are ignoring conditions, then always return true. this allows us to 5230b57cec5SDimitry Andric // iterate over disassembly code and still emulate an instruction even if we 5240b57cec5SDimitry Andric // don't have all the right bits set in the CPSR register... 5250b57cec5SDimitry Andric if (m_ignore_conditions) 5260b57cec5SDimitry Andric return true; 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric bool result = false; 5290b57cec5SDimitry Andric switch (UnsignedBits(cond, 3, 1)) { 5300b57cec5SDimitry Andric case 0: 5310b57cec5SDimitry Andric result = (m_opcode_pstate.Z == 1); 5320b57cec5SDimitry Andric break; 5330b57cec5SDimitry Andric case 1: 5340b57cec5SDimitry Andric result = (m_opcode_pstate.C == 1); 5350b57cec5SDimitry Andric break; 5360b57cec5SDimitry Andric case 2: 5370b57cec5SDimitry Andric result = (m_opcode_pstate.N == 1); 5380b57cec5SDimitry Andric break; 5390b57cec5SDimitry Andric case 3: 5400b57cec5SDimitry Andric result = (m_opcode_pstate.V == 1); 5410b57cec5SDimitry Andric break; 5420b57cec5SDimitry Andric case 4: 5430b57cec5SDimitry Andric result = (m_opcode_pstate.C == 1 && m_opcode_pstate.Z == 0); 5440b57cec5SDimitry Andric break; 5450b57cec5SDimitry Andric case 5: 5460b57cec5SDimitry Andric result = (m_opcode_pstate.N == m_opcode_pstate.V); 5470b57cec5SDimitry Andric break; 5480b57cec5SDimitry Andric case 6: 5490b57cec5SDimitry Andric result = (m_opcode_pstate.N == m_opcode_pstate.V && m_opcode_pstate.Z == 0); 5500b57cec5SDimitry Andric break; 5510b57cec5SDimitry Andric case 7: 5520b57cec5SDimitry Andric // Always execute (cond == 0b1110, or the special 0b1111 which gives 5530b57cec5SDimitry Andric // opcodes different meanings, but always means execution happens. 5540b57cec5SDimitry Andric return true; 5550b57cec5SDimitry Andric } 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric if (cond & 1) 5580b57cec5SDimitry Andric result = !result; 5590b57cec5SDimitry Andric return result; 5600b57cec5SDimitry Andric } 5610b57cec5SDimitry Andric 5625ffd83dbSDimitry Andric uint64_t EmulateInstructionARM64:: 5635ffd83dbSDimitry Andric AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in, 5645ffd83dbSDimitry Andric EmulateInstructionARM64::ProcState &proc_state) { 5655ffd83dbSDimitry Andric uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in); 566bdd1243dSDimitry Andric std::optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y)); 5675ffd83dbSDimitry Andric bool overflow = !signed_sum; 5685ffd83dbSDimitry Andric if (!overflow) 5695ffd83dbSDimitry Andric overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in)); 5705ffd83dbSDimitry Andric uint64_t result = unsigned_sum; 5715ffd83dbSDimitry Andric if (N < 64) 5725ffd83dbSDimitry Andric result = Bits64(result, N - 1, 0); 5735ffd83dbSDimitry Andric proc_state.N = Bit64(result, N - 1); 5745ffd83dbSDimitry Andric proc_state.Z = IsZero(result); 5755ffd83dbSDimitry Andric proc_state.C = UInt(result) != unsigned_sum; 5765ffd83dbSDimitry Andric proc_state.V = overflow; 5775ffd83dbSDimitry Andric return result; 5785ffd83dbSDimitry Andric } 5795ffd83dbSDimitry Andric 5800b57cec5SDimitry Andric bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) { 5810b57cec5SDimitry Andric // integer d = UInt(Rd); 5820b57cec5SDimitry Andric // integer n = UInt(Rn); 5830b57cec5SDimitry Andric // integer datasize = if sf == 1 then 64 else 32; 5840b57cec5SDimitry Andric // boolean sub_op = (op == 1); 5850b57cec5SDimitry Andric // boolean setflags = (S == 1); 5860b57cec5SDimitry Andric // bits(datasize) imm; 5870b57cec5SDimitry Andric // 5880b57cec5SDimitry Andric // case shift of 5890b57cec5SDimitry Andric // when '00' imm = ZeroExtend(imm12, datasize); 5900b57cec5SDimitry Andric // when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize); 5910b57cec5SDimitry Andric // when '1x' UNDEFINED; 5920b57cec5SDimitry Andric // 5930b57cec5SDimitry Andric // 5940b57cec5SDimitry Andric // bits(datasize) result; 5950b57cec5SDimitry Andric // bits(datasize) operand1 = if n == 31 then SP[] else X[n]; 5960b57cec5SDimitry Andric // bits(datasize) operand2 = imm; 5970b57cec5SDimitry Andric // bits(4) nzcv; 5980b57cec5SDimitry Andric // bit carry_in; 5990b57cec5SDimitry Andric // 6000b57cec5SDimitry Andric // if sub_op then 6010b57cec5SDimitry Andric // operand2 = NOT(operand2); 6020b57cec5SDimitry Andric // carry_in = 1; 6030b57cec5SDimitry Andric // else 6040b57cec5SDimitry Andric // carry_in = 0; 6050b57cec5SDimitry Andric // 6060b57cec5SDimitry Andric // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in); 6070b57cec5SDimitry Andric // 6080b57cec5SDimitry Andric // if setflags then 6090b57cec5SDimitry Andric // PSTATE.NZCV = nzcv; 6100b57cec5SDimitry Andric // 6110b57cec5SDimitry Andric // if d == 31 && !setflags then 6120b57cec5SDimitry Andric // SP[] = result; 6130b57cec5SDimitry Andric // else 6140b57cec5SDimitry Andric // X[d] = result; 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric const uint32_t sf = Bit32(opcode, 31); 6170b57cec5SDimitry Andric const uint32_t op = Bit32(opcode, 30); 6180b57cec5SDimitry Andric const uint32_t S = Bit32(opcode, 29); 6190b57cec5SDimitry Andric const uint32_t shift = Bits32(opcode, 23, 22); 6200b57cec5SDimitry Andric const uint32_t imm12 = Bits32(opcode, 21, 10); 6210b57cec5SDimitry Andric const uint32_t Rn = Bits32(opcode, 9, 5); 6220b57cec5SDimitry Andric const uint32_t Rd = Bits32(opcode, 4, 0); 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric bool success = false; 6250b57cec5SDimitry Andric 6260b57cec5SDimitry Andric const uint32_t d = UInt(Rd); 6270b57cec5SDimitry Andric const uint32_t n = UInt(Rn); 6280b57cec5SDimitry Andric const uint32_t datasize = (sf == 1) ? 64 : 32; 6290b57cec5SDimitry Andric boolean sub_op = op == 1; 6300b57cec5SDimitry Andric boolean setflags = S == 1; 6310b57cec5SDimitry Andric uint64_t imm; 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric switch (shift) { 6340b57cec5SDimitry Andric case 0: 6350b57cec5SDimitry Andric imm = imm12; 6360b57cec5SDimitry Andric break; 6370b57cec5SDimitry Andric case 1: 638bdd1243dSDimitry Andric imm = static_cast<uint64_t>(imm12) << 12; 6390b57cec5SDimitry Andric break; 6400b57cec5SDimitry Andric default: 6410b57cec5SDimitry Andric return false; // UNDEFINED; 6420b57cec5SDimitry Andric } 6430b57cec5SDimitry Andric uint64_t result; 6440b57cec5SDimitry Andric uint64_t operand1 = 6450b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success); 6460b57cec5SDimitry Andric uint64_t operand2 = imm; 6470b57cec5SDimitry Andric bit carry_in; 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric if (sub_op) { 6500b57cec5SDimitry Andric operand2 = NOT(operand2); 6510b57cec5SDimitry Andric carry_in = true; 6520b57cec5SDimitry Andric imm = -imm; // For the Register plug offset context below 6530b57cec5SDimitry Andric } else { 6540b57cec5SDimitry Andric carry_in = false; 6550b57cec5SDimitry Andric } 6560b57cec5SDimitry Andric 6570b57cec5SDimitry Andric ProcState proc_state; 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric result = AddWithCarry(datasize, operand1, operand2, carry_in, proc_state); 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric if (setflags) { 6620b57cec5SDimitry Andric m_emulated_pstate.N = proc_state.N; 6630b57cec5SDimitry Andric m_emulated_pstate.Z = proc_state.Z; 6640b57cec5SDimitry Andric m_emulated_pstate.C = proc_state.C; 6650b57cec5SDimitry Andric m_emulated_pstate.V = proc_state.V; 6660b57cec5SDimitry Andric } 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric Context context; 669bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_Rn = 670bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindLLDB, n); 671bdd1243dSDimitry Andric if (reg_info_Rn) 672bdd1243dSDimitry Andric context.SetRegisterPlusOffset(*reg_info_Rn, imm); 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric if (n == GetFramePointerRegisterNumber() && d == gpr_sp_arm64 && !setflags) { 6750b57cec5SDimitry Andric // 'mov sp, fp' - common epilogue instruction, CFA is now in terms of the 6760b57cec5SDimitry Andric // stack pointer, instead of frame pointer. 6770b57cec5SDimitry Andric context.type = EmulateInstruction::eContextRestoreStackPointer; 6780b57cec5SDimitry Andric } else if ((n == gpr_sp_arm64 || n == GetFramePointerRegisterNumber()) && 6790b57cec5SDimitry Andric d == gpr_sp_arm64 && !setflags) { 6800b57cec5SDimitry Andric context.type = EmulateInstruction::eContextAdjustStackPointer; 6810b57cec5SDimitry Andric } else if (d == GetFramePointerRegisterNumber() && n == gpr_sp_arm64 && 6820b57cec5SDimitry Andric !setflags) { 6830b57cec5SDimitry Andric context.type = EmulateInstruction::eContextSetFramePointer; 6840b57cec5SDimitry Andric } else { 6850b57cec5SDimitry Andric context.type = EmulateInstruction::eContextImmediate; 6860b57cec5SDimitry Andric } 6870b57cec5SDimitry Andric 6880b57cec5SDimitry Andric // If setflags && d == gpr_sp_arm64 then d = WZR/XZR. See CMN, CMP 6890b57cec5SDimitry Andric if (!setflags || d != gpr_sp_arm64) 6900b57cec5SDimitry Andric WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_x0_arm64 + d, result); 6910b57cec5SDimitry Andric 6920b57cec5SDimitry Andric return false; 6930b57cec5SDimitry Andric } 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric template <EmulateInstructionARM64::AddrMode a_mode> 6960b57cec5SDimitry Andric bool EmulateInstructionARM64::EmulateLDPSTP(const uint32_t opcode) { 6970b57cec5SDimitry Andric uint32_t opc = Bits32(opcode, 31, 30); 6980b57cec5SDimitry Andric uint32_t V = Bit32(opcode, 26); 6990b57cec5SDimitry Andric uint32_t L = Bit32(opcode, 22); 7000b57cec5SDimitry Andric uint32_t imm7 = Bits32(opcode, 21, 15); 7010b57cec5SDimitry Andric uint32_t Rt2 = Bits32(opcode, 14, 10); 7020b57cec5SDimitry Andric uint32_t Rn = Bits32(opcode, 9, 5); 7030b57cec5SDimitry Andric uint32_t Rt = Bits32(opcode, 4, 0); 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric integer n = UInt(Rn); 7060b57cec5SDimitry Andric integer t = UInt(Rt); 7070b57cec5SDimitry Andric integer t2 = UInt(Rt2); 7080b57cec5SDimitry Andric uint64_t idx; 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE; 7110b57cec5SDimitry Andric boolean vector = (V == 1); 7120b57cec5SDimitry Andric // AccType acctype = AccType_NORMAL; 7130b57cec5SDimitry Andric boolean is_signed = false; 7140b57cec5SDimitry Andric boolean wback = a_mode != AddrMode_OFF; 7150b57cec5SDimitry Andric boolean wb_unknown = false; 7160b57cec5SDimitry Andric boolean rt_unknown = false; 7170b57cec5SDimitry Andric integer scale; 7180b57cec5SDimitry Andric integer size; 7190b57cec5SDimitry Andric 7200b57cec5SDimitry Andric if (opc == 3) 7210b57cec5SDimitry Andric return false; // UNDEFINED 7220b57cec5SDimitry Andric 7230b57cec5SDimitry Andric if (vector) { 7240b57cec5SDimitry Andric scale = 2 + UInt(opc); 7250b57cec5SDimitry Andric } else { 7260b57cec5SDimitry Andric scale = (opc & 2) ? 3 : 2; 7270b57cec5SDimitry Andric is_signed = (opc & 1) != 0; 7280b57cec5SDimitry Andric if (is_signed && memop == MemOp_STORE) 7290b57cec5SDimitry Andric return false; // UNDEFINED 7300b57cec5SDimitry Andric } 7310b57cec5SDimitry Andric 7320b57cec5SDimitry Andric if (!vector && wback && ((t == n) || (t2 == n))) { 7330b57cec5SDimitry Andric switch (ConstrainUnpredictable(Unpredictable_WBOVERLAP)) { 7340b57cec5SDimitry Andric case Constraint_UNKNOWN: 7350b57cec5SDimitry Andric wb_unknown = true; // writeback is UNKNOWN 7360b57cec5SDimitry Andric break; 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric case Constraint_SUPPRESSWB: 7390b57cec5SDimitry Andric wback = false; // writeback is suppressed 7400b57cec5SDimitry Andric break; 7410b57cec5SDimitry Andric 7420b57cec5SDimitry Andric case Constraint_NOP: 7430b57cec5SDimitry Andric memop = MemOp_NOP; // do nothing 7440b57cec5SDimitry Andric wback = false; 7450b57cec5SDimitry Andric break; 7460b57cec5SDimitry Andric 7470b57cec5SDimitry Andric case Constraint_NONE: 7480b57cec5SDimitry Andric break; 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric } 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric if (memop == MemOp_LOAD && t == t2) { 7530b57cec5SDimitry Andric switch (ConstrainUnpredictable(Unpredictable_LDPOVERLAP)) { 7540b57cec5SDimitry Andric case Constraint_UNKNOWN: 7550b57cec5SDimitry Andric rt_unknown = true; // result is UNKNOWN 7560b57cec5SDimitry Andric break; 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric case Constraint_NOP: 7590b57cec5SDimitry Andric memop = MemOp_NOP; // do nothing 7600b57cec5SDimitry Andric wback = false; 7610b57cec5SDimitry Andric break; 7620b57cec5SDimitry Andric 7630b57cec5SDimitry Andric default: 7640b57cec5SDimitry Andric break; 7650b57cec5SDimitry Andric } 7660b57cec5SDimitry Andric } 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric idx = LSL(llvm::SignExtend64<7>(imm7), scale); 7690b57cec5SDimitry Andric size = (integer)1 << scale; 7700b57cec5SDimitry Andric uint64_t datasize = size * 8; 7710b57cec5SDimitry Andric uint64_t address; 7720b57cec5SDimitry Andric uint64_t wb_address; 7730b57cec5SDimitry Andric 774bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_base = 775bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + n); 776bdd1243dSDimitry Andric if (!reg_info_base) 7770b57cec5SDimitry Andric return false; 7780b57cec5SDimitry Andric 779bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_Rt; 780bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_Rt2; 781bdd1243dSDimitry Andric 7820b57cec5SDimitry Andric if (vector) { 783bdd1243dSDimitry Andric reg_info_Rt = GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t); 784bdd1243dSDimitry Andric reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t2); 7850b57cec5SDimitry Andric } else { 786bdd1243dSDimitry Andric reg_info_Rt = GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t); 787bdd1243dSDimitry Andric reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t2); 7880b57cec5SDimitry Andric } 7890b57cec5SDimitry Andric 790bdd1243dSDimitry Andric if (!reg_info_Rt || !reg_info_Rt2) 791bdd1243dSDimitry Andric return false; 792bdd1243dSDimitry Andric 7930b57cec5SDimitry Andric bool success = false; 7940b57cec5SDimitry Andric if (n == 31) { 7950b57cec5SDimitry Andric // CheckSPAlignment(); 7960b57cec5SDimitry Andric address = 7970b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_sp_arm64, 0, &success); 7980b57cec5SDimitry Andric } else 7990b57cec5SDimitry Andric address = 8000b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success); 8010b57cec5SDimitry Andric 8020b57cec5SDimitry Andric wb_address = address + idx; 8030b57cec5SDimitry Andric if (a_mode != AddrMode_POST) 8040b57cec5SDimitry Andric address = wb_address; 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric Context context_t; 8070b57cec5SDimitry Andric Context context_t2; 8080b57cec5SDimitry Andric 80906c3fb27SDimitry Andric RegisterValue::BytesContainer buffer; 8100b57cec5SDimitry Andric Status error; 8110b57cec5SDimitry Andric 8120b57cec5SDimitry Andric switch (memop) { 8130b57cec5SDimitry Andric case MemOp_STORE: { 8140b57cec5SDimitry Andric if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is 8150b57cec5SDimitry Andric // based off of the sp 8160b57cec5SDimitry Andric // or fp register 8170b57cec5SDimitry Andric { 8180b57cec5SDimitry Andric context_t.type = eContextPushRegisterOnStack; 8190b57cec5SDimitry Andric context_t2.type = eContextPushRegisterOnStack; 8200b57cec5SDimitry Andric } else { 8210b57cec5SDimitry Andric context_t.type = eContextRegisterStore; 8220b57cec5SDimitry Andric context_t2.type = eContextRegisterStore; 8230b57cec5SDimitry Andric } 824bdd1243dSDimitry Andric context_t.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base, 0); 825bdd1243dSDimitry Andric context_t2.SetRegisterToRegisterPlusOffset(*reg_info_Rt2, *reg_info_base, 8260b57cec5SDimitry Andric size); 8270b57cec5SDimitry Andric 828bdd1243dSDimitry Andric std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt); 829bdd1243dSDimitry Andric if (!data_Rt) 8300b57cec5SDimitry Andric return false; 8310b57cec5SDimitry Andric 83206c3fb27SDimitry Andric buffer.resize(reg_info_Rt->byte_size); 83306c3fb27SDimitry Andric if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer.data(), 83406c3fb27SDimitry Andric reg_info_Rt->byte_size, eByteOrderLittle, 83506c3fb27SDimitry Andric error) == 0) 8360b57cec5SDimitry Andric return false; 8370b57cec5SDimitry Andric 83806c3fb27SDimitry Andric if (!WriteMemory(context_t, address + 0, buffer.data(), 83906c3fb27SDimitry Andric reg_info_Rt->byte_size)) 8400b57cec5SDimitry Andric return false; 8410b57cec5SDimitry Andric 842bdd1243dSDimitry Andric std::optional<RegisterValue> data_Rt2 = ReadRegister(*reg_info_Rt2); 843bdd1243dSDimitry Andric if (!data_Rt2) 8440b57cec5SDimitry Andric return false; 8450b57cec5SDimitry Andric 84606c3fb27SDimitry Andric buffer.resize(reg_info_Rt2->byte_size); 84706c3fb27SDimitry Andric if (data_Rt2->GetAsMemoryData(*reg_info_Rt2, buffer.data(), 848bdd1243dSDimitry Andric reg_info_Rt2->byte_size, eByteOrderLittle, 849bdd1243dSDimitry Andric error) == 0) 8500b57cec5SDimitry Andric return false; 8510b57cec5SDimitry Andric 85206c3fb27SDimitry Andric if (!WriteMemory(context_t2, address + size, buffer.data(), 853bdd1243dSDimitry Andric reg_info_Rt2->byte_size)) 8540b57cec5SDimitry Andric return false; 8550b57cec5SDimitry Andric } break; 8560b57cec5SDimitry Andric 8570b57cec5SDimitry Andric case MemOp_LOAD: { 8580b57cec5SDimitry Andric if (n == 31 || n == GetFramePointerRegisterNumber()) // if this load is 8590b57cec5SDimitry Andric // based off of the sp 8600b57cec5SDimitry Andric // or fp register 8610b57cec5SDimitry Andric { 8620b57cec5SDimitry Andric context_t.type = eContextPopRegisterOffStack; 8630b57cec5SDimitry Andric context_t2.type = eContextPopRegisterOffStack; 8640b57cec5SDimitry Andric } else { 8650b57cec5SDimitry Andric context_t.type = eContextRegisterLoad; 8660b57cec5SDimitry Andric context_t2.type = eContextRegisterLoad; 8670b57cec5SDimitry Andric } 8680b57cec5SDimitry Andric context_t.SetAddress(address); 8690b57cec5SDimitry Andric context_t2.SetAddress(address + size); 8700b57cec5SDimitry Andric 87106c3fb27SDimitry Andric buffer.resize(reg_info_Rt->byte_size); 8720b57cec5SDimitry Andric if (rt_unknown) 87306c3fb27SDimitry Andric std::fill(buffer.begin(), buffer.end(), 'U'); 8740b57cec5SDimitry Andric else { 87506c3fb27SDimitry Andric if (!ReadMemory(context_t, address, buffer.data(), 87606c3fb27SDimitry Andric reg_info_Rt->byte_size)) 8770b57cec5SDimitry Andric return false; 8780b57cec5SDimitry Andric } 8790b57cec5SDimitry Andric 880bdd1243dSDimitry Andric RegisterValue data_Rt; 88106c3fb27SDimitry Andric if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer.data(), 88206c3fb27SDimitry Andric reg_info_Rt->byte_size, eByteOrderLittle, 88306c3fb27SDimitry Andric error) == 0) 8840b57cec5SDimitry Andric return false; 8850b57cec5SDimitry Andric 8860b57cec5SDimitry Andric if (!vector && is_signed && !data_Rt.SignExtend(datasize)) 8870b57cec5SDimitry Andric return false; 8880b57cec5SDimitry Andric 889bdd1243dSDimitry Andric if (!WriteRegister(context_t, *reg_info_Rt, data_Rt)) 8900b57cec5SDimitry Andric return false; 8910b57cec5SDimitry Andric 89206c3fb27SDimitry Andric buffer.resize(reg_info_Rt2->byte_size); 89306c3fb27SDimitry Andric if (!rt_unknown) 89406c3fb27SDimitry Andric if (!ReadMemory(context_t2, address + size, buffer.data(), 895bdd1243dSDimitry Andric reg_info_Rt2->byte_size)) 8960b57cec5SDimitry Andric return false; 8970b57cec5SDimitry Andric 898bdd1243dSDimitry Andric RegisterValue data_Rt2; 89906c3fb27SDimitry Andric if (data_Rt2.SetFromMemoryData(*reg_info_Rt2, buffer.data(), 900bdd1243dSDimitry Andric reg_info_Rt2->byte_size, eByteOrderLittle, 9010b57cec5SDimitry Andric error) == 0) 9020b57cec5SDimitry Andric return false; 9030b57cec5SDimitry Andric 9040b57cec5SDimitry Andric if (!vector && is_signed && !data_Rt2.SignExtend(datasize)) 9050b57cec5SDimitry Andric return false; 9060b57cec5SDimitry Andric 907bdd1243dSDimitry Andric if (!WriteRegister(context_t2, *reg_info_Rt2, data_Rt2)) 9080b57cec5SDimitry Andric return false; 9090b57cec5SDimitry Andric } break; 9100b57cec5SDimitry Andric 9110b57cec5SDimitry Andric default: 9120b57cec5SDimitry Andric break; 9130b57cec5SDimitry Andric } 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric if (wback) { 9160b57cec5SDimitry Andric if (wb_unknown) 9170b57cec5SDimitry Andric wb_address = LLDB_INVALID_ADDRESS; 9180b57cec5SDimitry Andric Context context; 9190b57cec5SDimitry Andric context.SetImmediateSigned(idx); 9200b57cec5SDimitry Andric if (n == 31) 9210b57cec5SDimitry Andric context.type = eContextAdjustStackPointer; 9220b57cec5SDimitry Andric else 9230b57cec5SDimitry Andric context.type = eContextAdjustBaseRegister; 924bdd1243dSDimitry Andric WriteRegisterUnsigned(context, *reg_info_base, wb_address); 9250b57cec5SDimitry Andric } 9260b57cec5SDimitry Andric return true; 9270b57cec5SDimitry Andric } 9280b57cec5SDimitry Andric 9290b57cec5SDimitry Andric template <EmulateInstructionARM64::AddrMode a_mode> 9300b57cec5SDimitry Andric bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) { 9310b57cec5SDimitry Andric uint32_t size = Bits32(opcode, 31, 30); 9320b57cec5SDimitry Andric uint32_t opc = Bits32(opcode, 23, 22); 9330b57cec5SDimitry Andric uint32_t n = Bits32(opcode, 9, 5); 9340b57cec5SDimitry Andric uint32_t t = Bits32(opcode, 4, 0); 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric bool wback; 9370b57cec5SDimitry Andric bool postindex; 9380b57cec5SDimitry Andric uint64_t offset; 9390b57cec5SDimitry Andric 9400b57cec5SDimitry Andric switch (a_mode) { 9410b57cec5SDimitry Andric case AddrMode_POST: 9420b57cec5SDimitry Andric wback = true; 9430b57cec5SDimitry Andric postindex = true; 9440b57cec5SDimitry Andric offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12)); 9450b57cec5SDimitry Andric break; 9460b57cec5SDimitry Andric case AddrMode_PRE: 9470b57cec5SDimitry Andric wback = true; 9480b57cec5SDimitry Andric postindex = false; 9490b57cec5SDimitry Andric offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12)); 9500b57cec5SDimitry Andric break; 9510b57cec5SDimitry Andric case AddrMode_OFF: 9520b57cec5SDimitry Andric wback = false; 9530b57cec5SDimitry Andric postindex = false; 9540b57cec5SDimitry Andric offset = LSL(Bits32(opcode, 21, 10), size); 9550b57cec5SDimitry Andric break; 9560b57cec5SDimitry Andric } 9570b57cec5SDimitry Andric 9580b57cec5SDimitry Andric MemOp memop; 9590b57cec5SDimitry Andric 9600b57cec5SDimitry Andric if (Bit32(opc, 1) == 0) { 9610b57cec5SDimitry Andric memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE; 9620b57cec5SDimitry Andric } else { 9630b57cec5SDimitry Andric memop = MemOp_LOAD; 9640b57cec5SDimitry Andric if (size == 2 && Bit32(opc, 0) == 1) 9650b57cec5SDimitry Andric return false; 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric 9680b57cec5SDimitry Andric Status error; 9690b57cec5SDimitry Andric bool success = false; 9700b57cec5SDimitry Andric uint64_t address; 97106c3fb27SDimitry Andric RegisterValue::BytesContainer buffer; 9720b57cec5SDimitry Andric 9730b57cec5SDimitry Andric if (n == 31) 9740b57cec5SDimitry Andric address = 9750b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_sp_arm64, 0, &success); 9760b57cec5SDimitry Andric else 9770b57cec5SDimitry Andric address = 9780b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success); 9790b57cec5SDimitry Andric 9800b57cec5SDimitry Andric if (!success) 9810b57cec5SDimitry Andric return false; 9820b57cec5SDimitry Andric 9830b57cec5SDimitry Andric if (!postindex) 9840b57cec5SDimitry Andric address += offset; 9850b57cec5SDimitry Andric 986bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_base = 987bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + n); 988bdd1243dSDimitry Andric if (!reg_info_base) 9890b57cec5SDimitry Andric return false; 9900b57cec5SDimitry Andric 991bdd1243dSDimitry Andric std::optional<RegisterInfo> reg_info_Rt = 992bdd1243dSDimitry Andric GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t); 993bdd1243dSDimitry Andric if (!reg_info_Rt) 9940b57cec5SDimitry Andric return false; 9950b57cec5SDimitry Andric 9960b57cec5SDimitry Andric Context context; 9970b57cec5SDimitry Andric switch (memop) { 998bdd1243dSDimitry Andric case MemOp_STORE: { 9990b57cec5SDimitry Andric if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is 10000b57cec5SDimitry Andric // based off of the sp 10010b57cec5SDimitry Andric // or fp register 10020b57cec5SDimitry Andric context.type = eContextPushRegisterOnStack; 10030b57cec5SDimitry Andric else 10040b57cec5SDimitry Andric context.type = eContextRegisterStore; 1005bdd1243dSDimitry Andric context.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base, 10060b57cec5SDimitry Andric postindex ? 0 : offset); 10070b57cec5SDimitry Andric 1008bdd1243dSDimitry Andric std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt); 1009bdd1243dSDimitry Andric if (!data_Rt) 10100b57cec5SDimitry Andric return false; 10110b57cec5SDimitry Andric 101206c3fb27SDimitry Andric buffer.resize(reg_info_Rt->byte_size); 101306c3fb27SDimitry Andric if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer.data(), 101406c3fb27SDimitry Andric reg_info_Rt->byte_size, eByteOrderLittle, 101506c3fb27SDimitry Andric error) == 0) 10160b57cec5SDimitry Andric return false; 10170b57cec5SDimitry Andric 101806c3fb27SDimitry Andric if (!WriteMemory(context, address, buffer.data(), reg_info_Rt->byte_size)) 10190b57cec5SDimitry Andric return false; 1020bdd1243dSDimitry Andric } break; 10210b57cec5SDimitry Andric 1022bdd1243dSDimitry Andric case MemOp_LOAD: { 10230b57cec5SDimitry Andric if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is 10240b57cec5SDimitry Andric // based off of the sp 10250b57cec5SDimitry Andric // or fp register 10260b57cec5SDimitry Andric context.type = eContextPopRegisterOffStack; 10270b57cec5SDimitry Andric else 10280b57cec5SDimitry Andric context.type = eContextRegisterLoad; 10290b57cec5SDimitry Andric context.SetAddress(address); 10300b57cec5SDimitry Andric 103106c3fb27SDimitry Andric buffer.resize(reg_info_Rt->byte_size); 103206c3fb27SDimitry Andric if (!ReadMemory(context, address, buffer.data(), reg_info_Rt->byte_size)) 10330b57cec5SDimitry Andric return false; 10340b57cec5SDimitry Andric 1035bdd1243dSDimitry Andric RegisterValue data_Rt; 103606c3fb27SDimitry Andric if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer.data(), 103706c3fb27SDimitry Andric reg_info_Rt->byte_size, eByteOrderLittle, 103806c3fb27SDimitry Andric error) == 0) 10390b57cec5SDimitry Andric return false; 10400b57cec5SDimitry Andric 1041bdd1243dSDimitry Andric if (!WriteRegister(context, *reg_info_Rt, data_Rt)) 10420b57cec5SDimitry Andric return false; 1043bdd1243dSDimitry Andric } break; 10440b57cec5SDimitry Andric default: 10450b57cec5SDimitry Andric return false; 10460b57cec5SDimitry Andric } 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric if (wback) { 10490b57cec5SDimitry Andric if (postindex) 10500b57cec5SDimitry Andric address += offset; 10510b57cec5SDimitry Andric 10520b57cec5SDimitry Andric if (n == 31) 10530b57cec5SDimitry Andric context.type = eContextAdjustStackPointer; 10540b57cec5SDimitry Andric else 10550b57cec5SDimitry Andric context.type = eContextAdjustBaseRegister; 10560b57cec5SDimitry Andric context.SetImmediateSigned(offset); 10570b57cec5SDimitry Andric 1058bdd1243dSDimitry Andric if (!WriteRegisterUnsigned(context, *reg_info_base, address)) 10590b57cec5SDimitry Andric return false; 10600b57cec5SDimitry Andric } 10610b57cec5SDimitry Andric return true; 10620b57cec5SDimitry Andric } 10630b57cec5SDimitry Andric 10640b57cec5SDimitry Andric bool EmulateInstructionARM64::EmulateB(const uint32_t opcode) { 10650b57cec5SDimitry Andric #if 0 10660b57cec5SDimitry Andric // ARM64 pseudo code... 10670b57cec5SDimitry Andric if branch_type == BranchType_CALL then X[30] = PC[] + 4; 10680b57cec5SDimitry Andric BranchTo(PC[] + offset, branch_type); 10690b57cec5SDimitry Andric #endif 10700b57cec5SDimitry Andric 10710b57cec5SDimitry Andric bool success = false; 10720b57cec5SDimitry Andric 10730b57cec5SDimitry Andric EmulateInstruction::Context context; 10740b57cec5SDimitry Andric context.type = EmulateInstruction::eContextRelativeBranchImmediate; 10750b57cec5SDimitry Andric const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, 10760b57cec5SDimitry Andric LLDB_REGNUM_GENERIC_PC, 0, &success); 10770b57cec5SDimitry Andric if (!success) 10780b57cec5SDimitry Andric return false; 10790b57cec5SDimitry Andric 10800b57cec5SDimitry Andric int64_t offset = llvm::SignExtend64<28>(Bits32(opcode, 25, 0) << 2); 10810b57cec5SDimitry Andric BranchType branch_type = Bit32(opcode, 31) ? BranchType_CALL : BranchType_JMP; 10820b57cec5SDimitry Andric addr_t target = pc + offset; 10830b57cec5SDimitry Andric context.SetImmediateSigned(offset); 10840b57cec5SDimitry Andric 10850b57cec5SDimitry Andric switch (branch_type) { 10860b57cec5SDimitry Andric case BranchType_CALL: { 10870b57cec5SDimitry Andric addr_t x30 = pc + 4; 10880b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_lr_arm64, x30)) 10890b57cec5SDimitry Andric return false; 10900b57cec5SDimitry Andric } break; 10910b57cec5SDimitry Andric case BranchType_JMP: 10920b57cec5SDimitry Andric break; 10930b57cec5SDimitry Andric default: 10940b57cec5SDimitry Andric return false; 10950b57cec5SDimitry Andric } 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric return BranchTo(context, 64, target); 10980b57cec5SDimitry Andric } 10990b57cec5SDimitry Andric 11000b57cec5SDimitry Andric bool EmulateInstructionARM64::EmulateBcond(const uint32_t opcode) { 11010b57cec5SDimitry Andric #if 0 11020b57cec5SDimitry Andric // ARM64 pseudo code... 11030b57cec5SDimitry Andric bits(64) offset = SignExtend(imm19:'00', 64); 11040b57cec5SDimitry Andric bits(4) condition = cond; 11050b57cec5SDimitry Andric if ConditionHolds(condition) then 11060b57cec5SDimitry Andric BranchTo(PC[] + offset, BranchType_JMP); 11070b57cec5SDimitry Andric #endif 11080b57cec5SDimitry Andric 11090b57cec5SDimitry Andric if (ConditionHolds(Bits32(opcode, 3, 0))) { 11100b57cec5SDimitry Andric bool success = false; 11110b57cec5SDimitry Andric 11120b57cec5SDimitry Andric const uint64_t pc = ReadRegisterUnsigned( 11130b57cec5SDimitry Andric eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); 11140b57cec5SDimitry Andric if (!success) 11150b57cec5SDimitry Andric return false; 11160b57cec5SDimitry Andric 11170b57cec5SDimitry Andric int64_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2); 11180b57cec5SDimitry Andric addr_t target = pc + offset; 11190b57cec5SDimitry Andric 11200b57cec5SDimitry Andric EmulateInstruction::Context context; 11210b57cec5SDimitry Andric context.type = EmulateInstruction::eContextRelativeBranchImmediate; 11220b57cec5SDimitry Andric context.SetImmediateSigned(offset); 11230b57cec5SDimitry Andric if (!BranchTo(context, 64, target)) 11240b57cec5SDimitry Andric return false; 11250b57cec5SDimitry Andric } 11260b57cec5SDimitry Andric return true; 11270b57cec5SDimitry Andric } 11280b57cec5SDimitry Andric 11290b57cec5SDimitry Andric bool EmulateInstructionARM64::EmulateCBZ(const uint32_t opcode) { 11300b57cec5SDimitry Andric #if 0 11310b57cec5SDimitry Andric integer t = UInt(Rt); 11320b57cec5SDimitry Andric integer datasize = if sf == '1' then 64 else 32; 11330b57cec5SDimitry Andric boolean iszero = (op == '0'); 11340b57cec5SDimitry Andric bits(64) offset = SignExtend(imm19:'00', 64); 11350b57cec5SDimitry Andric 11360b57cec5SDimitry Andric bits(datasize) operand1 = X[t]; 11370b57cec5SDimitry Andric if IsZero(operand1) == iszero then 11380b57cec5SDimitry Andric BranchTo(PC[] + offset, BranchType_JMP); 11390b57cec5SDimitry Andric #endif 11400b57cec5SDimitry Andric 11410b57cec5SDimitry Andric bool success = false; 11420b57cec5SDimitry Andric 11430b57cec5SDimitry Andric uint32_t t = Bits32(opcode, 4, 0); 11440b57cec5SDimitry Andric bool is_zero = Bit32(opcode, 24) == 0; 11450b57cec5SDimitry Andric int32_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2); 11460b57cec5SDimitry Andric 11470b57cec5SDimitry Andric const uint64_t operand = 11480b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + t, 0, &success); 11490b57cec5SDimitry Andric if (!success) 11500b57cec5SDimitry Andric return false; 11510b57cec5SDimitry Andric 11520b57cec5SDimitry Andric if (m_ignore_conditions || ((operand == 0) == is_zero)) { 11530b57cec5SDimitry Andric const uint64_t pc = ReadRegisterUnsigned( 11540b57cec5SDimitry Andric eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); 11550b57cec5SDimitry Andric if (!success) 11560b57cec5SDimitry Andric return false; 11570b57cec5SDimitry Andric 11580b57cec5SDimitry Andric EmulateInstruction::Context context; 11590b57cec5SDimitry Andric context.type = EmulateInstruction::eContextRelativeBranchImmediate; 11600b57cec5SDimitry Andric context.SetImmediateSigned(offset); 11610b57cec5SDimitry Andric if (!BranchTo(context, 64, pc + offset)) 11620b57cec5SDimitry Andric return false; 11630b57cec5SDimitry Andric } 11640b57cec5SDimitry Andric return true; 11650b57cec5SDimitry Andric } 11660b57cec5SDimitry Andric 11670b57cec5SDimitry Andric bool EmulateInstructionARM64::EmulateTBZ(const uint32_t opcode) { 11680b57cec5SDimitry Andric #if 0 11690b57cec5SDimitry Andric integer t = UInt(Rt); 11700b57cec5SDimitry Andric integer datasize = if b5 == '1' then 64 else 32; 11710b57cec5SDimitry Andric integer bit_pos = UInt(b5:b40); 11720b57cec5SDimitry Andric bit bit_val = op; 11730b57cec5SDimitry Andric bits(64) offset = SignExtend(imm14:'00', 64); 11740b57cec5SDimitry Andric #endif 11750b57cec5SDimitry Andric 11760b57cec5SDimitry Andric bool success = false; 11770b57cec5SDimitry Andric 11780b57cec5SDimitry Andric uint32_t t = Bits32(opcode, 4, 0); 11790b57cec5SDimitry Andric uint32_t bit_pos = (Bit32(opcode, 31) << 6) | (Bits32(opcode, 23, 19)); 11800b57cec5SDimitry Andric uint32_t bit_val = Bit32(opcode, 24); 11810b57cec5SDimitry Andric int64_t offset = llvm::SignExtend64<16>(Bits32(opcode, 18, 5) << 2); 11820b57cec5SDimitry Andric 11830b57cec5SDimitry Andric const uint64_t operand = 11840b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + t, 0, &success); 11850b57cec5SDimitry Andric if (!success) 11860b57cec5SDimitry Andric return false; 11870b57cec5SDimitry Andric 11880b57cec5SDimitry Andric if (m_ignore_conditions || Bit32(operand, bit_pos) == bit_val) { 11890b57cec5SDimitry Andric const uint64_t pc = ReadRegisterUnsigned( 11900b57cec5SDimitry Andric eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); 11910b57cec5SDimitry Andric if (!success) 11920b57cec5SDimitry Andric return false; 11930b57cec5SDimitry Andric 11940b57cec5SDimitry Andric EmulateInstruction::Context context; 11950b57cec5SDimitry Andric context.type = EmulateInstruction::eContextRelativeBranchImmediate; 11960b57cec5SDimitry Andric context.SetImmediateSigned(offset); 11970b57cec5SDimitry Andric if (!BranchTo(context, 64, pc + offset)) 11980b57cec5SDimitry Andric return false; 11990b57cec5SDimitry Andric } 12000b57cec5SDimitry Andric return true; 12010b57cec5SDimitry Andric } 1202