//===-- EmulateInstructionARM64.h -------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM64_EMULATEINSTRUCTIONARM64_H #define LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM64_EMULATEINSTRUCTIONARM64_H #include "Plugins/Process/Utility/ARMDefines.h" #include "lldb/Core/EmulateInstruction.h" #include "lldb/Interpreter/OptionValue.h" #include "lldb/Utility/Status.h" class EmulateInstructionARM64 : public lldb_private::EmulateInstruction { public: EmulateInstructionARM64(const lldb_private::ArchSpec &arch) : EmulateInstruction(arch), m_opcode_pstate(), m_emulated_pstate(), m_ignore_conditions(false) {} static void Initialize(); static void Terminate(); static lldb_private::ConstString GetPluginNameStatic(); static const char *GetPluginDescriptionStatic(); static lldb_private::EmulateInstruction * CreateInstance(const lldb_private::ArchSpec &arch, lldb_private::InstructionType inst_type); static bool SupportsEmulatingInstructionsOfTypeStatic( lldb_private::InstructionType inst_type) { switch (inst_type) { case lldb_private::eInstructionTypeAny: case lldb_private::eInstructionTypePrologueEpilogue: return true; case lldb_private::eInstructionTypePCModifying: case lldb_private::eInstructionTypeAll: return false; } return false; } lldb_private::ConstString GetPluginName() override; uint32_t GetPluginVersion() override { return 1; } bool SetTargetTriple(const lldb_private::ArchSpec &arch) override; bool SupportsEmulatingInstructionsOfType( lldb_private::InstructionType inst_type) override { return SupportsEmulatingInstructionsOfTypeStatic(inst_type); } bool ReadInstruction() override; bool EvaluateInstruction(uint32_t evaluate_options) override; bool TestEmulation(lldb_private::Stream *out_stream, lldb_private::ArchSpec &arch, lldb_private::OptionValueDictionary *test_data) override { return false; } bool GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num, lldb_private::RegisterInfo ®_info) override; bool CreateFunctionEntryUnwind(lldb_private::UnwindPlan &unwind_plan) override; enum AddrMode { AddrMode_OFF, AddrMode_PRE, AddrMode_POST }; enum BranchType { BranchType_CALL, BranchType_ERET, BranchType_DRET, BranchType_RET, BranchType_JMP }; enum CountOp { CountOp_CLZ, CountOp_CLS, CountOp_CNT }; enum RevOp { RevOp_RBIT, RevOp_REV16, RevOp_REV32, RevOp_REV64 }; enum BitwiseOp { BitwiseOp_NOT, BitwiseOp_RBIT }; enum ExceptionLevel { EL0 = 0, EL1 = 1, EL2 = 2, EL3 = 3 }; enum ExtendType { ExtendType_SXTB, ExtendType_SXTH, ExtendType_SXTW, ExtendType_SXTX, ExtendType_UXTB, ExtendType_UXTH, ExtendType_UXTW, ExtendType_UXTX }; enum ExtractType { ExtractType_LEFT, ExtractType_RIGHT }; enum LogicalOp { LogicalOp_AND, LogicalOp_EOR, LogicalOp_ORR }; enum MemOp { MemOp_LOAD, MemOp_STORE, MemOp_PREFETCH, MemOp_NOP }; enum MoveWideOp { MoveWideOp_N, MoveWideOp_Z, MoveWideOp_K }; enum ShiftType { ShiftType_LSL, ShiftType_LSR, ShiftType_ASR, ShiftType_ROR }; enum StackPointerSelection { SP0 = 0, SPx = 1 }; enum Unpredictable { Unpredictable_WBOVERLAP, Unpredictable_LDPOVERLAP }; enum ConstraintType { Constraint_NONE, Constraint_UNKNOWN, Constraint_SUPPRESSWB, Constraint_NOP }; enum AccType { AccType_NORMAL, AccType_UNPRIV, AccType_STREAM, AccType_ALIGNED, AccType_ORDERED }; typedef struct { uint32_t N : 1, V : 1, C : 1, Z : 1, // condition code flags – can also be accessed as // PSTATE.[N,Z,C,V] Q : 1, // AArch32 only – CSPR.Q bit IT : 8, // AArch32 only – CPSR.IT bits J : 1, // AArch32 only – CSPR.J bit T : 1, // AArch32 only – CPSR.T bit SS : 1, // Single step process state bit IL : 1, // Illegal state bit D : 1, A : 1, I : 1, F : 1, // Interrupt masks – can also be accessed as PSTATE.[D,A,I,F] E : 1, // AArch32 only – CSPR.E bit M : 5, // AArch32 only – mode encodings RW : 1, // Current register width – 0 is AArch64, 1 is AArch32 EL : 2, // Current exception level (see ExceptionLevel enum) SP : 1; // AArch64 only - Stack Pointer selection (see // StackPointerSelection enum) } ProcState; protected: static uint64_t AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bool carry_in, EmulateInstructionARM64::ProcState &proc_state); typedef struct { uint32_t mask; uint32_t value; uint32_t vfp_variants; bool (EmulateInstructionARM64::*callback)(const uint32_t opcode); const char *name; } Opcode; static Opcode *GetOpcodeForInstruction(const uint32_t opcode); uint32_t GetFramePointerRegisterNumber() const; bool BranchTo(const Context &context, uint32_t N, lldb::addr_t target); bool ConditionHolds(const uint32_t cond); bool UsingAArch32(); bool EmulateADDSUBImm(const uint32_t opcode); template bool EmulateLDPSTP(const uint32_t opcode); template bool EmulateLDRSTRImm(const uint32_t opcode); bool EmulateB(const uint32_t opcode); bool EmulateBcond(const uint32_t opcode); bool EmulateCBZ(const uint32_t opcode); bool EmulateTBZ(const uint32_t opcode); ProcState m_opcode_pstate; ProcState m_emulated_pstate; // This can get updated by the opcode. bool m_ignore_conditions; }; #endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM64_EMULATEINSTRUCTIONARM64_H