1dda28197Spatrick //===-- EmulateInstructionARM64.cpp ---------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "EmulateInstructionARM64.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Core/Address.h"
12061da546Spatrick #include "lldb/Core/PluginManager.h"
13061da546Spatrick #include "lldb/Symbol/UnwindPlan.h"
14061da546Spatrick #include "lldb/Utility/ArchSpec.h"
15061da546Spatrick #include "lldb/Utility/ConstString.h"
16061da546Spatrick #include "lldb/Utility/RegisterValue.h"
17061da546Spatrick #include "lldb/Utility/Stream.h"
18061da546Spatrick
19dda28197Spatrick #include "llvm/Support/CheckedArithmetic.h"
20dda28197Spatrick
21061da546Spatrick #include "Plugins/Process/Utility/ARMDefines.h"
22061da546Spatrick #include "Plugins/Process/Utility/ARMUtils.h"
23061da546Spatrick #include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
24061da546Spatrick
25dda28197Spatrick #include <cstdlib>
26*f6aab3d8Srobert #include <optional>
27dda28197Spatrick
28061da546Spatrick #define GPR_OFFSET(idx) ((idx)*8)
29061da546Spatrick #define GPR_OFFSET_NAME(reg) 0
30061da546Spatrick #define FPU_OFFSET(idx) ((idx)*16)
31061da546Spatrick #define FPU_OFFSET_NAME(reg) 0
32061da546Spatrick #define EXC_OFFSET_NAME(reg) 0
33061da546Spatrick #define DBG_OFFSET_NAME(reg) 0
34061da546Spatrick #define DBG_OFFSET_NAME(reg) 0
35061da546Spatrick #define DEFINE_DBG(re, y) \
36061da546Spatrick "na", nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \
37061da546Spatrick {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
38061da546Spatrick LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, \
39*f6aab3d8Srobert nullptr, nullptr
40061da546Spatrick
41061da546Spatrick #define DECLARE_REGISTER_INFOS_ARM64_STRUCT
42061da546Spatrick
43061da546Spatrick #include "Plugins/Process/Utility/RegisterInfos_arm64.h"
44061da546Spatrick
45061da546Spatrick #include "llvm/ADT/STLExtras.h"
46061da546Spatrick #include "llvm/Support/MathExtras.h"
47061da546Spatrick
48061da546Spatrick #include "Plugins/Process/Utility/InstructionUtils.h"
49061da546Spatrick
50061da546Spatrick using namespace lldb;
51061da546Spatrick using namespace lldb_private;
52061da546Spatrick
LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM64,InstructionARM64)53dda28197Spatrick LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM64, InstructionARM64)
54dda28197Spatrick
55*f6aab3d8Srobert static std::optional<RegisterInfo> LLDBTableGetRegisterInfo(uint32_t reg_num) {
56*f6aab3d8Srobert if (reg_num >= std::size(g_register_infos_arm64_le))
57*f6aab3d8Srobert return {};
58*f6aab3d8Srobert return g_register_infos_arm64_le[reg_num];
59061da546Spatrick }
60061da546Spatrick
61061da546Spatrick #define No_VFP 0
62061da546Spatrick #define VFPv1 (1u << 1)
63061da546Spatrick #define VFPv2 (1u << 2)
64061da546Spatrick #define VFPv3 (1u << 3)
65061da546Spatrick #define AdvancedSIMD (1u << 4)
66061da546Spatrick
67061da546Spatrick #define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)
68061da546Spatrick #define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)
69061da546Spatrick #define VFPv2v3 (VFPv2 | VFPv3)
70061da546Spatrick
71061da546Spatrick #define UInt(x) ((uint64_t)x)
72061da546Spatrick #define SInt(x) ((int64_t)x)
73061da546Spatrick #define bit bool
74061da546Spatrick #define boolean bool
75061da546Spatrick #define integer int64_t
76061da546Spatrick
IsZero(uint64_t x)77061da546Spatrick static inline bool IsZero(uint64_t x) { return x == 0; }
78061da546Spatrick
NOT(uint64_t x)79061da546Spatrick static inline uint64_t NOT(uint64_t x) { return ~x; }
80061da546Spatrick
81061da546Spatrick // LSL()
82061da546Spatrick // =====
83061da546Spatrick
LSL(uint64_t x,integer shift)84061da546Spatrick static inline uint64_t LSL(uint64_t x, integer shift) {
85061da546Spatrick if (shift == 0)
86061da546Spatrick return x;
87061da546Spatrick return x << shift;
88061da546Spatrick }
89061da546Spatrick
90061da546Spatrick // ConstrainUnpredictable()
91061da546Spatrick // ========================
92061da546Spatrick
93061da546Spatrick EmulateInstructionARM64::ConstraintType
ConstrainUnpredictable(EmulateInstructionARM64::Unpredictable which)94061da546Spatrick ConstrainUnpredictable(EmulateInstructionARM64::Unpredictable which) {
95061da546Spatrick EmulateInstructionARM64::ConstraintType result =
96061da546Spatrick EmulateInstructionARM64::Constraint_UNKNOWN;
97061da546Spatrick switch (which) {
98061da546Spatrick case EmulateInstructionARM64::Unpredictable_WBOVERLAP:
99061da546Spatrick case EmulateInstructionARM64::Unpredictable_LDPOVERLAP:
100061da546Spatrick // TODO: don't know what to really do here? Pseudo code says:
101061da546Spatrick // set result to one of above Constraint behaviours or UNDEFINED
102061da546Spatrick break;
103061da546Spatrick }
104061da546Spatrick return result;
105061da546Spatrick }
106061da546Spatrick
107061da546Spatrick //
108061da546Spatrick // EmulateInstructionARM implementation
109061da546Spatrick //
110061da546Spatrick
Initialize()111061da546Spatrick void EmulateInstructionARM64::Initialize() {
112061da546Spatrick PluginManager::RegisterPlugin(GetPluginNameStatic(),
113061da546Spatrick GetPluginDescriptionStatic(), CreateInstance);
114061da546Spatrick }
115061da546Spatrick
Terminate()116061da546Spatrick void EmulateInstructionARM64::Terminate() {
117061da546Spatrick PluginManager::UnregisterPlugin(CreateInstance);
118061da546Spatrick }
119061da546Spatrick
GetPluginDescriptionStatic()120*f6aab3d8Srobert llvm::StringRef EmulateInstructionARM64::GetPluginDescriptionStatic() {
121061da546Spatrick return "Emulate instructions for the ARM64 architecture.";
122061da546Spatrick }
123061da546Spatrick
124061da546Spatrick EmulateInstruction *
CreateInstance(const ArchSpec & arch,InstructionType inst_type)125061da546Spatrick EmulateInstructionARM64::CreateInstance(const ArchSpec &arch,
126061da546Spatrick InstructionType inst_type) {
127061da546Spatrick if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic(
128061da546Spatrick inst_type)) {
129061da546Spatrick if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
130061da546Spatrick arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {
131061da546Spatrick return new EmulateInstructionARM64(arch);
132061da546Spatrick }
133061da546Spatrick }
134061da546Spatrick
135061da546Spatrick return nullptr;
136061da546Spatrick }
137061da546Spatrick
SetTargetTriple(const ArchSpec & arch)138061da546Spatrick bool EmulateInstructionARM64::SetTargetTriple(const ArchSpec &arch) {
139061da546Spatrick if (arch.GetTriple().getArch() == llvm::Triple::arm)
140061da546Spatrick return true;
141061da546Spatrick else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
142061da546Spatrick return true;
143061da546Spatrick
144061da546Spatrick return false;
145061da546Spatrick }
146061da546Spatrick
147*f6aab3d8Srobert std::optional<RegisterInfo>
GetRegisterInfo(RegisterKind reg_kind,uint32_t reg_num)148*f6aab3d8Srobert EmulateInstructionARM64::GetRegisterInfo(RegisterKind reg_kind,
149*f6aab3d8Srobert uint32_t reg_num) {
150061da546Spatrick if (reg_kind == eRegisterKindGeneric) {
151061da546Spatrick switch (reg_num) {
152061da546Spatrick case LLDB_REGNUM_GENERIC_PC:
153061da546Spatrick reg_kind = eRegisterKindLLDB;
154061da546Spatrick reg_num = gpr_pc_arm64;
155061da546Spatrick break;
156061da546Spatrick case LLDB_REGNUM_GENERIC_SP:
157061da546Spatrick reg_kind = eRegisterKindLLDB;
158061da546Spatrick reg_num = gpr_sp_arm64;
159061da546Spatrick break;
160061da546Spatrick case LLDB_REGNUM_GENERIC_FP:
161061da546Spatrick reg_kind = eRegisterKindLLDB;
162061da546Spatrick reg_num = gpr_fp_arm64;
163061da546Spatrick break;
164061da546Spatrick case LLDB_REGNUM_GENERIC_RA:
165061da546Spatrick reg_kind = eRegisterKindLLDB;
166061da546Spatrick reg_num = gpr_lr_arm64;
167061da546Spatrick break;
168061da546Spatrick case LLDB_REGNUM_GENERIC_FLAGS:
169061da546Spatrick reg_kind = eRegisterKindLLDB;
170061da546Spatrick reg_num = gpr_cpsr_arm64;
171061da546Spatrick break;
172061da546Spatrick
173061da546Spatrick default:
174*f6aab3d8Srobert return {};
175061da546Spatrick }
176061da546Spatrick }
177061da546Spatrick
178061da546Spatrick if (reg_kind == eRegisterKindLLDB)
179*f6aab3d8Srobert return LLDBTableGetRegisterInfo(reg_num);
180*f6aab3d8Srobert return {};
181061da546Spatrick }
182061da546Spatrick
183061da546Spatrick EmulateInstructionARM64::Opcode *
GetOpcodeForInstruction(const uint32_t opcode)184061da546Spatrick EmulateInstructionARM64::GetOpcodeForInstruction(const uint32_t opcode) {
185061da546Spatrick static EmulateInstructionARM64::Opcode g_opcodes[] = {
186061da546Spatrick // Prologue instructions
187061da546Spatrick
188061da546Spatrick // push register(s)
189061da546Spatrick {0xff000000, 0xd1000000, No_VFP,
190061da546Spatrick &EmulateInstructionARM64::EmulateADDSUBImm,
191061da546Spatrick "SUB <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"},
192061da546Spatrick {0xff000000, 0xf1000000, No_VFP,
193061da546Spatrick &EmulateInstructionARM64::EmulateADDSUBImm,
194061da546Spatrick "SUBS <Xd>, <Xn|SP>, #<imm> {, <shift>}"},
195061da546Spatrick {0xff000000, 0x91000000, No_VFP,
196061da546Spatrick &EmulateInstructionARM64::EmulateADDSUBImm,
197061da546Spatrick "ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"},
198061da546Spatrick {0xff000000, 0xb1000000, No_VFP,
199061da546Spatrick &EmulateInstructionARM64::EmulateADDSUBImm,
200061da546Spatrick "ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}"},
201061da546Spatrick
202061da546Spatrick {0xff000000, 0x51000000, No_VFP,
203061da546Spatrick &EmulateInstructionARM64::EmulateADDSUBImm,
204061da546Spatrick "SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"},
205061da546Spatrick {0xff000000, 0x71000000, No_VFP,
206061da546Spatrick &EmulateInstructionARM64::EmulateADDSUBImm,
207061da546Spatrick "SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"},
208061da546Spatrick {0xff000000, 0x11000000, No_VFP,
209061da546Spatrick &EmulateInstructionARM64::EmulateADDSUBImm,
210061da546Spatrick "ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"},
211061da546Spatrick {0xff000000, 0x31000000, No_VFP,
212061da546Spatrick &EmulateInstructionARM64::EmulateADDSUBImm,
213061da546Spatrick "ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"},
214061da546Spatrick
215061da546Spatrick {0xffc00000, 0x29000000, No_VFP,
216061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
217061da546Spatrick "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},
218061da546Spatrick {0xffc00000, 0xa9000000, No_VFP,
219061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
220061da546Spatrick "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},
221061da546Spatrick {0xffc00000, 0x2d000000, No_VFP,
222061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
223061da546Spatrick "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},
224061da546Spatrick {0xffc00000, 0x6d000000, No_VFP,
225061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
226061da546Spatrick "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},
227061da546Spatrick {0xffc00000, 0xad000000, No_VFP,
228061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
229061da546Spatrick "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},
230061da546Spatrick
231061da546Spatrick {0xffc00000, 0x29800000, No_VFP,
232061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
233061da546Spatrick "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
234061da546Spatrick {0xffc00000, 0xa9800000, No_VFP,
235061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
236061da546Spatrick "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
237061da546Spatrick {0xffc00000, 0x2d800000, No_VFP,
238061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
239061da546Spatrick "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
240061da546Spatrick {0xffc00000, 0x6d800000, No_VFP,
241061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
242061da546Spatrick "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
243061da546Spatrick {0xffc00000, 0xad800000, No_VFP,
244061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
245061da546Spatrick "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
246061da546Spatrick
247061da546Spatrick {0xffc00000, 0x28800000, No_VFP,
248061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
249061da546Spatrick "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
250061da546Spatrick {0xffc00000, 0xa8800000, No_VFP,
251061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
252061da546Spatrick "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
253061da546Spatrick {0xffc00000, 0x2c800000, No_VFP,
254061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
255061da546Spatrick "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
256061da546Spatrick {0xffc00000, 0x6c800000, No_VFP,
257061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
258061da546Spatrick "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
259061da546Spatrick {0xffc00000, 0xac800000, No_VFP,
260061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
261061da546Spatrick "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
262061da546Spatrick
263061da546Spatrick {0xffc00000, 0x29400000, No_VFP,
264061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
265061da546Spatrick "LDP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},
266061da546Spatrick {0xffc00000, 0xa9400000, No_VFP,
267061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
268061da546Spatrick "LDP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},
269061da546Spatrick {0xffc00000, 0x2d400000, No_VFP,
270061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
271061da546Spatrick "LDP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},
272061da546Spatrick {0xffc00000, 0x6d400000, No_VFP,
273061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
274061da546Spatrick "LDP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},
275061da546Spatrick {0xffc00000, 0xad400000, No_VFP,
276061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
277061da546Spatrick "LDP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},
278061da546Spatrick
279061da546Spatrick {0xffc00000, 0x29c00000, No_VFP,
280061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
281061da546Spatrick "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
282061da546Spatrick {0xffc00000, 0xa9c00000, No_VFP,
283061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
284061da546Spatrick "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
285061da546Spatrick {0xffc00000, 0x2dc00000, No_VFP,
286061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
287061da546Spatrick "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
288061da546Spatrick {0xffc00000, 0x6dc00000, No_VFP,
289061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
290061da546Spatrick "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
291061da546Spatrick {0xffc00000, 0xadc00000, No_VFP,
292061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
293061da546Spatrick "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
294061da546Spatrick
295061da546Spatrick {0xffc00000, 0x28c00000, No_VFP,
296061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
297061da546Spatrick "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
298061da546Spatrick {0xffc00000, 0xa8c00000, No_VFP,
299061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
300061da546Spatrick "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
301061da546Spatrick {0xffc00000, 0x2cc00000, No_VFP,
302061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
303061da546Spatrick "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
304061da546Spatrick {0xffc00000, 0x6cc00000, No_VFP,
305061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
306061da546Spatrick "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
307061da546Spatrick {0xffc00000, 0xacc00000, No_VFP,
308061da546Spatrick &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
309061da546Spatrick "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
310061da546Spatrick
311061da546Spatrick {0xffe00c00, 0xb8000400, No_VFP,
312061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
313061da546Spatrick "STR <Wt>, [<Xn|SP>], #<simm>"},
314061da546Spatrick {0xffe00c00, 0xf8000400, No_VFP,
315061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
316061da546Spatrick "STR <Xt>, [<Xn|SP>], #<simm>"},
317061da546Spatrick {0xffe00c00, 0xb8000c00, No_VFP,
318061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
319061da546Spatrick "STR <Wt>, [<Xn|SP>, #<simm>]!"},
320061da546Spatrick {0xffe00c00, 0xf8000c00, No_VFP,
321061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
322061da546Spatrick "STR <Xt>, [<Xn|SP>, #<simm>]!"},
323061da546Spatrick {0xffc00000, 0xb9000000, No_VFP,
324061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
325061da546Spatrick "STR <Wt>, [<Xn|SP>{, #<pimm>}]"},
326061da546Spatrick {0xffc00000, 0xf9000000, No_VFP,
327061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
328061da546Spatrick "STR <Xt>, [<Xn|SP>{, #<pimm>}]"},
329061da546Spatrick
330061da546Spatrick {0xffe00c00, 0xb8400400, No_VFP,
331061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
332061da546Spatrick "LDR <Wt>, [<Xn|SP>], #<simm>"},
333061da546Spatrick {0xffe00c00, 0xf8400400, No_VFP,
334061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
335061da546Spatrick "LDR <Xt>, [<Xn|SP>], #<simm>"},
336061da546Spatrick {0xffe00c00, 0xb8400c00, No_VFP,
337061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
338061da546Spatrick "LDR <Wt>, [<Xn|SP>, #<simm>]!"},
339061da546Spatrick {0xffe00c00, 0xf8400c00, No_VFP,
340061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
341061da546Spatrick "LDR <Xt>, [<Xn|SP>, #<simm>]!"},
342061da546Spatrick {0xffc00000, 0xb9400000, No_VFP,
343061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
344061da546Spatrick "LDR <Wt>, [<Xn|SP>{, #<pimm>}]"},
345061da546Spatrick {0xffc00000, 0xf9400000, No_VFP,
346061da546Spatrick &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
347061da546Spatrick "LDR <Xt>, [<Xn|SP>{, #<pimm>}]"},
348061da546Spatrick
349061da546Spatrick {0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB,
350061da546Spatrick "B <label>"},
351061da546Spatrick {0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond,
352061da546Spatrick "B.<cond> <label>"},
353061da546Spatrick {0x7f000000, 0x34000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,
354061da546Spatrick "CBZ <Wt>, <label>"},
355061da546Spatrick {0x7f000000, 0x35000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,
356061da546Spatrick "CBNZ <Wt>, <label>"},
357061da546Spatrick {0x7f000000, 0x36000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,
358061da546Spatrick "TBZ <R><t>, #<imm>, <label>"},
359061da546Spatrick {0x7f000000, 0x37000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,
360061da546Spatrick "TBNZ <R><t>, #<imm>, <label>"},
361061da546Spatrick
362061da546Spatrick };
363*f6aab3d8Srobert static const size_t k_num_arm_opcodes = std::size(g_opcodes);
364061da546Spatrick
365061da546Spatrick for (size_t i = 0; i < k_num_arm_opcodes; ++i) {
366061da546Spatrick if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
367061da546Spatrick return &g_opcodes[i];
368061da546Spatrick }
369061da546Spatrick return nullptr;
370061da546Spatrick }
371061da546Spatrick
ReadInstruction()372061da546Spatrick bool EmulateInstructionARM64::ReadInstruction() {
373061da546Spatrick bool success = false;
374061da546Spatrick m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
375061da546Spatrick LLDB_INVALID_ADDRESS, &success);
376061da546Spatrick if (success) {
377061da546Spatrick Context read_inst_context;
378061da546Spatrick read_inst_context.type = eContextReadOpcode;
379061da546Spatrick read_inst_context.SetNoArgs();
380061da546Spatrick m_opcode.SetOpcode32(
381061da546Spatrick ReadMemoryUnsigned(read_inst_context, m_addr, 4, 0, &success),
382061da546Spatrick GetByteOrder());
383061da546Spatrick }
384061da546Spatrick if (!success)
385061da546Spatrick m_addr = LLDB_INVALID_ADDRESS;
386061da546Spatrick return success;
387061da546Spatrick }
388061da546Spatrick
EvaluateInstruction(uint32_t evaluate_options)389061da546Spatrick bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) {
390061da546Spatrick const uint32_t opcode = m_opcode.GetOpcode32();
391061da546Spatrick Opcode *opcode_data = GetOpcodeForInstruction(opcode);
392061da546Spatrick if (opcode_data == nullptr)
393061da546Spatrick return false;
394061da546Spatrick
395061da546Spatrick const bool auto_advance_pc =
396061da546Spatrick evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
397061da546Spatrick m_ignore_conditions =
398061da546Spatrick evaluate_options & eEmulateInstructionOptionIgnoreConditions;
399061da546Spatrick
400061da546Spatrick bool success = false;
401061da546Spatrick
402061da546Spatrick // Only return false if we are unable to read the CPSR if we care about
403061da546Spatrick // conditions
404061da546Spatrick if (!success && !m_ignore_conditions)
405061da546Spatrick return false;
406061da546Spatrick
407061da546Spatrick uint32_t orig_pc_value = 0;
408061da546Spatrick if (auto_advance_pc) {
409061da546Spatrick orig_pc_value =
410061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success);
411061da546Spatrick if (!success)
412061da546Spatrick return false;
413061da546Spatrick }
414061da546Spatrick
415061da546Spatrick // Call the Emulate... function.
416061da546Spatrick success = (this->*opcode_data->callback)(opcode);
417061da546Spatrick if (!success)
418061da546Spatrick return false;
419061da546Spatrick
420061da546Spatrick if (auto_advance_pc) {
421061da546Spatrick uint32_t new_pc_value =
422061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success);
423061da546Spatrick if (!success)
424061da546Spatrick return false;
425061da546Spatrick
426dda28197Spatrick if (new_pc_value == orig_pc_value) {
427061da546Spatrick EmulateInstruction::Context context;
428061da546Spatrick context.type = eContextAdvancePC;
429061da546Spatrick context.SetNoArgs();
430061da546Spatrick if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_arm64,
431061da546Spatrick orig_pc_value + 4))
432061da546Spatrick return false;
433061da546Spatrick }
434061da546Spatrick }
435061da546Spatrick return true;
436061da546Spatrick }
437061da546Spatrick
CreateFunctionEntryUnwind(UnwindPlan & unwind_plan)438061da546Spatrick bool EmulateInstructionARM64::CreateFunctionEntryUnwind(
439061da546Spatrick UnwindPlan &unwind_plan) {
440061da546Spatrick unwind_plan.Clear();
441061da546Spatrick unwind_plan.SetRegisterKind(eRegisterKindLLDB);
442061da546Spatrick
443061da546Spatrick UnwindPlan::RowSP row(new UnwindPlan::Row);
444061da546Spatrick
445061da546Spatrick // Our previous Call Frame Address is the stack pointer
446061da546Spatrick row->GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_arm64, 0);
447061da546Spatrick
448061da546Spatrick unwind_plan.AppendRow(row);
449061da546Spatrick unwind_plan.SetSourceName("EmulateInstructionARM64");
450061da546Spatrick unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
451061da546Spatrick unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
452061da546Spatrick unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
453061da546Spatrick unwind_plan.SetReturnAddressRegister(gpr_lr_arm64);
454061da546Spatrick return true;
455061da546Spatrick }
456061da546Spatrick
GetFramePointerRegisterNumber() const457061da546Spatrick uint32_t EmulateInstructionARM64::GetFramePointerRegisterNumber() const {
458061da546Spatrick if (m_arch.GetTriple().isAndroid())
459061da546Spatrick return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
460061da546Spatrick
461061da546Spatrick return gpr_fp_arm64;
462061da546Spatrick }
463061da546Spatrick
UsingAArch32()464061da546Spatrick bool EmulateInstructionARM64::UsingAArch32() {
465061da546Spatrick bool aarch32 = m_opcode_pstate.RW == 1;
466061da546Spatrick // if !HaveAnyAArch32() then assert !aarch32;
467061da546Spatrick // if HighestELUsingAArch32() then assert aarch32;
468061da546Spatrick return aarch32;
469061da546Spatrick }
470061da546Spatrick
BranchTo(const Context & context,uint32_t N,addr_t target)471061da546Spatrick bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N,
472061da546Spatrick addr_t target) {
473061da546Spatrick #if 0
474061da546Spatrick // Set program counter to a new address, with a branch reason hint for
475061da546Spatrick // possible use by hardware fetching the next instruction.
476061da546Spatrick BranchTo(bits(N) target, BranchType branch_type)
477061da546Spatrick Hint_Branch(branch_type);
478061da546Spatrick if N == 32 then
479061da546Spatrick assert UsingAArch32();
480061da546Spatrick _PC = ZeroExtend(target);
481061da546Spatrick else
482061da546Spatrick assert N == 64 && !UsingAArch32();
483061da546Spatrick // Remove the tag bits from a tagged target
484061da546Spatrick case PSTATE.EL of
485061da546Spatrick when EL0, EL1
486061da546Spatrick if target<55> == '1' && TCR_EL1.TBI1 == '1' then
487061da546Spatrick target<63:56> = '11111111';
488061da546Spatrick if target<55> == '0' && TCR_EL1.TBI0 == '1' then
489061da546Spatrick target<63:56> = '00000000';
490061da546Spatrick when EL2
491061da546Spatrick if TCR_EL2.TBI == '1' then
492061da546Spatrick target<63:56> = '00000000';
493061da546Spatrick when EL3
494061da546Spatrick if TCR_EL3.TBI == '1' then
495061da546Spatrick target<63:56> = '00000000';
496061da546Spatrick _PC = target<63:0>;
497061da546Spatrick return;
498061da546Spatrick #endif
499061da546Spatrick
500061da546Spatrick addr_t addr;
501061da546Spatrick
502061da546Spatrick // Hint_Branch(branch_type);
503061da546Spatrick if (N == 32) {
504061da546Spatrick if (!UsingAArch32())
505061da546Spatrick return false;
506061da546Spatrick addr = target;
507061da546Spatrick } else if (N == 64) {
508061da546Spatrick if (UsingAArch32())
509061da546Spatrick return false;
510061da546Spatrick // TODO: Remove the tag bits from a tagged target
511061da546Spatrick addr = target;
512061da546Spatrick } else
513061da546Spatrick return false;
514061da546Spatrick
515061da546Spatrick return WriteRegisterUnsigned(context, eRegisterKindGeneric,
516061da546Spatrick LLDB_REGNUM_GENERIC_PC, addr);
517061da546Spatrick }
518061da546Spatrick
ConditionHolds(const uint32_t cond)519061da546Spatrick bool EmulateInstructionARM64::ConditionHolds(const uint32_t cond) {
520061da546Spatrick // If we are ignoring conditions, then always return true. this allows us to
521061da546Spatrick // iterate over disassembly code and still emulate an instruction even if we
522061da546Spatrick // don't have all the right bits set in the CPSR register...
523061da546Spatrick if (m_ignore_conditions)
524061da546Spatrick return true;
525061da546Spatrick
526061da546Spatrick bool result = false;
527061da546Spatrick switch (UnsignedBits(cond, 3, 1)) {
528061da546Spatrick case 0:
529061da546Spatrick result = (m_opcode_pstate.Z == 1);
530061da546Spatrick break;
531061da546Spatrick case 1:
532061da546Spatrick result = (m_opcode_pstate.C == 1);
533061da546Spatrick break;
534061da546Spatrick case 2:
535061da546Spatrick result = (m_opcode_pstate.N == 1);
536061da546Spatrick break;
537061da546Spatrick case 3:
538061da546Spatrick result = (m_opcode_pstate.V == 1);
539061da546Spatrick break;
540061da546Spatrick case 4:
541061da546Spatrick result = (m_opcode_pstate.C == 1 && m_opcode_pstate.Z == 0);
542061da546Spatrick break;
543061da546Spatrick case 5:
544061da546Spatrick result = (m_opcode_pstate.N == m_opcode_pstate.V);
545061da546Spatrick break;
546061da546Spatrick case 6:
547061da546Spatrick result = (m_opcode_pstate.N == m_opcode_pstate.V && m_opcode_pstate.Z == 0);
548061da546Spatrick break;
549061da546Spatrick case 7:
550061da546Spatrick // Always execute (cond == 0b1110, or the special 0b1111 which gives
551061da546Spatrick // opcodes different meanings, but always means execution happens.
552061da546Spatrick return true;
553061da546Spatrick }
554061da546Spatrick
555061da546Spatrick if (cond & 1)
556061da546Spatrick result = !result;
557061da546Spatrick return result;
558061da546Spatrick }
559061da546Spatrick
560dda28197Spatrick uint64_t EmulateInstructionARM64::
AddWithCarry(uint32_t N,uint64_t x,uint64_t y,bit carry_in,EmulateInstructionARM64::ProcState & proc_state)561dda28197Spatrick AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in,
562dda28197Spatrick EmulateInstructionARM64::ProcState &proc_state) {
563dda28197Spatrick uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
564*f6aab3d8Srobert std::optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y));
565dda28197Spatrick bool overflow = !signed_sum;
566dda28197Spatrick if (!overflow)
567dda28197Spatrick overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in));
568dda28197Spatrick uint64_t result = unsigned_sum;
569dda28197Spatrick if (N < 64)
570dda28197Spatrick result = Bits64(result, N - 1, 0);
571dda28197Spatrick proc_state.N = Bit64(result, N - 1);
572dda28197Spatrick proc_state.Z = IsZero(result);
573dda28197Spatrick proc_state.C = UInt(result) != unsigned_sum;
574dda28197Spatrick proc_state.V = overflow;
575dda28197Spatrick return result;
576dda28197Spatrick }
577dda28197Spatrick
EmulateADDSUBImm(const uint32_t opcode)578061da546Spatrick bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) {
579061da546Spatrick // integer d = UInt(Rd);
580061da546Spatrick // integer n = UInt(Rn);
581061da546Spatrick // integer datasize = if sf == 1 then 64 else 32;
582061da546Spatrick // boolean sub_op = (op == 1);
583061da546Spatrick // boolean setflags = (S == 1);
584061da546Spatrick // bits(datasize) imm;
585061da546Spatrick //
586061da546Spatrick // case shift of
587061da546Spatrick // when '00' imm = ZeroExtend(imm12, datasize);
588061da546Spatrick // when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize);
589061da546Spatrick // when '1x' UNDEFINED;
590061da546Spatrick //
591061da546Spatrick //
592061da546Spatrick // bits(datasize) result;
593061da546Spatrick // bits(datasize) operand1 = if n == 31 then SP[] else X[n];
594061da546Spatrick // bits(datasize) operand2 = imm;
595061da546Spatrick // bits(4) nzcv;
596061da546Spatrick // bit carry_in;
597061da546Spatrick //
598061da546Spatrick // if sub_op then
599061da546Spatrick // operand2 = NOT(operand2);
600061da546Spatrick // carry_in = 1;
601061da546Spatrick // else
602061da546Spatrick // carry_in = 0;
603061da546Spatrick //
604061da546Spatrick // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in);
605061da546Spatrick //
606061da546Spatrick // if setflags then
607061da546Spatrick // PSTATE.NZCV = nzcv;
608061da546Spatrick //
609061da546Spatrick // if d == 31 && !setflags then
610061da546Spatrick // SP[] = result;
611061da546Spatrick // else
612061da546Spatrick // X[d] = result;
613061da546Spatrick
614061da546Spatrick const uint32_t sf = Bit32(opcode, 31);
615061da546Spatrick const uint32_t op = Bit32(opcode, 30);
616061da546Spatrick const uint32_t S = Bit32(opcode, 29);
617061da546Spatrick const uint32_t shift = Bits32(opcode, 23, 22);
618061da546Spatrick const uint32_t imm12 = Bits32(opcode, 21, 10);
619061da546Spatrick const uint32_t Rn = Bits32(opcode, 9, 5);
620061da546Spatrick const uint32_t Rd = Bits32(opcode, 4, 0);
621061da546Spatrick
622061da546Spatrick bool success = false;
623061da546Spatrick
624061da546Spatrick const uint32_t d = UInt(Rd);
625061da546Spatrick const uint32_t n = UInt(Rn);
626061da546Spatrick const uint32_t datasize = (sf == 1) ? 64 : 32;
627061da546Spatrick boolean sub_op = op == 1;
628061da546Spatrick boolean setflags = S == 1;
629061da546Spatrick uint64_t imm;
630061da546Spatrick
631061da546Spatrick switch (shift) {
632061da546Spatrick case 0:
633061da546Spatrick imm = imm12;
634061da546Spatrick break;
635061da546Spatrick case 1:
636*f6aab3d8Srobert imm = static_cast<uint64_t>(imm12) << 12;
637061da546Spatrick break;
638061da546Spatrick default:
639061da546Spatrick return false; // UNDEFINED;
640061da546Spatrick }
641061da546Spatrick uint64_t result;
642061da546Spatrick uint64_t operand1 =
643061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);
644061da546Spatrick uint64_t operand2 = imm;
645061da546Spatrick bit carry_in;
646061da546Spatrick
647061da546Spatrick if (sub_op) {
648061da546Spatrick operand2 = NOT(operand2);
649061da546Spatrick carry_in = true;
650061da546Spatrick imm = -imm; // For the Register plug offset context below
651061da546Spatrick } else {
652061da546Spatrick carry_in = false;
653061da546Spatrick }
654061da546Spatrick
655061da546Spatrick ProcState proc_state;
656061da546Spatrick
657061da546Spatrick result = AddWithCarry(datasize, operand1, operand2, carry_in, proc_state);
658061da546Spatrick
659061da546Spatrick if (setflags) {
660061da546Spatrick m_emulated_pstate.N = proc_state.N;
661061da546Spatrick m_emulated_pstate.Z = proc_state.Z;
662061da546Spatrick m_emulated_pstate.C = proc_state.C;
663061da546Spatrick m_emulated_pstate.V = proc_state.V;
664061da546Spatrick }
665061da546Spatrick
666061da546Spatrick Context context;
667*f6aab3d8Srobert std::optional<RegisterInfo> reg_info_Rn =
668*f6aab3d8Srobert GetRegisterInfo(eRegisterKindLLDB, n);
669*f6aab3d8Srobert if (reg_info_Rn)
670*f6aab3d8Srobert context.SetRegisterPlusOffset(*reg_info_Rn, imm);
671061da546Spatrick
672061da546Spatrick if (n == GetFramePointerRegisterNumber() && d == gpr_sp_arm64 && !setflags) {
673061da546Spatrick // 'mov sp, fp' - common epilogue instruction, CFA is now in terms of the
674061da546Spatrick // stack pointer, instead of frame pointer.
675061da546Spatrick context.type = EmulateInstruction::eContextRestoreStackPointer;
676061da546Spatrick } else if ((n == gpr_sp_arm64 || n == GetFramePointerRegisterNumber()) &&
677061da546Spatrick d == gpr_sp_arm64 && !setflags) {
678061da546Spatrick context.type = EmulateInstruction::eContextAdjustStackPointer;
679061da546Spatrick } else if (d == GetFramePointerRegisterNumber() && n == gpr_sp_arm64 &&
680061da546Spatrick !setflags) {
681061da546Spatrick context.type = EmulateInstruction::eContextSetFramePointer;
682061da546Spatrick } else {
683061da546Spatrick context.type = EmulateInstruction::eContextImmediate;
684061da546Spatrick }
685061da546Spatrick
686061da546Spatrick // If setflags && d == gpr_sp_arm64 then d = WZR/XZR. See CMN, CMP
687061da546Spatrick if (!setflags || d != gpr_sp_arm64)
688061da546Spatrick WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_x0_arm64 + d, result);
689061da546Spatrick
690061da546Spatrick return false;
691061da546Spatrick }
692061da546Spatrick
693061da546Spatrick template <EmulateInstructionARM64::AddrMode a_mode>
EmulateLDPSTP(const uint32_t opcode)694061da546Spatrick bool EmulateInstructionARM64::EmulateLDPSTP(const uint32_t opcode) {
695061da546Spatrick uint32_t opc = Bits32(opcode, 31, 30);
696061da546Spatrick uint32_t V = Bit32(opcode, 26);
697061da546Spatrick uint32_t L = Bit32(opcode, 22);
698061da546Spatrick uint32_t imm7 = Bits32(opcode, 21, 15);
699061da546Spatrick uint32_t Rt2 = Bits32(opcode, 14, 10);
700061da546Spatrick uint32_t Rn = Bits32(opcode, 9, 5);
701061da546Spatrick uint32_t Rt = Bits32(opcode, 4, 0);
702061da546Spatrick
703061da546Spatrick integer n = UInt(Rn);
704061da546Spatrick integer t = UInt(Rt);
705061da546Spatrick integer t2 = UInt(Rt2);
706061da546Spatrick uint64_t idx;
707061da546Spatrick
708061da546Spatrick MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE;
709061da546Spatrick boolean vector = (V == 1);
710061da546Spatrick // AccType acctype = AccType_NORMAL;
711061da546Spatrick boolean is_signed = false;
712061da546Spatrick boolean wback = a_mode != AddrMode_OFF;
713061da546Spatrick boolean wb_unknown = false;
714061da546Spatrick boolean rt_unknown = false;
715061da546Spatrick integer scale;
716061da546Spatrick integer size;
717061da546Spatrick
718061da546Spatrick if (opc == 3)
719061da546Spatrick return false; // UNDEFINED
720061da546Spatrick
721061da546Spatrick if (vector) {
722061da546Spatrick scale = 2 + UInt(opc);
723061da546Spatrick } else {
724061da546Spatrick scale = (opc & 2) ? 3 : 2;
725061da546Spatrick is_signed = (opc & 1) != 0;
726061da546Spatrick if (is_signed && memop == MemOp_STORE)
727061da546Spatrick return false; // UNDEFINED
728061da546Spatrick }
729061da546Spatrick
730061da546Spatrick if (!vector && wback && ((t == n) || (t2 == n))) {
731061da546Spatrick switch (ConstrainUnpredictable(Unpredictable_WBOVERLAP)) {
732061da546Spatrick case Constraint_UNKNOWN:
733061da546Spatrick wb_unknown = true; // writeback is UNKNOWN
734061da546Spatrick break;
735061da546Spatrick
736061da546Spatrick case Constraint_SUPPRESSWB:
737061da546Spatrick wback = false; // writeback is suppressed
738061da546Spatrick break;
739061da546Spatrick
740061da546Spatrick case Constraint_NOP:
741061da546Spatrick memop = MemOp_NOP; // do nothing
742061da546Spatrick wback = false;
743061da546Spatrick break;
744061da546Spatrick
745061da546Spatrick case Constraint_NONE:
746061da546Spatrick break;
747061da546Spatrick }
748061da546Spatrick }
749061da546Spatrick
750061da546Spatrick if (memop == MemOp_LOAD && t == t2) {
751061da546Spatrick switch (ConstrainUnpredictable(Unpredictable_LDPOVERLAP)) {
752061da546Spatrick case Constraint_UNKNOWN:
753061da546Spatrick rt_unknown = true; // result is UNKNOWN
754061da546Spatrick break;
755061da546Spatrick
756061da546Spatrick case Constraint_NOP:
757061da546Spatrick memop = MemOp_NOP; // do nothing
758061da546Spatrick wback = false;
759061da546Spatrick break;
760061da546Spatrick
761061da546Spatrick default:
762061da546Spatrick break;
763061da546Spatrick }
764061da546Spatrick }
765061da546Spatrick
766061da546Spatrick idx = LSL(llvm::SignExtend64<7>(imm7), scale);
767061da546Spatrick size = (integer)1 << scale;
768061da546Spatrick uint64_t datasize = size * 8;
769061da546Spatrick uint64_t address;
770061da546Spatrick uint64_t wb_address;
771061da546Spatrick
772*f6aab3d8Srobert std::optional<RegisterInfo> reg_info_base =
773*f6aab3d8Srobert GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + n);
774*f6aab3d8Srobert if (!reg_info_base)
775061da546Spatrick return false;
776061da546Spatrick
777*f6aab3d8Srobert std::optional<RegisterInfo> reg_info_Rt;
778*f6aab3d8Srobert std::optional<RegisterInfo> reg_info_Rt2;
779*f6aab3d8Srobert
780061da546Spatrick if (vector) {
781*f6aab3d8Srobert reg_info_Rt = GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t);
782*f6aab3d8Srobert reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t2);
783061da546Spatrick } else {
784*f6aab3d8Srobert reg_info_Rt = GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);
785*f6aab3d8Srobert reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t2);
786061da546Spatrick }
787061da546Spatrick
788*f6aab3d8Srobert if (!reg_info_Rt || !reg_info_Rt2)
789*f6aab3d8Srobert return false;
790*f6aab3d8Srobert
791061da546Spatrick bool success = false;
792061da546Spatrick if (n == 31) {
793061da546Spatrick // CheckSPAlignment();
794061da546Spatrick address =
795061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_sp_arm64, 0, &success);
796061da546Spatrick } else
797061da546Spatrick address =
798061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);
799061da546Spatrick
800061da546Spatrick wb_address = address + idx;
801061da546Spatrick if (a_mode != AddrMode_POST)
802061da546Spatrick address = wb_address;
803061da546Spatrick
804061da546Spatrick Context context_t;
805061da546Spatrick Context context_t2;
806061da546Spatrick
807061da546Spatrick uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
808061da546Spatrick Status error;
809061da546Spatrick
810061da546Spatrick switch (memop) {
811061da546Spatrick case MemOp_STORE: {
812061da546Spatrick if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
813061da546Spatrick // based off of the sp
814061da546Spatrick // or fp register
815061da546Spatrick {
816061da546Spatrick context_t.type = eContextPushRegisterOnStack;
817061da546Spatrick context_t2.type = eContextPushRegisterOnStack;
818061da546Spatrick } else {
819061da546Spatrick context_t.type = eContextRegisterStore;
820061da546Spatrick context_t2.type = eContextRegisterStore;
821061da546Spatrick }
822*f6aab3d8Srobert context_t.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base, 0);
823*f6aab3d8Srobert context_t2.SetRegisterToRegisterPlusOffset(*reg_info_Rt2, *reg_info_base,
824061da546Spatrick size);
825061da546Spatrick
826*f6aab3d8Srobert std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt);
827*f6aab3d8Srobert if (!data_Rt)
828061da546Spatrick return false;
829061da546Spatrick
830*f6aab3d8Srobert if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer, reg_info_Rt->byte_size,
831061da546Spatrick eByteOrderLittle, error) == 0)
832061da546Spatrick return false;
833061da546Spatrick
834*f6aab3d8Srobert if (!WriteMemory(context_t, address + 0, buffer, reg_info_Rt->byte_size))
835061da546Spatrick return false;
836061da546Spatrick
837*f6aab3d8Srobert std::optional<RegisterValue> data_Rt2 = ReadRegister(*reg_info_Rt2);
838*f6aab3d8Srobert if (!data_Rt2)
839061da546Spatrick return false;
840061da546Spatrick
841*f6aab3d8Srobert if (data_Rt2->GetAsMemoryData(*reg_info_Rt2, buffer,
842*f6aab3d8Srobert reg_info_Rt2->byte_size, eByteOrderLittle,
843*f6aab3d8Srobert error) == 0)
844061da546Spatrick return false;
845061da546Spatrick
846061da546Spatrick if (!WriteMemory(context_t2, address + size, buffer,
847*f6aab3d8Srobert reg_info_Rt2->byte_size))
848061da546Spatrick return false;
849061da546Spatrick } break;
850061da546Spatrick
851061da546Spatrick case MemOp_LOAD: {
852061da546Spatrick if (n == 31 || n == GetFramePointerRegisterNumber()) // if this load is
853061da546Spatrick // based off of the sp
854061da546Spatrick // or fp register
855061da546Spatrick {
856061da546Spatrick context_t.type = eContextPopRegisterOffStack;
857061da546Spatrick context_t2.type = eContextPopRegisterOffStack;
858061da546Spatrick } else {
859061da546Spatrick context_t.type = eContextRegisterLoad;
860061da546Spatrick context_t2.type = eContextRegisterLoad;
861061da546Spatrick }
862061da546Spatrick context_t.SetAddress(address);
863061da546Spatrick context_t2.SetAddress(address + size);
864061da546Spatrick
865061da546Spatrick if (rt_unknown)
866*f6aab3d8Srobert memset(buffer, 'U', reg_info_Rt->byte_size);
867061da546Spatrick else {
868*f6aab3d8Srobert if (!ReadMemory(context_t, address, buffer, reg_info_Rt->byte_size))
869061da546Spatrick return false;
870061da546Spatrick }
871061da546Spatrick
872*f6aab3d8Srobert RegisterValue data_Rt;
873*f6aab3d8Srobert if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer, reg_info_Rt->byte_size,
874061da546Spatrick eByteOrderLittle, error) == 0)
875061da546Spatrick return false;
876061da546Spatrick
877061da546Spatrick if (!vector && is_signed && !data_Rt.SignExtend(datasize))
878061da546Spatrick return false;
879061da546Spatrick
880*f6aab3d8Srobert if (!WriteRegister(context_t, *reg_info_Rt, data_Rt))
881061da546Spatrick return false;
882061da546Spatrick
883061da546Spatrick if (!rt_unknown) {
884061da546Spatrick if (!ReadMemory(context_t2, address + size, buffer,
885*f6aab3d8Srobert reg_info_Rt2->byte_size))
886061da546Spatrick return false;
887061da546Spatrick }
888061da546Spatrick
889*f6aab3d8Srobert RegisterValue data_Rt2;
890*f6aab3d8Srobert if (data_Rt2.SetFromMemoryData(*reg_info_Rt2, buffer,
891*f6aab3d8Srobert reg_info_Rt2->byte_size, eByteOrderLittle,
892061da546Spatrick error) == 0)
893061da546Spatrick return false;
894061da546Spatrick
895061da546Spatrick if (!vector && is_signed && !data_Rt2.SignExtend(datasize))
896061da546Spatrick return false;
897061da546Spatrick
898*f6aab3d8Srobert if (!WriteRegister(context_t2, *reg_info_Rt2, data_Rt2))
899061da546Spatrick return false;
900061da546Spatrick } break;
901061da546Spatrick
902061da546Spatrick default:
903061da546Spatrick break;
904061da546Spatrick }
905061da546Spatrick
906061da546Spatrick if (wback) {
907061da546Spatrick if (wb_unknown)
908061da546Spatrick wb_address = LLDB_INVALID_ADDRESS;
909061da546Spatrick Context context;
910061da546Spatrick context.SetImmediateSigned(idx);
911061da546Spatrick if (n == 31)
912061da546Spatrick context.type = eContextAdjustStackPointer;
913061da546Spatrick else
914061da546Spatrick context.type = eContextAdjustBaseRegister;
915*f6aab3d8Srobert WriteRegisterUnsigned(context, *reg_info_base, wb_address);
916061da546Spatrick }
917061da546Spatrick return true;
918061da546Spatrick }
919061da546Spatrick
920061da546Spatrick template <EmulateInstructionARM64::AddrMode a_mode>
EmulateLDRSTRImm(const uint32_t opcode)921061da546Spatrick bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
922061da546Spatrick uint32_t size = Bits32(opcode, 31, 30);
923061da546Spatrick uint32_t opc = Bits32(opcode, 23, 22);
924061da546Spatrick uint32_t n = Bits32(opcode, 9, 5);
925061da546Spatrick uint32_t t = Bits32(opcode, 4, 0);
926061da546Spatrick
927061da546Spatrick bool wback;
928061da546Spatrick bool postindex;
929061da546Spatrick uint64_t offset;
930061da546Spatrick
931061da546Spatrick switch (a_mode) {
932061da546Spatrick case AddrMode_POST:
933061da546Spatrick wback = true;
934061da546Spatrick postindex = true;
935061da546Spatrick offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));
936061da546Spatrick break;
937061da546Spatrick case AddrMode_PRE:
938061da546Spatrick wback = true;
939061da546Spatrick postindex = false;
940061da546Spatrick offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));
941061da546Spatrick break;
942061da546Spatrick case AddrMode_OFF:
943061da546Spatrick wback = false;
944061da546Spatrick postindex = false;
945061da546Spatrick offset = LSL(Bits32(opcode, 21, 10), size);
946061da546Spatrick break;
947061da546Spatrick }
948061da546Spatrick
949061da546Spatrick MemOp memop;
950061da546Spatrick
951061da546Spatrick if (Bit32(opc, 1) == 0) {
952061da546Spatrick memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
953061da546Spatrick } else {
954061da546Spatrick memop = MemOp_LOAD;
955061da546Spatrick if (size == 2 && Bit32(opc, 0) == 1)
956061da546Spatrick return false;
957061da546Spatrick }
958061da546Spatrick
959061da546Spatrick Status error;
960061da546Spatrick bool success = false;
961061da546Spatrick uint64_t address;
962061da546Spatrick uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
963061da546Spatrick
964061da546Spatrick if (n == 31)
965061da546Spatrick address =
966061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_sp_arm64, 0, &success);
967061da546Spatrick else
968061da546Spatrick address =
969061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);
970061da546Spatrick
971061da546Spatrick if (!success)
972061da546Spatrick return false;
973061da546Spatrick
974061da546Spatrick if (!postindex)
975061da546Spatrick address += offset;
976061da546Spatrick
977*f6aab3d8Srobert std::optional<RegisterInfo> reg_info_base =
978*f6aab3d8Srobert GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + n);
979*f6aab3d8Srobert if (!reg_info_base)
980061da546Spatrick return false;
981061da546Spatrick
982*f6aab3d8Srobert std::optional<RegisterInfo> reg_info_Rt =
983*f6aab3d8Srobert GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);
984*f6aab3d8Srobert if (!reg_info_Rt)
985061da546Spatrick return false;
986061da546Spatrick
987061da546Spatrick Context context;
988061da546Spatrick switch (memop) {
989*f6aab3d8Srobert case MemOp_STORE: {
990061da546Spatrick if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
991061da546Spatrick // based off of the sp
992061da546Spatrick // or fp register
993061da546Spatrick context.type = eContextPushRegisterOnStack;
994061da546Spatrick else
995061da546Spatrick context.type = eContextRegisterStore;
996*f6aab3d8Srobert context.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base,
997061da546Spatrick postindex ? 0 : offset);
998061da546Spatrick
999*f6aab3d8Srobert std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt);
1000*f6aab3d8Srobert if (!data_Rt)
1001061da546Spatrick return false;
1002061da546Spatrick
1003*f6aab3d8Srobert if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer, reg_info_Rt->byte_size,
1004061da546Spatrick eByteOrderLittle, error) == 0)
1005061da546Spatrick return false;
1006061da546Spatrick
1007*f6aab3d8Srobert if (!WriteMemory(context, address, buffer, reg_info_Rt->byte_size))
1008061da546Spatrick return false;
1009*f6aab3d8Srobert } break;
1010061da546Spatrick
1011*f6aab3d8Srobert case MemOp_LOAD: {
1012061da546Spatrick if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
1013061da546Spatrick // based off of the sp
1014061da546Spatrick // or fp register
1015061da546Spatrick context.type = eContextPopRegisterOffStack;
1016061da546Spatrick else
1017061da546Spatrick context.type = eContextRegisterLoad;
1018061da546Spatrick context.SetAddress(address);
1019061da546Spatrick
1020*f6aab3d8Srobert if (!ReadMemory(context, address, buffer, reg_info_Rt->byte_size))
1021061da546Spatrick return false;
1022061da546Spatrick
1023*f6aab3d8Srobert RegisterValue data_Rt;
1024*f6aab3d8Srobert if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer, reg_info_Rt->byte_size,
1025061da546Spatrick eByteOrderLittle, error) == 0)
1026061da546Spatrick return false;
1027061da546Spatrick
1028*f6aab3d8Srobert if (!WriteRegister(context, *reg_info_Rt, data_Rt))
1029061da546Spatrick return false;
1030*f6aab3d8Srobert } break;
1031061da546Spatrick default:
1032061da546Spatrick return false;
1033061da546Spatrick }
1034061da546Spatrick
1035061da546Spatrick if (wback) {
1036061da546Spatrick if (postindex)
1037061da546Spatrick address += offset;
1038061da546Spatrick
1039061da546Spatrick if (n == 31)
1040061da546Spatrick context.type = eContextAdjustStackPointer;
1041061da546Spatrick else
1042061da546Spatrick context.type = eContextAdjustBaseRegister;
1043061da546Spatrick context.SetImmediateSigned(offset);
1044061da546Spatrick
1045*f6aab3d8Srobert if (!WriteRegisterUnsigned(context, *reg_info_base, address))
1046061da546Spatrick return false;
1047061da546Spatrick }
1048061da546Spatrick return true;
1049061da546Spatrick }
1050061da546Spatrick
EmulateB(const uint32_t opcode)1051061da546Spatrick bool EmulateInstructionARM64::EmulateB(const uint32_t opcode) {
1052061da546Spatrick #if 0
1053061da546Spatrick // ARM64 pseudo code...
1054061da546Spatrick if branch_type == BranchType_CALL then X[30] = PC[] + 4;
1055061da546Spatrick BranchTo(PC[] + offset, branch_type);
1056061da546Spatrick #endif
1057061da546Spatrick
1058061da546Spatrick bool success = false;
1059061da546Spatrick
1060061da546Spatrick EmulateInstruction::Context context;
1061061da546Spatrick context.type = EmulateInstruction::eContextRelativeBranchImmediate;
1062061da546Spatrick const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric,
1063061da546Spatrick LLDB_REGNUM_GENERIC_PC, 0, &success);
1064061da546Spatrick if (!success)
1065061da546Spatrick return false;
1066061da546Spatrick
1067061da546Spatrick int64_t offset = llvm::SignExtend64<28>(Bits32(opcode, 25, 0) << 2);
1068061da546Spatrick BranchType branch_type = Bit32(opcode, 31) ? BranchType_CALL : BranchType_JMP;
1069061da546Spatrick addr_t target = pc + offset;
1070061da546Spatrick context.SetImmediateSigned(offset);
1071061da546Spatrick
1072061da546Spatrick switch (branch_type) {
1073061da546Spatrick case BranchType_CALL: {
1074061da546Spatrick addr_t x30 = pc + 4;
1075061da546Spatrick if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_lr_arm64, x30))
1076061da546Spatrick return false;
1077061da546Spatrick } break;
1078061da546Spatrick case BranchType_JMP:
1079061da546Spatrick break;
1080061da546Spatrick default:
1081061da546Spatrick return false;
1082061da546Spatrick }
1083061da546Spatrick
1084061da546Spatrick return BranchTo(context, 64, target);
1085061da546Spatrick }
1086061da546Spatrick
EmulateBcond(const uint32_t opcode)1087061da546Spatrick bool EmulateInstructionARM64::EmulateBcond(const uint32_t opcode) {
1088061da546Spatrick #if 0
1089061da546Spatrick // ARM64 pseudo code...
1090061da546Spatrick bits(64) offset = SignExtend(imm19:'00', 64);
1091061da546Spatrick bits(4) condition = cond;
1092061da546Spatrick if ConditionHolds(condition) then
1093061da546Spatrick BranchTo(PC[] + offset, BranchType_JMP);
1094061da546Spatrick #endif
1095061da546Spatrick
1096061da546Spatrick if (ConditionHolds(Bits32(opcode, 3, 0))) {
1097061da546Spatrick bool success = false;
1098061da546Spatrick
1099061da546Spatrick const uint64_t pc = ReadRegisterUnsigned(
1100061da546Spatrick eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1101061da546Spatrick if (!success)
1102061da546Spatrick return false;
1103061da546Spatrick
1104061da546Spatrick int64_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
1105061da546Spatrick addr_t target = pc + offset;
1106061da546Spatrick
1107061da546Spatrick EmulateInstruction::Context context;
1108061da546Spatrick context.type = EmulateInstruction::eContextRelativeBranchImmediate;
1109061da546Spatrick context.SetImmediateSigned(offset);
1110061da546Spatrick if (!BranchTo(context, 64, target))
1111061da546Spatrick return false;
1112061da546Spatrick }
1113061da546Spatrick return true;
1114061da546Spatrick }
1115061da546Spatrick
EmulateCBZ(const uint32_t opcode)1116061da546Spatrick bool EmulateInstructionARM64::EmulateCBZ(const uint32_t opcode) {
1117061da546Spatrick #if 0
1118061da546Spatrick integer t = UInt(Rt);
1119061da546Spatrick integer datasize = if sf == '1' then 64 else 32;
1120061da546Spatrick boolean iszero = (op == '0');
1121061da546Spatrick bits(64) offset = SignExtend(imm19:'00', 64);
1122061da546Spatrick
1123061da546Spatrick bits(datasize) operand1 = X[t];
1124061da546Spatrick if IsZero(operand1) == iszero then
1125061da546Spatrick BranchTo(PC[] + offset, BranchType_JMP);
1126061da546Spatrick #endif
1127061da546Spatrick
1128061da546Spatrick bool success = false;
1129061da546Spatrick
1130061da546Spatrick uint32_t t = Bits32(opcode, 4, 0);
1131061da546Spatrick bool is_zero = Bit32(opcode, 24) == 0;
1132061da546Spatrick int32_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
1133061da546Spatrick
1134061da546Spatrick const uint64_t operand =
1135061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + t, 0, &success);
1136061da546Spatrick if (!success)
1137061da546Spatrick return false;
1138061da546Spatrick
1139061da546Spatrick if (m_ignore_conditions || ((operand == 0) == is_zero)) {
1140061da546Spatrick const uint64_t pc = ReadRegisterUnsigned(
1141061da546Spatrick eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1142061da546Spatrick if (!success)
1143061da546Spatrick return false;
1144061da546Spatrick
1145061da546Spatrick EmulateInstruction::Context context;
1146061da546Spatrick context.type = EmulateInstruction::eContextRelativeBranchImmediate;
1147061da546Spatrick context.SetImmediateSigned(offset);
1148061da546Spatrick if (!BranchTo(context, 64, pc + offset))
1149061da546Spatrick return false;
1150061da546Spatrick }
1151061da546Spatrick return true;
1152061da546Spatrick }
1153061da546Spatrick
EmulateTBZ(const uint32_t opcode)1154061da546Spatrick bool EmulateInstructionARM64::EmulateTBZ(const uint32_t opcode) {
1155061da546Spatrick #if 0
1156061da546Spatrick integer t = UInt(Rt);
1157061da546Spatrick integer datasize = if b5 == '1' then 64 else 32;
1158061da546Spatrick integer bit_pos = UInt(b5:b40);
1159061da546Spatrick bit bit_val = op;
1160061da546Spatrick bits(64) offset = SignExtend(imm14:'00', 64);
1161061da546Spatrick #endif
1162061da546Spatrick
1163061da546Spatrick bool success = false;
1164061da546Spatrick
1165061da546Spatrick uint32_t t = Bits32(opcode, 4, 0);
1166061da546Spatrick uint32_t bit_pos = (Bit32(opcode, 31) << 6) | (Bits32(opcode, 23, 19));
1167061da546Spatrick uint32_t bit_val = Bit32(opcode, 24);
1168061da546Spatrick int64_t offset = llvm::SignExtend64<16>(Bits32(opcode, 18, 5) << 2);
1169061da546Spatrick
1170061da546Spatrick const uint64_t operand =
1171061da546Spatrick ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + t, 0, &success);
1172061da546Spatrick if (!success)
1173061da546Spatrick return false;
1174061da546Spatrick
1175061da546Spatrick if (m_ignore_conditions || Bit32(operand, bit_pos) == bit_val) {
1176061da546Spatrick const uint64_t pc = ReadRegisterUnsigned(
1177061da546Spatrick eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1178061da546Spatrick if (!success)
1179061da546Spatrick return false;
1180061da546Spatrick
1181061da546Spatrick EmulateInstruction::Context context;
1182061da546Spatrick context.type = EmulateInstruction::eContextRelativeBranchImmediate;
1183061da546Spatrick context.SetImmediateSigned(offset);
1184061da546Spatrick if (!BranchTo(context, 64, pc + offset))
1185061da546Spatrick return false;
1186061da546Spatrick }
1187061da546Spatrick return true;
1188061da546Spatrick }
1189