1 //===-- EmulateInstructionARM64.cpp ---------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "EmulateInstructionARM64.h"
10
11 #include "lldb/Core/Address.h"
12 #include "lldb/Core/PluginManager.h"
13 #include "lldb/Symbol/UnwindPlan.h"
14 #include "lldb/Utility/ArchSpec.h"
15 #include "lldb/Utility/ConstString.h"
16 #include "lldb/Utility/RegisterValue.h"
17 #include "lldb/Utility/Stream.h"
18
19 #include "llvm/Support/CheckedArithmetic.h"
20
21 #include "Plugins/Process/Utility/ARMDefines.h"
22 #include "Plugins/Process/Utility/ARMUtils.h"
23 #include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
24
25 #include <cstdlib>
26
27 #define GPR_OFFSET(idx) ((idx)*8)
28 #define GPR_OFFSET_NAME(reg) 0
29 #define FPU_OFFSET(idx) ((idx)*16)
30 #define FPU_OFFSET_NAME(reg) 0
31 #define EXC_OFFSET_NAME(reg) 0
32 #define DBG_OFFSET_NAME(reg) 0
33 #define DBG_OFFSET_NAME(reg) 0
34 #define DEFINE_DBG(re, y) \
35 "na", nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \
36 {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
37 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, \
38 nullptr, nullptr, nullptr, 0
39
40 #define DECLARE_REGISTER_INFOS_ARM64_STRUCT
41
42 #include "Plugins/Process/Utility/RegisterInfos_arm64.h"
43
44 #include "llvm/ADT/STLExtras.h"
45 #include "llvm/Support/MathExtras.h"
46
47 #include "Plugins/Process/Utility/InstructionUtils.h"
48
49 using namespace lldb;
50 using namespace lldb_private;
51
LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM64,InstructionARM64)52 LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM64, InstructionARM64)
53
54 static bool LLDBTableGetRegisterInfo(uint32_t reg_num, RegisterInfo ®_info) {
55 if (reg_num >= llvm::array_lengthof(g_register_infos_arm64_le))
56 return false;
57 reg_info = g_register_infos_arm64_le[reg_num];
58 return true;
59 }
60
61 #define No_VFP 0
62 #define VFPv1 (1u << 1)
63 #define VFPv2 (1u << 2)
64 #define VFPv3 (1u << 3)
65 #define AdvancedSIMD (1u << 4)
66
67 #define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)
68 #define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)
69 #define VFPv2v3 (VFPv2 | VFPv3)
70
71 #define UInt(x) ((uint64_t)x)
72 #define SInt(x) ((int64_t)x)
73 #define bit bool
74 #define boolean bool
75 #define integer int64_t
76
IsZero(uint64_t x)77 static inline bool IsZero(uint64_t x) { return x == 0; }
78
NOT(uint64_t x)79 static inline uint64_t NOT(uint64_t x) { return ~x; }
80
81 // LSL()
82 // =====
83
LSL(uint64_t x,integer shift)84 static inline uint64_t LSL(uint64_t x, integer shift) {
85 if (shift == 0)
86 return x;
87 return x << shift;
88 }
89
90 // ConstrainUnpredictable()
91 // ========================
92
93 EmulateInstructionARM64::ConstraintType
ConstrainUnpredictable(EmulateInstructionARM64::Unpredictable which)94 ConstrainUnpredictable(EmulateInstructionARM64::Unpredictable which) {
95 EmulateInstructionARM64::ConstraintType result =
96 EmulateInstructionARM64::Constraint_UNKNOWN;
97 switch (which) {
98 case EmulateInstructionARM64::Unpredictable_WBOVERLAP:
99 case EmulateInstructionARM64::Unpredictable_LDPOVERLAP:
100 // TODO: don't know what to really do here? Pseudo code says:
101 // set result to one of above Constraint behaviours or UNDEFINED
102 break;
103 }
104 return result;
105 }
106
107 //
108 // EmulateInstructionARM implementation
109 //
110
Initialize()111 void EmulateInstructionARM64::Initialize() {
112 PluginManager::RegisterPlugin(GetPluginNameStatic(),
113 GetPluginDescriptionStatic(), CreateInstance);
114 }
115
Terminate()116 void EmulateInstructionARM64::Terminate() {
117 PluginManager::UnregisterPlugin(CreateInstance);
118 }
119
GetPluginNameStatic()120 ConstString EmulateInstructionARM64::GetPluginNameStatic() {
121 ConstString g_plugin_name("lldb.emulate-instruction.arm64");
122 return g_plugin_name;
123 }
124
GetPluginName()125 lldb_private::ConstString EmulateInstructionARM64::GetPluginName() {
126 static ConstString g_plugin_name("EmulateInstructionARM64");
127 return g_plugin_name;
128 }
129
GetPluginDescriptionStatic()130 const char *EmulateInstructionARM64::GetPluginDescriptionStatic() {
131 return "Emulate instructions for the ARM64 architecture.";
132 }
133
134 EmulateInstruction *
CreateInstance(const ArchSpec & arch,InstructionType inst_type)135 EmulateInstructionARM64::CreateInstance(const ArchSpec &arch,
136 InstructionType inst_type) {
137 if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic(
138 inst_type)) {
139 if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
140 arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {
141 return new EmulateInstructionARM64(arch);
142 }
143 }
144
145 return nullptr;
146 }
147
SetTargetTriple(const ArchSpec & arch)148 bool EmulateInstructionARM64::SetTargetTriple(const ArchSpec &arch) {
149 if (arch.GetTriple().getArch() == llvm::Triple::arm)
150 return true;
151 else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
152 return true;
153
154 return false;
155 }
156
GetRegisterInfo(RegisterKind reg_kind,uint32_t reg_num,RegisterInfo & reg_info)157 bool EmulateInstructionARM64::GetRegisterInfo(RegisterKind reg_kind,
158 uint32_t reg_num,
159 RegisterInfo ®_info) {
160 if (reg_kind == eRegisterKindGeneric) {
161 switch (reg_num) {
162 case LLDB_REGNUM_GENERIC_PC:
163 reg_kind = eRegisterKindLLDB;
164 reg_num = gpr_pc_arm64;
165 break;
166 case LLDB_REGNUM_GENERIC_SP:
167 reg_kind = eRegisterKindLLDB;
168 reg_num = gpr_sp_arm64;
169 break;
170 case LLDB_REGNUM_GENERIC_FP:
171 reg_kind = eRegisterKindLLDB;
172 reg_num = gpr_fp_arm64;
173 break;
174 case LLDB_REGNUM_GENERIC_RA:
175 reg_kind = eRegisterKindLLDB;
176 reg_num = gpr_lr_arm64;
177 break;
178 case LLDB_REGNUM_GENERIC_FLAGS:
179 reg_kind = eRegisterKindLLDB;
180 reg_num = gpr_cpsr_arm64;
181 break;
182
183 default:
184 return false;
185 }
186 }
187
188 if (reg_kind == eRegisterKindLLDB)
189 return LLDBTableGetRegisterInfo(reg_num, reg_info);
190 return false;
191 }
192
193 EmulateInstructionARM64::Opcode *
GetOpcodeForInstruction(const uint32_t opcode)194 EmulateInstructionARM64::GetOpcodeForInstruction(const uint32_t opcode) {
195 static EmulateInstructionARM64::Opcode g_opcodes[] = {
196 // Prologue instructions
197
198 // push register(s)
199 {0xff000000, 0xd1000000, No_VFP,
200 &EmulateInstructionARM64::EmulateADDSUBImm,
201 "SUB <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"},
202 {0xff000000, 0xf1000000, No_VFP,
203 &EmulateInstructionARM64::EmulateADDSUBImm,
204 "SUBS <Xd>, <Xn|SP>, #<imm> {, <shift>}"},
205 {0xff000000, 0x91000000, No_VFP,
206 &EmulateInstructionARM64::EmulateADDSUBImm,
207 "ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"},
208 {0xff000000, 0xb1000000, No_VFP,
209 &EmulateInstructionARM64::EmulateADDSUBImm,
210 "ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}"},
211
212 {0xff000000, 0x51000000, No_VFP,
213 &EmulateInstructionARM64::EmulateADDSUBImm,
214 "SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"},
215 {0xff000000, 0x71000000, No_VFP,
216 &EmulateInstructionARM64::EmulateADDSUBImm,
217 "SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"},
218 {0xff000000, 0x11000000, No_VFP,
219 &EmulateInstructionARM64::EmulateADDSUBImm,
220 "ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"},
221 {0xff000000, 0x31000000, No_VFP,
222 &EmulateInstructionARM64::EmulateADDSUBImm,
223 "ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"},
224
225 {0xffc00000, 0x29000000, No_VFP,
226 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
227 "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},
228 {0xffc00000, 0xa9000000, No_VFP,
229 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
230 "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},
231 {0xffc00000, 0x2d000000, No_VFP,
232 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
233 "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},
234 {0xffc00000, 0x6d000000, No_VFP,
235 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
236 "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},
237 {0xffc00000, 0xad000000, No_VFP,
238 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
239 "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},
240
241 {0xffc00000, 0x29800000, No_VFP,
242 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
243 "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
244 {0xffc00000, 0xa9800000, No_VFP,
245 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
246 "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
247 {0xffc00000, 0x2d800000, No_VFP,
248 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
249 "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
250 {0xffc00000, 0x6d800000, No_VFP,
251 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
252 "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
253 {0xffc00000, 0xad800000, No_VFP,
254 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
255 "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
256
257 {0xffc00000, 0x28800000, No_VFP,
258 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
259 "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
260 {0xffc00000, 0xa8800000, No_VFP,
261 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
262 "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
263 {0xffc00000, 0x2c800000, No_VFP,
264 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
265 "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
266 {0xffc00000, 0x6c800000, No_VFP,
267 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
268 "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
269 {0xffc00000, 0xac800000, No_VFP,
270 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
271 "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
272
273 {0xffc00000, 0x29400000, No_VFP,
274 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
275 "LDP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},
276 {0xffc00000, 0xa9400000, No_VFP,
277 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
278 "LDP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},
279 {0xffc00000, 0x2d400000, No_VFP,
280 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
281 "LDP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},
282 {0xffc00000, 0x6d400000, No_VFP,
283 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
284 "LDP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},
285 {0xffc00000, 0xad400000, No_VFP,
286 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
287 "LDP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},
288
289 {0xffc00000, 0x29c00000, No_VFP,
290 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
291 "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
292 {0xffc00000, 0xa9c00000, No_VFP,
293 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
294 "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
295 {0xffc00000, 0x2dc00000, No_VFP,
296 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
297 "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
298 {0xffc00000, 0x6dc00000, No_VFP,
299 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
300 "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
301 {0xffc00000, 0xadc00000, No_VFP,
302 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
303 "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
304
305 {0xffc00000, 0x28c00000, No_VFP,
306 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
307 "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
308 {0xffc00000, 0xa8c00000, No_VFP,
309 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
310 "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
311 {0xffc00000, 0x2cc00000, No_VFP,
312 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
313 "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
314 {0xffc00000, 0x6cc00000, No_VFP,
315 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
316 "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
317 {0xffc00000, 0xacc00000, No_VFP,
318 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
319 "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
320
321 {0xffe00c00, 0xb8000400, No_VFP,
322 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
323 "STR <Wt>, [<Xn|SP>], #<simm>"},
324 {0xffe00c00, 0xf8000400, No_VFP,
325 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
326 "STR <Xt>, [<Xn|SP>], #<simm>"},
327 {0xffe00c00, 0xb8000c00, No_VFP,
328 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
329 "STR <Wt>, [<Xn|SP>, #<simm>]!"},
330 {0xffe00c00, 0xf8000c00, No_VFP,
331 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
332 "STR <Xt>, [<Xn|SP>, #<simm>]!"},
333 {0xffc00000, 0xb9000000, No_VFP,
334 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
335 "STR <Wt>, [<Xn|SP>{, #<pimm>}]"},
336 {0xffc00000, 0xf9000000, No_VFP,
337 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
338 "STR <Xt>, [<Xn|SP>{, #<pimm>}]"},
339
340 {0xffe00c00, 0xb8400400, No_VFP,
341 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
342 "LDR <Wt>, [<Xn|SP>], #<simm>"},
343 {0xffe00c00, 0xf8400400, No_VFP,
344 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
345 "LDR <Xt>, [<Xn|SP>], #<simm>"},
346 {0xffe00c00, 0xb8400c00, No_VFP,
347 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
348 "LDR <Wt>, [<Xn|SP>, #<simm>]!"},
349 {0xffe00c00, 0xf8400c00, No_VFP,
350 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
351 "LDR <Xt>, [<Xn|SP>, #<simm>]!"},
352 {0xffc00000, 0xb9400000, No_VFP,
353 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
354 "LDR <Wt>, [<Xn|SP>{, #<pimm>}]"},
355 {0xffc00000, 0xf9400000, No_VFP,
356 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
357 "LDR <Xt>, [<Xn|SP>{, #<pimm>}]"},
358
359 {0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB,
360 "B <label>"},
361 {0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond,
362 "B.<cond> <label>"},
363 {0x7f000000, 0x34000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,
364 "CBZ <Wt>, <label>"},
365 {0x7f000000, 0x35000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,
366 "CBNZ <Wt>, <label>"},
367 {0x7f000000, 0x36000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,
368 "TBZ <R><t>, #<imm>, <label>"},
369 {0x7f000000, 0x37000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,
370 "TBNZ <R><t>, #<imm>, <label>"},
371
372 };
373 static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_opcodes);
374
375 for (size_t i = 0; i < k_num_arm_opcodes; ++i) {
376 if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
377 return &g_opcodes[i];
378 }
379 return nullptr;
380 }
381
ReadInstruction()382 bool EmulateInstructionARM64::ReadInstruction() {
383 bool success = false;
384 m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
385 LLDB_INVALID_ADDRESS, &success);
386 if (success) {
387 Context read_inst_context;
388 read_inst_context.type = eContextReadOpcode;
389 read_inst_context.SetNoArgs();
390 m_opcode.SetOpcode32(
391 ReadMemoryUnsigned(read_inst_context, m_addr, 4, 0, &success),
392 GetByteOrder());
393 }
394 if (!success)
395 m_addr = LLDB_INVALID_ADDRESS;
396 return success;
397 }
398
EvaluateInstruction(uint32_t evaluate_options)399 bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) {
400 const uint32_t opcode = m_opcode.GetOpcode32();
401 Opcode *opcode_data = GetOpcodeForInstruction(opcode);
402 if (opcode_data == nullptr)
403 return false;
404
405 const bool auto_advance_pc =
406 evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
407 m_ignore_conditions =
408 evaluate_options & eEmulateInstructionOptionIgnoreConditions;
409
410 bool success = false;
411
412 // Only return false if we are unable to read the CPSR if we care about
413 // conditions
414 if (!success && !m_ignore_conditions)
415 return false;
416
417 uint32_t orig_pc_value = 0;
418 if (auto_advance_pc) {
419 orig_pc_value =
420 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success);
421 if (!success)
422 return false;
423 }
424
425 // Call the Emulate... function.
426 success = (this->*opcode_data->callback)(opcode);
427 if (!success)
428 return false;
429
430 if (auto_advance_pc) {
431 uint32_t new_pc_value =
432 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success);
433 if (!success)
434 return false;
435
436 if (new_pc_value == orig_pc_value) {
437 EmulateInstruction::Context context;
438 context.type = eContextAdvancePC;
439 context.SetNoArgs();
440 if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_arm64,
441 orig_pc_value + 4))
442 return false;
443 }
444 }
445 return true;
446 }
447
CreateFunctionEntryUnwind(UnwindPlan & unwind_plan)448 bool EmulateInstructionARM64::CreateFunctionEntryUnwind(
449 UnwindPlan &unwind_plan) {
450 unwind_plan.Clear();
451 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
452
453 UnwindPlan::RowSP row(new UnwindPlan::Row);
454
455 // Our previous Call Frame Address is the stack pointer
456 row->GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_arm64, 0);
457
458 unwind_plan.AppendRow(row);
459 unwind_plan.SetSourceName("EmulateInstructionARM64");
460 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
461 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
462 unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
463 unwind_plan.SetReturnAddressRegister(gpr_lr_arm64);
464 return true;
465 }
466
GetFramePointerRegisterNumber() const467 uint32_t EmulateInstructionARM64::GetFramePointerRegisterNumber() const {
468 if (m_arch.GetTriple().isAndroid())
469 return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
470
471 return gpr_fp_arm64;
472 }
473
UsingAArch32()474 bool EmulateInstructionARM64::UsingAArch32() {
475 bool aarch32 = m_opcode_pstate.RW == 1;
476 // if !HaveAnyAArch32() then assert !aarch32;
477 // if HighestELUsingAArch32() then assert aarch32;
478 return aarch32;
479 }
480
BranchTo(const Context & context,uint32_t N,addr_t target)481 bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N,
482 addr_t target) {
483 #if 0
484 // Set program counter to a new address, with a branch reason hint for
485 // possible use by hardware fetching the next instruction.
486 BranchTo(bits(N) target, BranchType branch_type)
487 Hint_Branch(branch_type);
488 if N == 32 then
489 assert UsingAArch32();
490 _PC = ZeroExtend(target);
491 else
492 assert N == 64 && !UsingAArch32();
493 // Remove the tag bits from a tagged target
494 case PSTATE.EL of
495 when EL0, EL1
496 if target<55> == '1' && TCR_EL1.TBI1 == '1' then
497 target<63:56> = '11111111';
498 if target<55> == '0' && TCR_EL1.TBI0 == '1' then
499 target<63:56> = '00000000';
500 when EL2
501 if TCR_EL2.TBI == '1' then
502 target<63:56> = '00000000';
503 when EL3
504 if TCR_EL3.TBI == '1' then
505 target<63:56> = '00000000';
506 _PC = target<63:0>;
507 return;
508 #endif
509
510 addr_t addr;
511
512 // Hint_Branch(branch_type);
513 if (N == 32) {
514 if (!UsingAArch32())
515 return false;
516 addr = target;
517 } else if (N == 64) {
518 if (UsingAArch32())
519 return false;
520 // TODO: Remove the tag bits from a tagged target
521 addr = target;
522 } else
523 return false;
524
525 return WriteRegisterUnsigned(context, eRegisterKindGeneric,
526 LLDB_REGNUM_GENERIC_PC, addr);
527 }
528
ConditionHolds(const uint32_t cond)529 bool EmulateInstructionARM64::ConditionHolds(const uint32_t cond) {
530 // If we are ignoring conditions, then always return true. this allows us to
531 // iterate over disassembly code and still emulate an instruction even if we
532 // don't have all the right bits set in the CPSR register...
533 if (m_ignore_conditions)
534 return true;
535
536 bool result = false;
537 switch (UnsignedBits(cond, 3, 1)) {
538 case 0:
539 result = (m_opcode_pstate.Z == 1);
540 break;
541 case 1:
542 result = (m_opcode_pstate.C == 1);
543 break;
544 case 2:
545 result = (m_opcode_pstate.N == 1);
546 break;
547 case 3:
548 result = (m_opcode_pstate.V == 1);
549 break;
550 case 4:
551 result = (m_opcode_pstate.C == 1 && m_opcode_pstate.Z == 0);
552 break;
553 case 5:
554 result = (m_opcode_pstate.N == m_opcode_pstate.V);
555 break;
556 case 6:
557 result = (m_opcode_pstate.N == m_opcode_pstate.V && m_opcode_pstate.Z == 0);
558 break;
559 case 7:
560 // Always execute (cond == 0b1110, or the special 0b1111 which gives
561 // opcodes different meanings, but always means execution happens.
562 return true;
563 }
564
565 if (cond & 1)
566 result = !result;
567 return result;
568 }
569
570 uint64_t EmulateInstructionARM64::
AddWithCarry(uint32_t N,uint64_t x,uint64_t y,bit carry_in,EmulateInstructionARM64::ProcState & proc_state)571 AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in,
572 EmulateInstructionARM64::ProcState &proc_state) {
573 uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
574 llvm::Optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y));
575 bool overflow = !signed_sum;
576 if (!overflow)
577 overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in));
578 uint64_t result = unsigned_sum;
579 if (N < 64)
580 result = Bits64(result, N - 1, 0);
581 proc_state.N = Bit64(result, N - 1);
582 proc_state.Z = IsZero(result);
583 proc_state.C = UInt(result) != unsigned_sum;
584 proc_state.V = overflow;
585 return result;
586 }
587
EmulateADDSUBImm(const uint32_t opcode)588 bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) {
589 // integer d = UInt(Rd);
590 // integer n = UInt(Rn);
591 // integer datasize = if sf == 1 then 64 else 32;
592 // boolean sub_op = (op == 1);
593 // boolean setflags = (S == 1);
594 // bits(datasize) imm;
595 //
596 // case shift of
597 // when '00' imm = ZeroExtend(imm12, datasize);
598 // when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize);
599 // when '1x' UNDEFINED;
600 //
601 //
602 // bits(datasize) result;
603 // bits(datasize) operand1 = if n == 31 then SP[] else X[n];
604 // bits(datasize) operand2 = imm;
605 // bits(4) nzcv;
606 // bit carry_in;
607 //
608 // if sub_op then
609 // operand2 = NOT(operand2);
610 // carry_in = 1;
611 // else
612 // carry_in = 0;
613 //
614 // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in);
615 //
616 // if setflags then
617 // PSTATE.NZCV = nzcv;
618 //
619 // if d == 31 && !setflags then
620 // SP[] = result;
621 // else
622 // X[d] = result;
623
624 const uint32_t sf = Bit32(opcode, 31);
625 const uint32_t op = Bit32(opcode, 30);
626 const uint32_t S = Bit32(opcode, 29);
627 const uint32_t shift = Bits32(opcode, 23, 22);
628 const uint32_t imm12 = Bits32(opcode, 21, 10);
629 const uint32_t Rn = Bits32(opcode, 9, 5);
630 const uint32_t Rd = Bits32(opcode, 4, 0);
631
632 bool success = false;
633
634 const uint32_t d = UInt(Rd);
635 const uint32_t n = UInt(Rn);
636 const uint32_t datasize = (sf == 1) ? 64 : 32;
637 boolean sub_op = op == 1;
638 boolean setflags = S == 1;
639 uint64_t imm;
640
641 switch (shift) {
642 case 0:
643 imm = imm12;
644 break;
645 case 1:
646 imm = imm12 << 12;
647 break;
648 default:
649 return false; // UNDEFINED;
650 }
651 uint64_t result;
652 uint64_t operand1 =
653 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);
654 uint64_t operand2 = imm;
655 bit carry_in;
656
657 if (sub_op) {
658 operand2 = NOT(operand2);
659 carry_in = true;
660 imm = -imm; // For the Register plug offset context below
661 } else {
662 carry_in = false;
663 }
664
665 ProcState proc_state;
666
667 result = AddWithCarry(datasize, operand1, operand2, carry_in, proc_state);
668
669 if (setflags) {
670 m_emulated_pstate.N = proc_state.N;
671 m_emulated_pstate.Z = proc_state.Z;
672 m_emulated_pstate.C = proc_state.C;
673 m_emulated_pstate.V = proc_state.V;
674 }
675
676 Context context;
677 RegisterInfo reg_info_Rn;
678 if (GetRegisterInfo(eRegisterKindLLDB, n, reg_info_Rn))
679 context.SetRegisterPlusOffset(reg_info_Rn, imm);
680
681 if (n == GetFramePointerRegisterNumber() && d == gpr_sp_arm64 && !setflags) {
682 // 'mov sp, fp' - common epilogue instruction, CFA is now in terms of the
683 // stack pointer, instead of frame pointer.
684 context.type = EmulateInstruction::eContextRestoreStackPointer;
685 } else if ((n == gpr_sp_arm64 || n == GetFramePointerRegisterNumber()) &&
686 d == gpr_sp_arm64 && !setflags) {
687 context.type = EmulateInstruction::eContextAdjustStackPointer;
688 } else if (d == GetFramePointerRegisterNumber() && n == gpr_sp_arm64 &&
689 !setflags) {
690 context.type = EmulateInstruction::eContextSetFramePointer;
691 } else {
692 context.type = EmulateInstruction::eContextImmediate;
693 }
694
695 // If setflags && d == gpr_sp_arm64 then d = WZR/XZR. See CMN, CMP
696 if (!setflags || d != gpr_sp_arm64)
697 WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_x0_arm64 + d, result);
698
699 return false;
700 }
701
702 template <EmulateInstructionARM64::AddrMode a_mode>
EmulateLDPSTP(const uint32_t opcode)703 bool EmulateInstructionARM64::EmulateLDPSTP(const uint32_t opcode) {
704 uint32_t opc = Bits32(opcode, 31, 30);
705 uint32_t V = Bit32(opcode, 26);
706 uint32_t L = Bit32(opcode, 22);
707 uint32_t imm7 = Bits32(opcode, 21, 15);
708 uint32_t Rt2 = Bits32(opcode, 14, 10);
709 uint32_t Rn = Bits32(opcode, 9, 5);
710 uint32_t Rt = Bits32(opcode, 4, 0);
711
712 integer n = UInt(Rn);
713 integer t = UInt(Rt);
714 integer t2 = UInt(Rt2);
715 uint64_t idx;
716
717 MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE;
718 boolean vector = (V == 1);
719 // AccType acctype = AccType_NORMAL;
720 boolean is_signed = false;
721 boolean wback = a_mode != AddrMode_OFF;
722 boolean wb_unknown = false;
723 boolean rt_unknown = false;
724 integer scale;
725 integer size;
726
727 if (opc == 3)
728 return false; // UNDEFINED
729
730 if (vector) {
731 scale = 2 + UInt(opc);
732 } else {
733 scale = (opc & 2) ? 3 : 2;
734 is_signed = (opc & 1) != 0;
735 if (is_signed && memop == MemOp_STORE)
736 return false; // UNDEFINED
737 }
738
739 if (!vector && wback && ((t == n) || (t2 == n))) {
740 switch (ConstrainUnpredictable(Unpredictable_WBOVERLAP)) {
741 case Constraint_UNKNOWN:
742 wb_unknown = true; // writeback is UNKNOWN
743 break;
744
745 case Constraint_SUPPRESSWB:
746 wback = false; // writeback is suppressed
747 break;
748
749 case Constraint_NOP:
750 memop = MemOp_NOP; // do nothing
751 wback = false;
752 break;
753
754 case Constraint_NONE:
755 break;
756 }
757 }
758
759 if (memop == MemOp_LOAD && t == t2) {
760 switch (ConstrainUnpredictable(Unpredictable_LDPOVERLAP)) {
761 case Constraint_UNKNOWN:
762 rt_unknown = true; // result is UNKNOWN
763 break;
764
765 case Constraint_NOP:
766 memop = MemOp_NOP; // do nothing
767 wback = false;
768 break;
769
770 default:
771 break;
772 }
773 }
774
775 idx = LSL(llvm::SignExtend64<7>(imm7), scale);
776 size = (integer)1 << scale;
777 uint64_t datasize = size * 8;
778 uint64_t address;
779 uint64_t wb_address;
780
781 RegisterValue data_Rt;
782 RegisterValue data_Rt2;
783 RegisterInfo reg_info_base;
784 RegisterInfo reg_info_Rt;
785 RegisterInfo reg_info_Rt2;
786 if (!GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + n, reg_info_base))
787 return false;
788
789 if (vector) {
790 if (!GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t, reg_info_Rt))
791 return false;
792 if (!GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t2, reg_info_Rt2))
793 return false;
794 } else {
795 if (!GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t, reg_info_Rt))
796 return false;
797 if (!GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t2, reg_info_Rt2))
798 return false;
799 }
800
801 bool success = false;
802 if (n == 31) {
803 // CheckSPAlignment();
804 address =
805 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_sp_arm64, 0, &success);
806 } else
807 address =
808 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);
809
810 wb_address = address + idx;
811 if (a_mode != AddrMode_POST)
812 address = wb_address;
813
814 Context context_t;
815 Context context_t2;
816
817 uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
818 Status error;
819
820 switch (memop) {
821 case MemOp_STORE: {
822 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
823 // based off of the sp
824 // or fp register
825 {
826 context_t.type = eContextPushRegisterOnStack;
827 context_t2.type = eContextPushRegisterOnStack;
828 } else {
829 context_t.type = eContextRegisterStore;
830 context_t2.type = eContextRegisterStore;
831 }
832 context_t.SetRegisterToRegisterPlusOffset(reg_info_Rt, reg_info_base, 0);
833 context_t2.SetRegisterToRegisterPlusOffset(reg_info_Rt2, reg_info_base,
834 size);
835
836 if (!ReadRegister(®_info_Rt, data_Rt))
837 return false;
838
839 if (data_Rt.GetAsMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size,
840 eByteOrderLittle, error) == 0)
841 return false;
842
843 if (!WriteMemory(context_t, address + 0, buffer, reg_info_Rt.byte_size))
844 return false;
845
846 if (!ReadRegister(®_info_Rt2, data_Rt2))
847 return false;
848
849 if (data_Rt2.GetAsMemoryData(®_info_Rt2, buffer, reg_info_Rt2.byte_size,
850 eByteOrderLittle, error) == 0)
851 return false;
852
853 if (!WriteMemory(context_t2, address + size, buffer,
854 reg_info_Rt2.byte_size))
855 return false;
856 } break;
857
858 case MemOp_LOAD: {
859 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this load is
860 // based off of the sp
861 // or fp register
862 {
863 context_t.type = eContextPopRegisterOffStack;
864 context_t2.type = eContextPopRegisterOffStack;
865 } else {
866 context_t.type = eContextRegisterLoad;
867 context_t2.type = eContextRegisterLoad;
868 }
869 context_t.SetAddress(address);
870 context_t2.SetAddress(address + size);
871
872 if (rt_unknown)
873 memset(buffer, 'U', reg_info_Rt.byte_size);
874 else {
875 if (!ReadMemory(context_t, address, buffer, reg_info_Rt.byte_size))
876 return false;
877 }
878
879 if (data_Rt.SetFromMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size,
880 eByteOrderLittle, error) == 0)
881 return false;
882
883 if (!vector && is_signed && !data_Rt.SignExtend(datasize))
884 return false;
885
886 if (!WriteRegister(context_t, ®_info_Rt, data_Rt))
887 return false;
888
889 if (!rt_unknown) {
890 if (!ReadMemory(context_t2, address + size, buffer,
891 reg_info_Rt2.byte_size))
892 return false;
893 }
894
895 if (data_Rt2.SetFromMemoryData(®_info_Rt2, buffer,
896 reg_info_Rt2.byte_size, eByteOrderLittle,
897 error) == 0)
898 return false;
899
900 if (!vector && is_signed && !data_Rt2.SignExtend(datasize))
901 return false;
902
903 if (!WriteRegister(context_t2, ®_info_Rt2, data_Rt2))
904 return false;
905 } break;
906
907 default:
908 break;
909 }
910
911 if (wback) {
912 if (wb_unknown)
913 wb_address = LLDB_INVALID_ADDRESS;
914 Context context;
915 context.SetImmediateSigned(idx);
916 if (n == 31)
917 context.type = eContextAdjustStackPointer;
918 else
919 context.type = eContextAdjustBaseRegister;
920 WriteRegisterUnsigned(context, ®_info_base, wb_address);
921 }
922 return true;
923 }
924
925 template <EmulateInstructionARM64::AddrMode a_mode>
EmulateLDRSTRImm(const uint32_t opcode)926 bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
927 uint32_t size = Bits32(opcode, 31, 30);
928 uint32_t opc = Bits32(opcode, 23, 22);
929 uint32_t n = Bits32(opcode, 9, 5);
930 uint32_t t = Bits32(opcode, 4, 0);
931
932 bool wback;
933 bool postindex;
934 uint64_t offset;
935
936 switch (a_mode) {
937 case AddrMode_POST:
938 wback = true;
939 postindex = true;
940 offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));
941 break;
942 case AddrMode_PRE:
943 wback = true;
944 postindex = false;
945 offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));
946 break;
947 case AddrMode_OFF:
948 wback = false;
949 postindex = false;
950 offset = LSL(Bits32(opcode, 21, 10), size);
951 break;
952 }
953
954 MemOp memop;
955
956 if (Bit32(opc, 1) == 0) {
957 memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
958 } else {
959 memop = MemOp_LOAD;
960 if (size == 2 && Bit32(opc, 0) == 1)
961 return false;
962 }
963
964 Status error;
965 bool success = false;
966 uint64_t address;
967 uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
968 RegisterValue data_Rt;
969
970 if (n == 31)
971 address =
972 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_sp_arm64, 0, &success);
973 else
974 address =
975 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + n, 0, &success);
976
977 if (!success)
978 return false;
979
980 if (!postindex)
981 address += offset;
982
983 RegisterInfo reg_info_base;
984 if (!GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + n, reg_info_base))
985 return false;
986
987 RegisterInfo reg_info_Rt;
988 if (!GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t, reg_info_Rt))
989 return false;
990
991 Context context;
992 switch (memop) {
993 case MemOp_STORE:
994 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
995 // based off of the sp
996 // or fp register
997 context.type = eContextPushRegisterOnStack;
998 else
999 context.type = eContextRegisterStore;
1000 context.SetRegisterToRegisterPlusOffset(reg_info_Rt, reg_info_base,
1001 postindex ? 0 : offset);
1002
1003 if (!ReadRegister(®_info_Rt, data_Rt))
1004 return false;
1005
1006 if (data_Rt.GetAsMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size,
1007 eByteOrderLittle, error) == 0)
1008 return false;
1009
1010 if (!WriteMemory(context, address, buffer, reg_info_Rt.byte_size))
1011 return false;
1012 break;
1013
1014 case MemOp_LOAD:
1015 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
1016 // based off of the sp
1017 // or fp register
1018 context.type = eContextPopRegisterOffStack;
1019 else
1020 context.type = eContextRegisterLoad;
1021 context.SetAddress(address);
1022
1023 if (!ReadMemory(context, address, buffer, reg_info_Rt.byte_size))
1024 return false;
1025
1026 if (data_Rt.SetFromMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size,
1027 eByteOrderLittle, error) == 0)
1028 return false;
1029
1030 if (!WriteRegister(context, ®_info_Rt, data_Rt))
1031 return false;
1032 break;
1033 default:
1034 return false;
1035 }
1036
1037 if (wback) {
1038 if (postindex)
1039 address += offset;
1040
1041 if (n == 31)
1042 context.type = eContextAdjustStackPointer;
1043 else
1044 context.type = eContextAdjustBaseRegister;
1045 context.SetImmediateSigned(offset);
1046
1047 if (!WriteRegisterUnsigned(context, ®_info_base, address))
1048 return false;
1049 }
1050 return true;
1051 }
1052
EmulateB(const uint32_t opcode)1053 bool EmulateInstructionARM64::EmulateB(const uint32_t opcode) {
1054 #if 0
1055 // ARM64 pseudo code...
1056 if branch_type == BranchType_CALL then X[30] = PC[] + 4;
1057 BranchTo(PC[] + offset, branch_type);
1058 #endif
1059
1060 bool success = false;
1061
1062 EmulateInstruction::Context context;
1063 context.type = EmulateInstruction::eContextRelativeBranchImmediate;
1064 const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric,
1065 LLDB_REGNUM_GENERIC_PC, 0, &success);
1066 if (!success)
1067 return false;
1068
1069 int64_t offset = llvm::SignExtend64<28>(Bits32(opcode, 25, 0) << 2);
1070 BranchType branch_type = Bit32(opcode, 31) ? BranchType_CALL : BranchType_JMP;
1071 addr_t target = pc + offset;
1072 context.SetImmediateSigned(offset);
1073
1074 switch (branch_type) {
1075 case BranchType_CALL: {
1076 addr_t x30 = pc + 4;
1077 if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_lr_arm64, x30))
1078 return false;
1079 } break;
1080 case BranchType_JMP:
1081 break;
1082 default:
1083 return false;
1084 }
1085
1086 return BranchTo(context, 64, target);
1087 }
1088
EmulateBcond(const uint32_t opcode)1089 bool EmulateInstructionARM64::EmulateBcond(const uint32_t opcode) {
1090 #if 0
1091 // ARM64 pseudo code...
1092 bits(64) offset = SignExtend(imm19:'00', 64);
1093 bits(4) condition = cond;
1094 if ConditionHolds(condition) then
1095 BranchTo(PC[] + offset, BranchType_JMP);
1096 #endif
1097
1098 if (ConditionHolds(Bits32(opcode, 3, 0))) {
1099 bool success = false;
1100
1101 const uint64_t pc = ReadRegisterUnsigned(
1102 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1103 if (!success)
1104 return false;
1105
1106 int64_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
1107 addr_t target = pc + offset;
1108
1109 EmulateInstruction::Context context;
1110 context.type = EmulateInstruction::eContextRelativeBranchImmediate;
1111 context.SetImmediateSigned(offset);
1112 if (!BranchTo(context, 64, target))
1113 return false;
1114 }
1115 return true;
1116 }
1117
EmulateCBZ(const uint32_t opcode)1118 bool EmulateInstructionARM64::EmulateCBZ(const uint32_t opcode) {
1119 #if 0
1120 integer t = UInt(Rt);
1121 integer datasize = if sf == '1' then 64 else 32;
1122 boolean iszero = (op == '0');
1123 bits(64) offset = SignExtend(imm19:'00', 64);
1124
1125 bits(datasize) operand1 = X[t];
1126 if IsZero(operand1) == iszero then
1127 BranchTo(PC[] + offset, BranchType_JMP);
1128 #endif
1129
1130 bool success = false;
1131
1132 uint32_t t = Bits32(opcode, 4, 0);
1133 bool is_zero = Bit32(opcode, 24) == 0;
1134 int32_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
1135
1136 const uint64_t operand =
1137 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + t, 0, &success);
1138 if (!success)
1139 return false;
1140
1141 if (m_ignore_conditions || ((operand == 0) == is_zero)) {
1142 const uint64_t pc = ReadRegisterUnsigned(
1143 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1144 if (!success)
1145 return false;
1146
1147 EmulateInstruction::Context context;
1148 context.type = EmulateInstruction::eContextRelativeBranchImmediate;
1149 context.SetImmediateSigned(offset);
1150 if (!BranchTo(context, 64, pc + offset))
1151 return false;
1152 }
1153 return true;
1154 }
1155
EmulateTBZ(const uint32_t opcode)1156 bool EmulateInstructionARM64::EmulateTBZ(const uint32_t opcode) {
1157 #if 0
1158 integer t = UInt(Rt);
1159 integer datasize = if b5 == '1' then 64 else 32;
1160 integer bit_pos = UInt(b5:b40);
1161 bit bit_val = op;
1162 bits(64) offset = SignExtend(imm14:'00', 64);
1163 #endif
1164
1165 bool success = false;
1166
1167 uint32_t t = Bits32(opcode, 4, 0);
1168 uint32_t bit_pos = (Bit32(opcode, 31) << 6) | (Bits32(opcode, 23, 19));
1169 uint32_t bit_val = Bit32(opcode, 24);
1170 int64_t offset = llvm::SignExtend64<16>(Bits32(opcode, 18, 5) << 2);
1171
1172 const uint64_t operand =
1173 ReadRegisterUnsigned(eRegisterKindLLDB, gpr_x0_arm64 + t, 0, &success);
1174 if (!success)
1175 return false;
1176
1177 if (m_ignore_conditions || Bit32(operand, bit_pos) == bit_val) {
1178 const uint64_t pc = ReadRegisterUnsigned(
1179 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1180 if (!success)
1181 return false;
1182
1183 EmulateInstruction::Context context;
1184 context.type = EmulateInstruction::eContextRelativeBranchImmediate;
1185 context.SetImmediateSigned(offset);
1186 if (!BranchTo(context, 64, pc + offset))
1187 return false;
1188 }
1189 return true;
1190 }
1191