Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
39648 views
//===-- EmulateInstructionARM64.cpp ---------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "EmulateInstructionARM64.h"910#include "lldb/Core/Address.h"11#include "lldb/Core/PluginManager.h"12#include "lldb/Symbol/UnwindPlan.h"13#include "lldb/Utility/ArchSpec.h"14#include "lldb/Utility/RegisterValue.h"15#include "lldb/Utility/Stream.h"1617#include "llvm/Support/CheckedArithmetic.h"1819#include "Plugins/Process/Utility/ARMDefines.h"20#include "Plugins/Process/Utility/ARMUtils.h"21#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"2223#include <algorithm>24#include <cstdlib>25#include <optional>2627#define GPR_OFFSET(idx) ((idx)*8)28#define GPR_OFFSET_NAME(reg) 029#define FPU_OFFSET(idx) ((idx)*16)30#define FPU_OFFSET_NAME(reg) 031#define EXC_OFFSET_NAME(reg) 032#define DBG_OFFSET_NAME(reg) 033#define DBG_OFFSET_NAME(reg) 034#define DEFINE_DBG(re, y) \35"na", nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \36{LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \37LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, \38nullptr, nullptr, nullptr3940#define DECLARE_REGISTER_INFOS_ARM64_STRUCT4142#include "Plugins/Process/Utility/RegisterInfos_arm64.h"4344#include "llvm/ADT/STLExtras.h"45#include "llvm/Support/MathExtras.h"4647#include "Plugins/Process/Utility/InstructionUtils.h"4849using namespace lldb;50using namespace lldb_private;5152LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM64, InstructionARM64)5354static std::optional<RegisterInfo> LLDBTableGetRegisterInfo(uint32_t reg_num) {55if (reg_num >= std::size(g_register_infos_arm64_le))56return {};57return g_register_infos_arm64_le[reg_num];58}5960#define No_VFP 061#define VFPv1 (1u << 1)62#define VFPv2 (1u << 2)63#define VFPv3 (1u << 3)64#define AdvancedSIMD (1u << 4)6566#define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)67#define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)68#define VFPv2v3 (VFPv2 | VFPv3)6970#define UInt(x) ((uint64_t)x)71#define SInt(x) ((int64_t)x)72#define bit bool73#define boolean bool74#define integer int64_t7576static inline bool IsZero(uint64_t x) { return x == 0; }7778static inline uint64_t NOT(uint64_t x) { return ~x; }7980// LSL()81// =====8283static inline uint64_t LSL(uint64_t x, integer shift) {84if (shift == 0)85return x;86return x << shift;87}8889// ConstrainUnpredictable()90// ========================9192EmulateInstructionARM64::ConstraintType93ConstrainUnpredictable(EmulateInstructionARM64::Unpredictable which) {94EmulateInstructionARM64::ConstraintType result =95EmulateInstructionARM64::Constraint_UNKNOWN;96switch (which) {97case EmulateInstructionARM64::Unpredictable_WBOVERLAP:98case EmulateInstructionARM64::Unpredictable_LDPOVERLAP:99// TODO: don't know what to really do here? Pseudo code says:100// set result to one of above Constraint behaviours or UNDEFINED101break;102}103return result;104}105106//107// EmulateInstructionARM implementation108//109110void EmulateInstructionARM64::Initialize() {111PluginManager::RegisterPlugin(GetPluginNameStatic(),112GetPluginDescriptionStatic(), CreateInstance);113}114115void EmulateInstructionARM64::Terminate() {116PluginManager::UnregisterPlugin(CreateInstance);117}118119llvm::StringRef EmulateInstructionARM64::GetPluginDescriptionStatic() {120return "Emulate instructions for the ARM64 architecture.";121}122123EmulateInstruction *124EmulateInstructionARM64::CreateInstance(const ArchSpec &arch,125InstructionType inst_type) {126if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic(127inst_type)) {128if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||129arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {130return new EmulateInstructionARM64(arch);131}132}133134return nullptr;135}136137bool EmulateInstructionARM64::SetTargetTriple(const ArchSpec &arch) {138if (arch.GetTriple().getArch() == llvm::Triple::arm)139return true;140else if (arch.GetTriple().getArch() == llvm::Triple::thumb)141return true;142143return false;144}145146std::optional<RegisterInfo>147EmulateInstructionARM64::GetRegisterInfo(RegisterKind reg_kind,148uint32_t reg_num) {149if (reg_kind == eRegisterKindGeneric) {150switch (reg_num) {151case LLDB_REGNUM_GENERIC_PC:152reg_kind = eRegisterKindLLDB;153reg_num = gpr_pc_arm64;154break;155case LLDB_REGNUM_GENERIC_SP:156reg_kind = eRegisterKindLLDB;157reg_num = gpr_sp_arm64;158break;159case LLDB_REGNUM_GENERIC_FP:160reg_kind = eRegisterKindLLDB;161reg_num = gpr_fp_arm64;162break;163case LLDB_REGNUM_GENERIC_RA:164reg_kind = eRegisterKindLLDB;165reg_num = gpr_lr_arm64;166break;167case LLDB_REGNUM_GENERIC_FLAGS:168reg_kind = eRegisterKindLLDB;169reg_num = gpr_cpsr_arm64;170break;171172default:173return {};174}175}176177if (reg_kind == eRegisterKindLLDB)178return LLDBTableGetRegisterInfo(reg_num);179return {};180}181182EmulateInstructionARM64::Opcode *183EmulateInstructionARM64::GetOpcodeForInstruction(const uint32_t opcode) {184static EmulateInstructionARM64::Opcode g_opcodes[] = {185// Prologue instructions186187// push register(s)188{0xff000000, 0xd1000000, No_VFP,189&EmulateInstructionARM64::EmulateADDSUBImm,190"SUB <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"},191{0xff000000, 0xf1000000, No_VFP,192&EmulateInstructionARM64::EmulateADDSUBImm,193"SUBS <Xd>, <Xn|SP>, #<imm> {, <shift>}"},194{0xff000000, 0x91000000, No_VFP,195&EmulateInstructionARM64::EmulateADDSUBImm,196"ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"},197{0xff000000, 0xb1000000, No_VFP,198&EmulateInstructionARM64::EmulateADDSUBImm,199"ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}"},200201{0xff000000, 0x51000000, No_VFP,202&EmulateInstructionARM64::EmulateADDSUBImm,203"SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"},204{0xff000000, 0x71000000, No_VFP,205&EmulateInstructionARM64::EmulateADDSUBImm,206"SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"},207{0xff000000, 0x11000000, No_VFP,208&EmulateInstructionARM64::EmulateADDSUBImm,209"ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"},210{0xff000000, 0x31000000, No_VFP,211&EmulateInstructionARM64::EmulateADDSUBImm,212"ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"},213214{0xffc00000, 0x29000000, No_VFP,215&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,216"STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},217{0xffc00000, 0xa9000000, No_VFP,218&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,219"STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},220{0xffc00000, 0x2d000000, No_VFP,221&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,222"STP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},223{0xffc00000, 0x6d000000, No_VFP,224&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,225"STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},226{0xffc00000, 0xad000000, No_VFP,227&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,228"STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},229230{0xffc00000, 0x29800000, No_VFP,231&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,232"STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},233{0xffc00000, 0xa9800000, No_VFP,234&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,235"STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},236{0xffc00000, 0x2d800000, No_VFP,237&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,238"STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},239{0xffc00000, 0x6d800000, No_VFP,240&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,241"STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},242{0xffc00000, 0xad800000, No_VFP,243&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,244"STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},245246{0xffc00000, 0x28800000, No_VFP,247&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,248"STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},249{0xffc00000, 0xa8800000, No_VFP,250&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,251"STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},252{0xffc00000, 0x2c800000, No_VFP,253&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,254"STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},255{0xffc00000, 0x6c800000, No_VFP,256&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,257"STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},258{0xffc00000, 0xac800000, No_VFP,259&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,260"STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},261262{0xffc00000, 0x29400000, No_VFP,263&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,264"LDP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},265{0xffc00000, 0xa9400000, No_VFP,266&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,267"LDP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},268{0xffc00000, 0x2d400000, No_VFP,269&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,270"LDP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},271{0xffc00000, 0x6d400000, No_VFP,272&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,273"LDP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},274{0xffc00000, 0xad400000, No_VFP,275&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,276"LDP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},277278{0xffc00000, 0x29c00000, No_VFP,279&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,280"LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},281{0xffc00000, 0xa9c00000, No_VFP,282&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,283"LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},284{0xffc00000, 0x2dc00000, No_VFP,285&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,286"LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},287{0xffc00000, 0x6dc00000, No_VFP,288&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,289"LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},290{0xffc00000, 0xadc00000, No_VFP,291&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,292"LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},293294{0xffc00000, 0x28c00000, No_VFP,295&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,296"LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},297{0xffc00000, 0xa8c00000, No_VFP,298&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,299"LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},300{0xffc00000, 0x2cc00000, No_VFP,301&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,302"LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},303{0xffc00000, 0x6cc00000, No_VFP,304&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,305"LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},306{0xffc00000, 0xacc00000, No_VFP,307&EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,308"LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},309310{0xffe00c00, 0xb8000400, No_VFP,311&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,312"STR <Wt>, [<Xn|SP>], #<simm>"},313{0xffe00c00, 0xf8000400, No_VFP,314&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,315"STR <Xt>, [<Xn|SP>], #<simm>"},316{0xffe00c00, 0xb8000c00, No_VFP,317&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,318"STR <Wt>, [<Xn|SP>, #<simm>]!"},319{0xffe00c00, 0xf8000c00, No_VFP,320&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,321"STR <Xt>, [<Xn|SP>, #<simm>]!"},322{0xffc00000, 0xb9000000, No_VFP,323&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,324"STR <Wt>, [<Xn|SP>{, #<pimm>}]"},325{0xffc00000, 0xf9000000, No_VFP,326&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,327"STR <Xt>, [<Xn|SP>{, #<pimm>}]"},328329{0xffe00c00, 0xb8400400, No_VFP,330&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,331"LDR <Wt>, [<Xn|SP>], #<simm>"},332{0xffe00c00, 0xf8400400, No_VFP,333&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,334"LDR <Xt>, [<Xn|SP>], #<simm>"},335{0xffe00c00, 0xb8400c00, No_VFP,336&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,337"LDR <Wt>, [<Xn|SP>, #<simm>]!"},338{0xffe00c00, 0xf8400c00, No_VFP,339&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,340"LDR <Xt>, [<Xn|SP>, #<simm>]!"},341{0xffc00000, 0xb9400000, No_VFP,342&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,343"LDR <Wt>, [<Xn|SP>{, #<pimm>}]"},344{0xffc00000, 0xf9400000, No_VFP,345&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,346"LDR <Xt>, [<Xn|SP>{, #<pimm>}]"},347348{0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB,349"B <label>"},350{0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond,351"B.<cond> <label>"},352{0x7f000000, 0x34000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,353"CBZ <Wt>, <label>"},354{0x7f000000, 0x35000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,355"CBNZ <Wt>, <label>"},356{0x7f000000, 0x36000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,357"TBZ <R><t>, #<imm>, <label>"},358{0x7f000000, 0x37000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,359"TBNZ <R><t>, #<imm>, <label>"},360361};362static const size_t k_num_arm_opcodes = std::size(g_opcodes);363364for (size_t i = 0; i < k_num_arm_opcodes; ++i) {365if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)366return &g_opcodes[i];367}368return nullptr;369}370371bool EmulateInstructionARM64::ReadInstruction() {372bool success = false;373m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,374LLDB_INVALID_ADDRESS, &success);375if (success) {376Context read_inst_context;377read_inst_context.type = eContextReadOpcode;378read_inst_context.SetNoArgs();379m_opcode.SetOpcode32(380ReadMemoryUnsigned(read_inst_context, m_addr, 4, 0, &success),381GetByteOrder());382}383if (!success)384m_addr = LLDB_INVALID_ADDRESS;385return success;386}387388bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) {389const uint32_t opcode = m_opcode.GetOpcode32();390Opcode *opcode_data = GetOpcodeForInstruction(opcode);391if (opcode_data == nullptr)392return false;393394const bool auto_advance_pc =395evaluate_options & eEmulateInstructionOptionAutoAdvancePC;396m_ignore_conditions =397evaluate_options & eEmulateInstructionOptionIgnoreConditions;398399bool success = false;400401// Only return false if we are unable to read the CPSR if we care about402// conditions403if (!success && !m_ignore_conditions)404return false;405406uint32_t orig_pc_value = 0;407if (auto_advance_pc) {408orig_pc_value =409ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success);410if (!success)411return false;412}413414// Call the Emulate... function.415success = (this->*opcode_data->callback)(opcode);416if (!success)417return false;418419if (auto_advance_pc) {420uint32_t new_pc_value =421ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success);422if (!success)423return false;424425if (new_pc_value == orig_pc_value) {426EmulateInstruction::Context context;427context.type = eContextAdvancePC;428context.SetNoArgs();429if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_arm64,430orig_pc_value + 4))431return false;432}433}434return true;435}436437bool EmulateInstructionARM64::CreateFunctionEntryUnwind(438UnwindPlan &unwind_plan) {439unwind_plan.Clear();440unwind_plan.SetRegisterKind(eRegisterKindLLDB);441442UnwindPlan::RowSP row(new UnwindPlan::Row);443444// Our previous Call Frame Address is the stack pointer445row->GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_arm64, 0);446row->SetRegisterLocationToSame(gpr_lr_arm64, /*must_replace=*/false);447row->SetRegisterLocationToSame(gpr_fp_arm64, /*must_replace=*/false);448449unwind_plan.AppendRow(row);450unwind_plan.SetSourceName("EmulateInstructionARM64");451unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);452unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);453unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);454unwind_plan.SetReturnAddressRegister(gpr_lr_arm64);455return true;456}457458uint32_t EmulateInstructionARM64::GetFramePointerRegisterNumber() const {459if (m_arch.GetTriple().isAndroid())460return LLDB_INVALID_REGNUM; // Don't use frame pointer on android461462return gpr_fp_arm64;463}464465bool EmulateInstructionARM64::UsingAArch32() {466bool aarch32 = m_opcode_pstate.RW == 1;467// if !HaveAnyAArch32() then assert !aarch32;468// if HighestELUsingAArch32() then assert aarch32;469return aarch32;470}471472bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N,473addr_t target) {474#if 0475// Set program counter to a new address, with a branch reason hint for476// possible use by hardware fetching the next instruction.477BranchTo(bits(N) target, BranchType branch_type)478Hint_Branch(branch_type);479if N == 32 then480assert UsingAArch32();481_PC = ZeroExtend(target);482else483assert N == 64 && !UsingAArch32();484// Remove the tag bits from a tagged target485case PSTATE.EL of486when EL0, EL1487if target<55> == '1' && TCR_EL1.TBI1 == '1' then488target<63:56> = '11111111';489if target<55> == '0' && TCR_EL1.TBI0 == '1' then490target<63:56> = '00000000';491when EL2492if TCR_EL2.TBI == '1' then493target<63:56> = '00000000';494when EL3495if TCR_EL3.TBI == '1' then496target<63:56> = '00000000';497_PC = target<63:0>;498return;499#endif500501addr_t addr;502503// Hint_Branch(branch_type);504if (N == 32) {505if (!UsingAArch32())506return false;507addr = target;508} else if (N == 64) {509if (UsingAArch32())510return false;511// TODO: Remove the tag bits from a tagged target512addr = target;513} else514return false;515516return WriteRegisterUnsigned(context, eRegisterKindGeneric,517LLDB_REGNUM_GENERIC_PC, addr);518}519520bool EmulateInstructionARM64::ConditionHolds(const uint32_t cond) {521// If we are ignoring conditions, then always return true. this allows us to522// iterate over disassembly code and still emulate an instruction even if we523// don't have all the right bits set in the CPSR register...524if (m_ignore_conditions)525return true;526527bool result = false;528switch (UnsignedBits(cond, 3, 1)) {529case 0:530result = (m_opcode_pstate.Z == 1);531break;532case 1:533result = (m_opcode_pstate.C == 1);534break;535case 2:536result = (m_opcode_pstate.N == 1);537break;538case 3:539result = (m_opcode_pstate.V == 1);540break;541case 4:542result = (m_opcode_pstate.C == 1 && m_opcode_pstate.Z == 0);543break;544case 5:545result = (m_opcode_pstate.N == m_opcode_pstate.V);546break;547case 6:548result = (m_opcode_pstate.N == m_opcode_pstate.V && m_opcode_pstate.Z == 0);549break;550case 7:551// Always execute (cond == 0b1110, or the special 0b1111 which gives552// opcodes different meanings, but always means execution happens.553return true;554}555556if (cond & 1)557result = !result;558return result;559}560561uint64_t EmulateInstructionARM64::562AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in,563EmulateInstructionARM64::ProcState &proc_state) {564uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);565std::optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y));566bool overflow = !signed_sum;567if (!overflow)568overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in));569uint64_t result = unsigned_sum;570if (N < 64)571result = Bits64(result, N - 1, 0);572proc_state.N = Bit64(result, N - 1);573proc_state.Z = IsZero(result);574proc_state.C = UInt(result) != unsigned_sum;575proc_state.V = overflow;576return result;577}578579bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) {580// integer d = UInt(Rd);581// integer n = UInt(Rn);582// integer datasize = if sf == 1 then 64 else 32;583// boolean sub_op = (op == 1);584// boolean setflags = (S == 1);585// bits(datasize) imm;586//587// case shift of588// when '00' imm = ZeroExtend(imm12, datasize);589// when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize);590// when '1x' UNDEFINED;591//592//593// bits(datasize) result;594// bits(datasize) operand1 = if n == 31 then SP[] else X[n];595// bits(datasize) operand2 = imm;596// bits(4) nzcv;597// bit carry_in;598//599// if sub_op then600// operand2 = NOT(operand2);601// carry_in = 1;602// else603// carry_in = 0;604//605// (result, nzcv) = AddWithCarry(operand1, operand2, carry_in);606//607// if setflags then608// PSTATE.NZCV = nzcv;609//610// if d == 31 && !setflags then611// SP[] = result;612// else613// X[d] = result;614615const uint32_t sf = Bit32(opcode, 31);616const uint32_t op = Bit32(opcode, 30);617const uint32_t S = Bit32(opcode, 29);618const uint32_t shift = Bits32(opcode, 23, 22);619const uint32_t imm12 = Bits32(opcode, 21, 10);620const uint32_t Rn = Bits32(opcode, 9, 5);621const uint32_t Rd = Bits32(opcode, 4, 0);622623bool success = false;624625const uint32_t d = UInt(Rd);626const uint32_t n = UInt(Rn);627const uint32_t datasize = (sf == 1) ? 64 : 32;628boolean sub_op = op == 1;629boolean setflags = S == 1;630uint64_t imm;631632switch (shift) {633case 0:634imm = imm12;635break;636case 1:637imm = static_cast<uint64_t>(imm12) << 12;638break;639default:640return false; // UNDEFINED;641}642uint64_t result;643uint64_t operand1 =644ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);645uint64_t operand2 = imm;646bit carry_in;647648if (sub_op) {649operand2 = NOT(operand2);650carry_in = true;651imm = -imm; // For the Register plug offset context below652} else {653carry_in = false;654}655656ProcState proc_state;657658result = AddWithCarry(datasize, operand1, operand2, carry_in, proc_state);659660if (setflags) {661m_emulated_pstate.N = proc_state.N;662m_emulated_pstate.Z = proc_state.Z;663m_emulated_pstate.C = proc_state.C;664m_emulated_pstate.V = proc_state.V;665}666667Context context;668std::optional<RegisterInfo> reg_info_Rn =669GetRegisterInfo(eRegisterKindLLDB, n);670if (reg_info_Rn)671context.SetRegisterPlusOffset(*reg_info_Rn, imm);672673if (n == GetFramePointerRegisterNumber() && d == gpr_sp_arm64 && !setflags) {674// 'mov sp, fp' - common epilogue instruction, CFA is now in terms of the675// stack pointer, instead of frame pointer.676context.type = EmulateInstruction::eContextRestoreStackPointer;677} else if ((n == gpr_sp_arm64 || n == GetFramePointerRegisterNumber()) &&678d == gpr_sp_arm64 && !setflags) {679context.type = EmulateInstruction::eContextAdjustStackPointer;680} else if (d == GetFramePointerRegisterNumber() && n == gpr_sp_arm64 &&681!setflags) {682context.type = EmulateInstruction::eContextSetFramePointer;683} else {684context.type = EmulateInstruction::eContextImmediate;685}686687// If setflags && d == gpr_sp_arm64 then d = WZR/XZR. See CMN, CMP688if (!setflags || d != gpr_sp_arm64)689WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_x0_arm64 + d, result);690691return false;692}693694template <EmulateInstructionARM64::AddrMode a_mode>695bool EmulateInstructionARM64::EmulateLDPSTP(const uint32_t opcode) {696uint32_t opc = Bits32(opcode, 31, 30);697uint32_t V = Bit32(opcode, 26);698uint32_t L = Bit32(opcode, 22);699uint32_t imm7 = Bits32(opcode, 21, 15);700uint32_t Rt2 = Bits32(opcode, 14, 10);701uint32_t Rn = Bits32(opcode, 9, 5);702uint32_t Rt = Bits32(opcode, 4, 0);703704integer n = UInt(Rn);705integer t = UInt(Rt);706integer t2 = UInt(Rt2);707uint64_t idx;708709MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE;710boolean vector = (V == 1);711// AccType acctype = AccType_NORMAL;712boolean is_signed = false;713boolean wback = a_mode != AddrMode_OFF;714boolean wb_unknown = false;715boolean rt_unknown = false;716integer scale;717integer size;718719if (opc == 3)720return false; // UNDEFINED721722if (vector) {723scale = 2 + UInt(opc);724} else {725scale = (opc & 2) ? 3 : 2;726is_signed = (opc & 1) != 0;727if (is_signed && memop == MemOp_STORE)728return false; // UNDEFINED729}730731if (!vector && wback && ((t == n) || (t2 == n))) {732switch (ConstrainUnpredictable(Unpredictable_WBOVERLAP)) {733case Constraint_UNKNOWN:734wb_unknown = true; // writeback is UNKNOWN735break;736737case Constraint_SUPPRESSWB:738wback = false; // writeback is suppressed739break;740741case Constraint_NOP:742memop = MemOp_NOP; // do nothing743wback = false;744break;745746case Constraint_NONE:747break;748}749}750751if (memop == MemOp_LOAD && t == t2) {752switch (ConstrainUnpredictable(Unpredictable_LDPOVERLAP)) {753case Constraint_UNKNOWN:754rt_unknown = true; // result is UNKNOWN755break;756757case Constraint_NOP:758memop = MemOp_NOP; // do nothing759wback = false;760break;761762default:763break;764}765}766767idx = LSL(llvm::SignExtend64<7>(imm7), scale);768size = (integer)1 << scale;769uint64_t datasize = size * 8;770uint64_t address;771uint64_t wb_address;772773std::optional<RegisterInfo> reg_info_base =774GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + n);775if (!reg_info_base)776return false;777778std::optional<RegisterInfo> reg_info_Rt;779std::optional<RegisterInfo> reg_info_Rt2;780781if (vector) {782reg_info_Rt = GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t);783reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t2);784} else {785reg_info_Rt = GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);786reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t2);787}788789if (!reg_info_Rt || !reg_info_Rt2)790return false;791792bool success = false;793if (n == 31) {794// CheckSPAlignment();795address =796ReadRegisterUnsigned(eRegisterKindLLDB, gpr_sp_arm64, 0, &success);797} else798address =799ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);800801wb_address = address + idx;802if (a_mode != AddrMode_POST)803address = wb_address;804805Context context_t;806Context context_t2;807808RegisterValue::BytesContainer buffer;809Status error;810811switch (memop) {812case MemOp_STORE: {813if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is814// based off of the sp815// or fp register816{817context_t.type = eContextPushRegisterOnStack;818context_t2.type = eContextPushRegisterOnStack;819} else {820context_t.type = eContextRegisterStore;821context_t2.type = eContextRegisterStore;822}823context_t.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base, 0);824context_t2.SetRegisterToRegisterPlusOffset(*reg_info_Rt2, *reg_info_base,825size);826827std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt);828if (!data_Rt)829return false;830831buffer.resize(reg_info_Rt->byte_size);832if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer.data(),833reg_info_Rt->byte_size, eByteOrderLittle,834error) == 0)835return false;836837if (!WriteMemory(context_t, address + 0, buffer.data(),838reg_info_Rt->byte_size))839return false;840841std::optional<RegisterValue> data_Rt2 = ReadRegister(*reg_info_Rt2);842if (!data_Rt2)843return false;844845buffer.resize(reg_info_Rt2->byte_size);846if (data_Rt2->GetAsMemoryData(*reg_info_Rt2, buffer.data(),847reg_info_Rt2->byte_size, eByteOrderLittle,848error) == 0)849return false;850851if (!WriteMemory(context_t2, address + size, buffer.data(),852reg_info_Rt2->byte_size))853return false;854} break;855856case MemOp_LOAD: {857if (n == 31 || n == GetFramePointerRegisterNumber()) // if this load is858// based off of the sp859// or fp register860{861context_t.type = eContextPopRegisterOffStack;862context_t2.type = eContextPopRegisterOffStack;863} else {864context_t.type = eContextRegisterLoad;865context_t2.type = eContextRegisterLoad;866}867context_t.SetAddress(address);868context_t2.SetAddress(address + size);869870buffer.resize(reg_info_Rt->byte_size);871if (rt_unknown)872std::fill(buffer.begin(), buffer.end(), 'U');873else {874if (!ReadMemory(context_t, address, buffer.data(),875reg_info_Rt->byte_size))876return false;877}878879RegisterValue data_Rt;880if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer.data(),881reg_info_Rt->byte_size, eByteOrderLittle,882error) == 0)883return false;884885if (!vector && is_signed && !data_Rt.SignExtend(datasize))886return false;887888if (!WriteRegister(context_t, *reg_info_Rt, data_Rt))889return false;890891buffer.resize(reg_info_Rt2->byte_size);892if (!rt_unknown)893if (!ReadMemory(context_t2, address + size, buffer.data(),894reg_info_Rt2->byte_size))895return false;896897RegisterValue data_Rt2;898if (data_Rt2.SetFromMemoryData(*reg_info_Rt2, buffer.data(),899reg_info_Rt2->byte_size, eByteOrderLittle,900error) == 0)901return false;902903if (!vector && is_signed && !data_Rt2.SignExtend(datasize))904return false;905906if (!WriteRegister(context_t2, *reg_info_Rt2, data_Rt2))907return false;908} break;909910default:911break;912}913914if (wback) {915if (wb_unknown)916wb_address = LLDB_INVALID_ADDRESS;917Context context;918context.SetImmediateSigned(idx);919if (n == 31)920context.type = eContextAdjustStackPointer;921else922context.type = eContextAdjustBaseRegister;923WriteRegisterUnsigned(context, *reg_info_base, wb_address);924}925return true;926}927928template <EmulateInstructionARM64::AddrMode a_mode>929bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {930uint32_t size = Bits32(opcode, 31, 30);931uint32_t opc = Bits32(opcode, 23, 22);932uint32_t n = Bits32(opcode, 9, 5);933uint32_t t = Bits32(opcode, 4, 0);934935bool wback;936bool postindex;937uint64_t offset;938939switch (a_mode) {940case AddrMode_POST:941wback = true;942postindex = true;943offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));944break;945case AddrMode_PRE:946wback = true;947postindex = false;948offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));949break;950case AddrMode_OFF:951wback = false;952postindex = false;953offset = LSL(Bits32(opcode, 21, 10), size);954break;955}956957MemOp memop;958959if (Bit32(opc, 1) == 0) {960memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;961} else {962memop = MemOp_LOAD;963if (size == 2 && Bit32(opc, 0) == 1)964return false;965}966967Status error;968bool success = false;969uint64_t address;970RegisterValue::BytesContainer buffer;971972if (n == 31)973address =974ReadRegisterUnsigned(eRegisterKindLLDB, gpr_sp_arm64, 0, &success);975else976address =977ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);978979if (!success)980return false;981982if (!postindex)983address += offset;984985std::optional<RegisterInfo> reg_info_base =986GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + n);987if (!reg_info_base)988return false;989990std::optional<RegisterInfo> reg_info_Rt =991GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);992if (!reg_info_Rt)993return false;994995Context context;996switch (memop) {997case MemOp_STORE: {998if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is999// based off of the sp1000// or fp register1001context.type = eContextPushRegisterOnStack;1002else1003context.type = eContextRegisterStore;1004context.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base,1005postindex ? 0 : offset);10061007std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt);1008if (!data_Rt)1009return false;10101011buffer.resize(reg_info_Rt->byte_size);1012if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer.data(),1013reg_info_Rt->byte_size, eByteOrderLittle,1014error) == 0)1015return false;10161017if (!WriteMemory(context, address, buffer.data(), reg_info_Rt->byte_size))1018return false;1019} break;10201021case MemOp_LOAD: {1022if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is1023// based off of the sp1024// or fp register1025context.type = eContextPopRegisterOffStack;1026else1027context.type = eContextRegisterLoad;1028context.SetAddress(address);10291030buffer.resize(reg_info_Rt->byte_size);1031if (!ReadMemory(context, address, buffer.data(), reg_info_Rt->byte_size))1032return false;10331034RegisterValue data_Rt;1035if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer.data(),1036reg_info_Rt->byte_size, eByteOrderLittle,1037error) == 0)1038return false;10391040if (!WriteRegister(context, *reg_info_Rt, data_Rt))1041return false;1042} break;1043default:1044return false;1045}10461047if (wback) {1048if (postindex)1049address += offset;10501051if (n == 31)1052context.type = eContextAdjustStackPointer;1053else1054context.type = eContextAdjustBaseRegister;1055context.SetImmediateSigned(offset);10561057if (!WriteRegisterUnsigned(context, *reg_info_base, address))1058return false;1059}1060return true;1061}10621063bool EmulateInstructionARM64::EmulateB(const uint32_t opcode) {1064#if 01065// ARM64 pseudo code...1066if branch_type == BranchType_CALL then X[30] = PC[] + 4;1067BranchTo(PC[] + offset, branch_type);1068#endif10691070bool success = false;10711072EmulateInstruction::Context context;1073context.type = EmulateInstruction::eContextRelativeBranchImmediate;1074const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric,1075LLDB_REGNUM_GENERIC_PC, 0, &success);1076if (!success)1077return false;10781079int64_t offset = llvm::SignExtend64<28>(Bits32(opcode, 25, 0) << 2);1080BranchType branch_type = Bit32(opcode, 31) ? BranchType_CALL : BranchType_JMP;1081addr_t target = pc + offset;1082context.SetImmediateSigned(offset);10831084switch (branch_type) {1085case BranchType_CALL: {1086addr_t x30 = pc + 4;1087if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_lr_arm64, x30))1088return false;1089} break;1090case BranchType_JMP:1091break;1092default:1093return false;1094}10951096return BranchTo(context, 64, target);1097}10981099bool EmulateInstructionARM64::EmulateBcond(const uint32_t opcode) {1100#if 01101// ARM64 pseudo code...1102bits(64) offset = SignExtend(imm19:'00', 64);1103bits(4) condition = cond;1104if ConditionHolds(condition) then1105BranchTo(PC[] + offset, BranchType_JMP);1106#endif11071108if (ConditionHolds(Bits32(opcode, 3, 0))) {1109bool success = false;11101111const uint64_t pc = ReadRegisterUnsigned(1112eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);1113if (!success)1114return false;11151116int64_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);1117addr_t target = pc + offset;11181119EmulateInstruction::Context context;1120context.type = EmulateInstruction::eContextRelativeBranchImmediate;1121context.SetImmediateSigned(offset);1122if (!BranchTo(context, 64, target))1123return false;1124}1125return true;1126}11271128bool EmulateInstructionARM64::EmulateCBZ(const uint32_t opcode) {1129#if 01130integer t = UInt(Rt);1131integer datasize = if sf == '1' then 64 else 32;1132boolean iszero = (op == '0');1133bits(64) offset = SignExtend(imm19:'00', 64);11341135bits(datasize) operand1 = X[t];1136if IsZero(operand1) == iszero then1137BranchTo(PC[] + offset, BranchType_JMP);1138#endif11391140bool success = false;11411142uint32_t t = Bits32(opcode, 4, 0);1143bool is_zero = Bit32(opcode, 24) == 0;1144int32_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);11451146const uint64_t operand =1147ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + t, 0, &success);1148if (!success)1149return false;11501151if (m_ignore_conditions || ((operand == 0) == is_zero)) {1152const uint64_t pc = ReadRegisterUnsigned(1153eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);1154if (!success)1155return false;11561157EmulateInstruction::Context context;1158context.type = EmulateInstruction::eContextRelativeBranchImmediate;1159context.SetImmediateSigned(offset);1160if (!BranchTo(context, 64, pc + offset))1161return false;1162}1163return true;1164}11651166bool EmulateInstructionARM64::EmulateTBZ(const uint32_t opcode) {1167#if 01168integer t = UInt(Rt);1169integer datasize = if b5 == '1' then 64 else 32;1170integer bit_pos = UInt(b5:b40);1171bit bit_val = op;1172bits(64) offset = SignExtend(imm14:'00', 64);1173#endif11741175bool success = false;11761177uint32_t t = Bits32(opcode, 4, 0);1178uint32_t bit_pos = (Bit32(opcode, 31) << 6) | (Bits32(opcode, 23, 19));1179uint32_t bit_val = Bit32(opcode, 24);1180int64_t offset = llvm::SignExtend64<16>(Bits32(opcode, 18, 5) << 2);11811182const uint64_t operand =1183ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + t, 0, &success);1184if (!success)1185return false;11861187if (m_ignore_conditions || Bit32(operand, bit_pos) == bit_val) {1188const uint64_t pc = ReadRegisterUnsigned(1189eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);1190if (!success)1191return false;11921193EmulateInstruction::Context context;1194context.type = EmulateInstruction::eContextRelativeBranchImmediate;1195context.SetImmediateSigned(offset);1196if (!BranchTo(context, 64, pc + offset))1197return false;1198}1199return true;1200}120112021203