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