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 <algorithm>
25#include <cstdlib>
26#include <optional>
27
28#define GPR_OFFSET(idx) ((idx)*8)
29#define GPR_OFFSET_NAME(reg) 0
30#define FPU_OFFSET(idx) ((idx)*16)
31#define FPU_OFFSET_NAME(reg) 0
32#define EXC_OFFSET_NAME(reg) 0
33#define DBG_OFFSET_NAME(reg) 0
34#define DBG_OFFSET_NAME(reg) 0
35#define DEFINE_DBG(re, y) \
36 "na", nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \
37 {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
38 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, \
39 nullptr, nullptr, nullptr
40
41#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
42
44
45#include "llvm/ADT/STLExtras.h"
46#include "llvm/Support/MathExtras.h"
47
49
50using namespace lldb;
51using namespace lldb_private;
52
54
55static std::optional<RegisterInfo> LLDBTableGetRegisterInfo(uint32_t reg_num) {
56 if (reg_num >= std::size(g_register_infos_arm64_le))
57 return {};
58 return g_register_infos_arm64_le[reg_num];
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
77static inline bool IsZero(uint64_t x) { return x == 0; }
78
79static inline uint64_t NOT(uint64_t x) { return ~x; }
80
81// LSL()
82// =====
83
84static 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
97 switch (which) {
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
115
119
121 return "Emulate instructions for the ARM64 architecture.";
122}
123
126 InstructionType inst_type) {
128 inst_type)) {
129 if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
130 arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {
131 return new EmulateInstructionARM64(arch);
132 }
133 }
134
135 return nullptr;
136}
137
139 if (arch.GetTriple().getArch() == llvm::Triple::arm)
140 return true;
141 else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
142 return true;
143
144 return false;
145}
146
147std::optional<RegisterInfo>
149 uint32_t reg_num) {
150 if (reg_kind == eRegisterKindGeneric) {
151 switch (reg_num) {
153 reg_kind = eRegisterKindLLDB;
154 reg_num = gpr_pc_arm64;
155 break;
157 reg_kind = eRegisterKindLLDB;
158 reg_num = gpr_sp_arm64;
159 break;
161 reg_kind = eRegisterKindLLDB;
162 reg_num = gpr_fp_arm64;
163 break;
165 reg_kind = eRegisterKindLLDB;
166 reg_num = gpr_lr_arm64;
167 break;
169 reg_kind = eRegisterKindLLDB;
170 reg_num = gpr_cpsr_arm64;
171 break;
172
173 default:
174 return {};
175 }
176 }
177
178 if (reg_kind == eRegisterKindLLDB)
179 return LLDBTableGetRegisterInfo(reg_num);
180 return {};
181}
182
185 static EmulateInstructionARM64::Opcode g_opcodes[] = {
186 // Prologue instructions
187
188 // push register(s)
189 {0xff000000, 0xd1000000, No_VFP,
191 "SUB <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"},
192 {0xff000000, 0xf1000000, No_VFP,
194 "SUBS <Xd>, <Xn|SP>, #<imm> {, <shift>}"},
195 {0xff000000, 0x91000000, No_VFP,
197 "ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}"},
198 {0xff000000, 0xb1000000, No_VFP,
200 "ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}"},
201
202 {0xff000000, 0x51000000, No_VFP,
204 "SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"},
205 {0xff000000, 0x71000000, No_VFP,
207 "SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"},
208 {0xff000000, 0x11000000, No_VFP,
210 "ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}"},
211 {0xff000000, 0x31000000, No_VFP,
213 "ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}"},
214
215 {0xffc00000, 0x29000000, No_VFP,
217 "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},
218 {0xffc00000, 0xa9000000, No_VFP,
220 "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},
221 {0xffc00000, 0x2d000000, No_VFP,
223 "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},
224 {0xffc00000, 0x6d000000, No_VFP,
226 "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},
227 {0xffc00000, 0xad000000, No_VFP,
229 "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},
230
231 {0xffc00000, 0x29800000, No_VFP,
233 "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
234 {0xffc00000, 0xa9800000, No_VFP,
236 "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
237 {0xffc00000, 0x2d800000, No_VFP,
239 "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
240 {0xffc00000, 0x6d800000, No_VFP,
242 "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
243 {0xffc00000, 0xad800000, No_VFP,
245 "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
246
247 {0xffc00000, 0x28800000, No_VFP,
249 "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
250 {0xffc00000, 0xa8800000, No_VFP,
252 "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
253 {0xffc00000, 0x2c800000, No_VFP,
255 "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
256 {0xffc00000, 0x6c800000, No_VFP,
258 "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
259 {0xffc00000, 0xac800000, No_VFP,
261 "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
262
263 {0xffc00000, 0x29400000, No_VFP,
265 "LDP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},
266 {0xffc00000, 0xa9400000, No_VFP,
268 "LDP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},
269 {0xffc00000, 0x2d400000, No_VFP,
271 "LDP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},
272 {0xffc00000, 0x6d400000, No_VFP,
274 "LDP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},
275 {0xffc00000, 0xad400000, No_VFP,
277 "LDP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},
278
279 {0xffc00000, 0x29c00000, No_VFP,
281 "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
282 {0xffc00000, 0xa9c00000, No_VFP,
284 "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
285 {0xffc00000, 0x2dc00000, No_VFP,
287 "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
288 {0xffc00000, 0x6dc00000, No_VFP,
290 "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
291 {0xffc00000, 0xadc00000, No_VFP,
293 "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
294
295 {0xffc00000, 0x28c00000, No_VFP,
297 "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
298 {0xffc00000, 0xa8c00000, No_VFP,
300 "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
301 {0xffc00000, 0x2cc00000, No_VFP,
303 "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
304 {0xffc00000, 0x6cc00000, No_VFP,
306 "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
307 {0xffc00000, 0xacc00000, No_VFP,
309 "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
310
311 {0xffe00c00, 0xb8000400, No_VFP,
313 "STR <Wt>, [<Xn|SP>], #<simm>"},
314 {0xffe00c00, 0xf8000400, No_VFP,
316 "STR <Xt>, [<Xn|SP>], #<simm>"},
317 {0xffe00c00, 0xb8000c00, No_VFP,
319 "STR <Wt>, [<Xn|SP>, #<simm>]!"},
320 {0xffe00c00, 0xf8000c00, No_VFP,
322 "STR <Xt>, [<Xn|SP>, #<simm>]!"},
323 {0xffc00000, 0xb9000000, No_VFP,
325 "STR <Wt>, [<Xn|SP>{, #<pimm>}]"},
326 {0xffc00000, 0xf9000000, No_VFP,
328 "STR <Xt>, [<Xn|SP>{, #<pimm>}]"},
329
330 {0xffe00c00, 0xb8400400, No_VFP,
332 "LDR <Wt>, [<Xn|SP>], #<simm>"},
333 {0xffe00c00, 0xf8400400, No_VFP,
335 "LDR <Xt>, [<Xn|SP>], #<simm>"},
336 {0xffe00c00, 0xb8400c00, No_VFP,
338 "LDR <Wt>, [<Xn|SP>, #<simm>]!"},
339 {0xffe00c00, 0xf8400c00, No_VFP,
341 "LDR <Xt>, [<Xn|SP>, #<simm>]!"},
342 {0xffc00000, 0xb9400000, No_VFP,
344 "LDR <Wt>, [<Xn|SP>{, #<pimm>}]"},
345 {0xffc00000, 0xf9400000, No_VFP,
347 "LDR <Xt>, [<Xn|SP>{, #<pimm>}]"},
348
349 {0x3f200c00, 0x3c000400, No_VFP,
351 "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>], #<simm>"},
352 {0x3f200c00, 0x3c000c00, No_VFP,
354 "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>, #<simm>]!"},
355 {0x3f000000, 0x3d000000, No_VFP,
357 "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>{, #<pimm>}]"},
358
359 // A register-to-register MOV is an alias of ORR <Rd>, ZR, <Rm>, so these
360 // pin Rn to ZR, the shift type to LSL and the shift amount to 0, leaving
361 // only Rm and Rd free. The wider ORR family is deliberately not decoded.
362 {0xffe0ffe0, 0x2a0003e0, No_VFP,
364 {0xffe0ffe0, 0xaa0003e0, No_VFP,
366
367 {0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateBOrBl,
368 "B <label>"},
369 {0xfc000000, 0x94000000, No_VFP, &EmulateInstructionARM64::EmulateBOrBl,
370 "BL <label>"},
371 {0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond,
372 "B.<cond> <label>"},
373 {0x7f000000, 0x34000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,
374 "CBZ <Wt>, <label>"},
375 {0x7f000000, 0x35000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,
376 "CBNZ <Wt>, <label>"},
377 {0x7f000000, 0x36000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,
378 "TBZ <R><t>, #<imm>, <label>"},
379 {0x7f000000, 0x37000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,
380 "TBNZ <R><t>, #<imm>, <label>"},
381
382 };
383 static const size_t k_num_arm_opcodes = std::size(g_opcodes);
384
385 for (size_t i = 0; i < k_num_arm_opcodes; ++i) {
386 if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
387 return &g_opcodes[i];
388 }
389 return nullptr;
390}
391
393 bool success = false;
395 LLDB_INVALID_ADDRESS, &success);
396 if (success) {
397 Context read_inst_context;
398 read_inst_context.type = eContextReadOpcode;
399 read_inst_context.SetNoArgs();
400 m_opcode.SetOpcode32(
401 ReadMemoryUnsigned(read_inst_context, m_addr, 4, 0, &success),
402 GetByteOrder());
403 }
404 if (!success)
406 return success;
407}
408
409bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) {
410 const uint32_t opcode = m_opcode.GetOpcode32();
411 Opcode *opcode_data = GetOpcodeForInstruction(opcode);
412 if (opcode_data == nullptr)
413 return false;
414
415 const bool auto_advance_pc =
416 evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
418 evaluate_options & eEmulateInstructionOptionIgnoreConditions;
419
420 bool success = false;
421
422 // Only return false if we are unable to read the CPSR if we care about
423 // conditions
424 if (!success && !m_ignore_conditions)
425 return false;
426
427 uint64_t orig_pc_value = 0;
428 if (auto_advance_pc) {
429 orig_pc_value =
431 if (!success)
432 return false;
433 }
434
435 // Call the Emulate... function.
436 success = (this->*opcode_data->callback)(opcode);
437 if (!success)
438 return false;
439
440 if (auto_advance_pc) {
441 uint64_t new_pc_value =
443 if (!success)
444 return false;
445
446 if (new_pc_value == orig_pc_value) {
448 context.type = eContextAdvancePC;
449 context.SetNoArgs();
451 orig_pc_value + 4))
452 return false;
453 }
454 }
455 return true;
456}
457
459 UnwindPlan &unwind_plan) {
460 unwind_plan.Clear();
462
463 UnwindPlan::Row row;
464
465 // Our previous Call Frame Address is the stack pointer
467 row.SetRegisterLocationToSame(gpr_lr_arm64, /*must_replace=*/false);
468 row.SetRegisterLocationToSame(gpr_fp_arm64, /*must_replace=*/false);
469
470 unwind_plan.AppendRow(std::move(row));
471 unwind_plan.SetSourceName("EmulateInstructionARM64");
476 return true;
477}
478
480 if (m_arch.GetTriple().isAndroid())
481 return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
482
483 return gpr_fp_arm64;
484}
485
487 bool aarch32 = m_opcode_pstate.RW == 1;
488 // if !HaveAnyAArch32() then assert !aarch32;
489 // if HighestELUsingAArch32() then assert aarch32;
490 return aarch32;
491}
492
493bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N,
494 addr_t target) {
495#if 0
496 // Set program counter to a new address, with a branch reason hint for
497 // possible use by hardware fetching the next instruction.
498 BranchTo(bits(N) target, BranchType branch_type)
499 Hint_Branch(branch_type);
500 if N == 32 then
501 assert UsingAArch32();
502 _PC = ZeroExtend(target);
503 else
504 assert N == 64 && !UsingAArch32();
505 // Remove the tag bits from a tagged target
506 case PSTATE.EL of
507 when EL0, EL1
508 if target<55> == '1' && TCR_EL1.TBI1 == '1' then
509 target<63:56> = '11111111';
510 if target<55> == '0' && TCR_EL1.TBI0 == '1' then
511 target<63:56> = '00000000';
512 when EL2
513 if TCR_EL2.TBI == '1' then
514 target<63:56> = '00000000';
515 when EL3
516 if TCR_EL3.TBI == '1' then
517 target<63:56> = '00000000';
518 _PC = target<63:0>;
519 return;
520#endif
521
522 addr_t addr;
523
524 // Hint_Branch(branch_type);
525 if (N == 32) {
526 if (!UsingAArch32())
527 return false;
528 addr = target;
529 } else if (N == 64) {
530 if (UsingAArch32())
531 return false;
532 // TODO: Remove the tag bits from a tagged target
533 addr = target;
534 } else
535 return false;
536
539}
540
542 // If we are ignoring conditions, then always return true. this allows us to
543 // iterate over disassembly code and still emulate an instruction even if we
544 // don't have all the right bits set in the CPSR register...
546 return true;
547
548 bool result = false;
549 switch (UnsignedBits(cond, 3, 1)) {
550 case 0:
551 result = (m_opcode_pstate.Z == 1);
552 break;
553 case 1:
554 result = (m_opcode_pstate.C == 1);
555 break;
556 case 2:
557 result = (m_opcode_pstate.N == 1);
558 break;
559 case 3:
560 result = (m_opcode_pstate.V == 1);
561 break;
562 case 4:
563 result = (m_opcode_pstate.C == 1 && m_opcode_pstate.Z == 0);
564 break;
565 case 5:
566 result = (m_opcode_pstate.N == m_opcode_pstate.V);
567 break;
568 case 6:
569 result = (m_opcode_pstate.N == m_opcode_pstate.V && m_opcode_pstate.Z == 0);
570 break;
571 case 7:
572 // Always execute (cond == 0b1110, or the special 0b1111 which gives
573 // opcodes different meanings, but always means execution happens.
574 return true;
575 }
576
577 if (cond & 1)
578 result = !result;
579 return result;
580}
581
583AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in,
585 uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
586 std::optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y));
587 bool overflow = !signed_sum;
588 if (!overflow)
589 overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in));
590 uint64_t result = unsigned_sum;
591 if (N < 64)
592 result = Bits64(result, N - 1, 0);
593 proc_state.N = Bit64(result, N - 1);
594 proc_state.Z = IsZero(result);
595 proc_state.C = UInt(result) != unsigned_sum;
596 proc_state.V = overflow;
597 return result;
598}
599
600bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) {
601 // integer d = UInt(Rd);
602 // integer n = UInt(Rn);
603 // integer datasize = if sf == 1 then 64 else 32;
604 // boolean sub_op = (op == 1);
605 // boolean setflags = (S == 1);
606 // bits(datasize) imm;
607 //
608 // case shift of
609 // when '00' imm = ZeroExtend(imm12, datasize);
610 // when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize);
611 // when '1x' UNDEFINED;
612 //
613 //
614 // bits(datasize) result;
615 // bits(datasize) operand1 = if n == 31 then SP[] else X[n];
616 // bits(datasize) operand2 = imm;
617 // bits(4) nzcv;
618 // bit carry_in;
619 //
620 // if sub_op then
621 // operand2 = NOT(operand2);
622 // carry_in = 1;
623 // else
624 // carry_in = 0;
625 //
626 // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in);
627 //
628 // if setflags then
629 // PSTATE.NZCV = nzcv;
630 //
631 // if d == 31 && !setflags then
632 // SP[] = result;
633 // else
634 // X[d] = result;
635
636 const uint32_t sf = Bit32(opcode, 31);
637 const uint32_t op = Bit32(opcode, 30);
638 const uint32_t S = Bit32(opcode, 29);
639 const uint32_t shift = Bits32(opcode, 23, 22);
640 const uint32_t imm12 = Bits32(opcode, 21, 10);
641 const uint32_t Rn = Bits32(opcode, 9, 5);
642 const uint32_t Rd = Bits32(opcode, 4, 0);
643
644 bool success = false;
645
646 const uint32_t d = UInt(Rd);
647 const uint32_t n = UInt(Rn);
648 const uint32_t datasize = (sf == 1) ? 64 : 32;
649 boolean sub_op = op == 1;
650 boolean setflags = S == 1;
651 uint64_t imm;
652
653 switch (shift) {
654 case 0:
655 imm = imm12;
656 break;
657 case 1:
658 imm = static_cast<uint64_t>(imm12) << 12;
659 break;
660 default:
661 return false; // UNDEFINED;
662 }
663 uint64_t result;
664 uint64_t operand1 =
666 uint64_t operand2 = imm;
667 bit carry_in;
668
669 if (sub_op) {
670 operand2 = NOT(operand2);
671 carry_in = true;
672 imm = -imm; // For the Register plug offset context below
673 } else {
674 carry_in = false;
675 }
676
677 ProcState proc_state;
678
679 result = AddWithCarry(datasize, operand1, operand2, carry_in, proc_state);
680
681 if (setflags) {
682 m_emulated_pstate.N = proc_state.N;
683 m_emulated_pstate.Z = proc_state.Z;
684 m_emulated_pstate.C = proc_state.C;
685 m_emulated_pstate.V = proc_state.V;
686 }
687
688 Context context;
689 std::optional<RegisterInfo> reg_info_Rn =
691 if (reg_info_Rn)
692 context.SetRegisterPlusOffset(*reg_info_Rn, imm);
693
694 if (n == GetFramePointerRegisterNumber() && d == gpr_sp_arm64 && !setflags) {
695 // 'mov sp, fp' - common epilogue instruction, CFA is now in terms of the
696 // stack pointer, instead of frame pointer.
698 } else if ((n == gpr_sp_arm64 || n == GetFramePointerRegisterNumber()) &&
699 d == gpr_sp_arm64 && !setflags) {
701 } else if (d == GetFramePointerRegisterNumber() && n == gpr_sp_arm64 &&
702 !setflags) {
704 } else {
706 }
707
708 // If setflags && d == gpr_sp_arm64 then d = WZR/XZR. See CMN, CMP
709 if (!setflags || d != gpr_sp_arm64)
711
712 return false;
713}
714
715template <EmulateInstructionARM64::AddrMode a_mode>
716bool EmulateInstructionARM64::EmulateLDPSTP(const uint32_t opcode) {
717 uint32_t opc = Bits32(opcode, 31, 30);
718 uint32_t V = Bit32(opcode, 26);
719 uint32_t L = Bit32(opcode, 22);
720 uint32_t imm7 = Bits32(opcode, 21, 15);
721 uint32_t Rt2 = Bits32(opcode, 14, 10);
722 uint32_t Rn = Bits32(opcode, 9, 5);
723 uint32_t Rt = Bits32(opcode, 4, 0);
724
725 integer n = UInt(Rn);
726 integer t = UInt(Rt);
727 integer t2 = UInt(Rt2);
728 uint64_t idx;
729
730 MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE;
731 boolean vector = (V == 1);
732 // AccType acctype = AccType_NORMAL;
733 boolean is_signed = false;
734 boolean wback = a_mode != AddrMode_OFF;
735 boolean wb_unknown = false;
736 boolean rt_unknown = false;
737 integer scale;
738 integer size;
739
740 if (opc == 3)
741 return false; // UNDEFINED
742
743 if (vector) {
744 scale = 2 + UInt(opc);
745 } else {
746 scale = (opc & 2) ? 3 : 2;
747 is_signed = (opc & 1) != 0;
748 if (is_signed && memop == MemOp_STORE)
749 return false; // UNDEFINED
750 }
751
752 if (!vector && wback && ((t == n) || (t2 == n))) {
755 wb_unknown = true; // writeback is UNKNOWN
756 break;
757
759 wback = false; // writeback is suppressed
760 break;
761
762 case Constraint_NOP:
763 memop = MemOp_NOP; // do nothing
764 wback = false;
765 break;
766
767 case Constraint_NONE:
768 break;
769 }
770 }
771
772 if (memop == MemOp_LOAD && t == t2) {
775 rt_unknown = true; // result is UNKNOWN
776 break;
777
778 case Constraint_NOP:
779 memop = MemOp_NOP; // do nothing
780 wback = false;
781 break;
782
783 default:
784 break;
785 }
786 }
787
788 idx = LSL(llvm::SignExtend64<7>(imm7), scale);
789 size = (integer)1 << scale;
790 uint64_t datasize = size * 8;
791 uint64_t address;
792 uint64_t wb_address;
793
794 std::optional<RegisterInfo> reg_info_base =
796 if (!reg_info_base)
797 return false;
798
799 std::optional<RegisterInfo> reg_info_Rt;
800 std::optional<RegisterInfo> reg_info_Rt2;
801
802 if (vector) {
804 reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t2);
805 } else {
807 reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t2);
808 }
809
810 if (!reg_info_Rt || !reg_info_Rt2)
811 return false;
812
813 bool success = false;
814 if (n == 31) {
815 // CheckSPAlignment();
816 address =
818 } else
819 address =
821
822 wb_address = address + idx;
823 if (a_mode != AddrMode_POST)
824 address = wb_address;
825
826 Context context_t;
827 Context context_t2;
828
831
832 switch (memop) {
833 case MemOp_STORE: {
834 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
835 // based off of the sp
836 // or fp register
837 {
840 } else {
841 context_t.type = eContextRegisterStore;
842 context_t2.type = eContextRegisterStore;
843 }
844 context_t.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base, 0);
845 context_t2.SetRegisterToRegisterPlusOffset(*reg_info_Rt2, *reg_info_base,
846 size);
847
848 std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt);
849 if (!data_Rt)
850 return false;
851
852 buffer.resize(reg_info_Rt->byte_size);
853 if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer.data(),
854 reg_info_Rt->byte_size, eByteOrderLittle,
855 error) == 0)
856 return false;
857
858 if (!WriteMemory(context_t, address + 0, buffer.data(),
859 reg_info_Rt->byte_size))
860 return false;
861
862 std::optional<RegisterValue> data_Rt2 = ReadRegister(*reg_info_Rt2);
863 if (!data_Rt2)
864 return false;
865
866 buffer.resize(reg_info_Rt2->byte_size);
867 if (data_Rt2->GetAsMemoryData(*reg_info_Rt2, buffer.data(),
868 reg_info_Rt2->byte_size, eByteOrderLittle,
869 error) == 0)
870 return false;
871
872 if (!WriteMemory(context_t2, address + size, buffer.data(),
873 reg_info_Rt2->byte_size))
874 return false;
875 } break;
876
877 case MemOp_LOAD: {
878 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this load is
879 // based off of the sp
880 // or fp register
881 {
884 } else {
885 context_t.type = eContextRegisterLoad;
886 context_t2.type = eContextRegisterLoad;
887 }
888 context_t.SetAddress(address);
889 context_t2.SetAddress(address + size);
890
891 buffer.resize(reg_info_Rt->byte_size);
892 if (rt_unknown)
893 std::fill(buffer.begin(), buffer.end(), 'U');
894 else {
895 if (!ReadMemory(context_t, address, buffer.data(),
896 reg_info_Rt->byte_size))
897 return false;
898 }
899
900 RegisterValue data_Rt;
901 if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer.data(),
902 reg_info_Rt->byte_size, eByteOrderLittle,
903 error) == 0)
904 return false;
905
906 if (!vector && is_signed && !data_Rt.SignExtend(datasize))
907 return false;
908
909 if (!WriteRegister(context_t, *reg_info_Rt, data_Rt))
910 return false;
911
912 buffer.resize(reg_info_Rt2->byte_size);
913 if (!rt_unknown)
914 if (!ReadMemory(context_t2, address + size, buffer.data(),
915 reg_info_Rt2->byte_size))
916 return false;
917
918 RegisterValue data_Rt2;
919 if (data_Rt2.SetFromMemoryData(*reg_info_Rt2, buffer.data(),
920 reg_info_Rt2->byte_size, eByteOrderLittle,
921 error) == 0)
922 return false;
923
924 if (!vector && is_signed && !data_Rt2.SignExtend(datasize))
925 return false;
926
927 if (!WriteRegister(context_t2, *reg_info_Rt2, data_Rt2))
928 return false;
929 } break;
930
931 default:
932 break;
933 }
934
935 if (wback) {
936 if (wb_unknown)
937 wb_address = LLDB_INVALID_ADDRESS;
938 Context context;
939 context.SetImmediateSigned(idx);
940 if (n == 31)
942 else
944 WriteRegisterUnsigned(context, *reg_info_base, wb_address);
945 }
946 return true;
947}
948
949template <EmulateInstructionARM64::AddrMode a_mode>
950bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
951 uint32_t size = Bits32(opcode, 31, 30);
952 uint32_t opc = Bits32(opcode, 23, 22);
953 uint32_t vr = Bit32(opcode, 26);
954 uint32_t n = Bits32(opcode, 9, 5);
955 uint32_t t = Bits32(opcode, 4, 0);
956
957 MemOp memop;
958 if (vr) {
959 // opc<1> == 1 && size != 0 is an undefined encoding.
960 if (Bit32(opc, 1) == 1 && size != 0)
961 return false;
962 // opc<1> == 1 && size == 0 encode the 128-bit variant.
963 if (Bit32(opc, 1) == 1)
964 size = 4;
965 memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
966 } else {
967 if (Bit32(opc, 1) == 0) {
968 memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
969 } else {
970 memop = MemOp_LOAD;
971 if (size == 2 && Bit32(opc, 0) == 1)
972 return false;
973 }
974 }
975
976 bool wback;
977 bool postindex;
978 uint64_t offset;
979
980 switch (a_mode) {
981 case AddrMode_POST:
982 wback = true;
983 postindex = true;
984 offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));
985 break;
986 case AddrMode_PRE:
987 wback = true;
988 postindex = false;
989 offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));
990 break;
991 case AddrMode_OFF:
992 wback = false;
993 postindex = false;
994 offset = LSL(Bits32(opcode, 21, 10), size);
995 break;
996 }
997
999 bool success = false;
1000 uint64_t address;
1002
1003 if (n == 31)
1004 address =
1006 else
1007 address =
1009
1010 if (!success)
1011 return false;
1012
1013 if (!postindex)
1014 address += offset;
1015
1016 std::optional<RegisterInfo> reg_info_base =
1018 if (!reg_info_base)
1019 return false;
1020
1021 std::optional<RegisterInfo> reg_info_Rt =
1024 if (!reg_info_Rt)
1025 return false;
1026
1027 Context context;
1028 switch (memop) {
1029 case MemOp_STORE: {
1030 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
1031 // based off of the sp
1032 // or fp register
1034 else
1035 context.type = eContextRegisterStore;
1036 context.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base,
1037 postindex ? 0 : offset);
1038
1039 std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt);
1040 if (!data_Rt)
1041 return false;
1042
1043 buffer.resize(reg_info_Rt->byte_size);
1044 if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer.data(),
1045 reg_info_Rt->byte_size, eByteOrderLittle,
1046 error) == 0)
1047 return false;
1048
1049 if (!WriteMemory(context, address, buffer.data(), reg_info_Rt->byte_size))
1050 return false;
1051 } break;
1052
1053 case MemOp_LOAD: {
1054 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
1055 // based off of the sp
1056 // or fp register
1058 else
1059 context.type = eContextRegisterLoad;
1060 context.SetAddress(address);
1061
1062 buffer.resize(reg_info_Rt->byte_size);
1063 if (!ReadMemory(context, address, buffer.data(), reg_info_Rt->byte_size))
1064 return false;
1065
1066 RegisterValue data_Rt;
1067 if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer.data(),
1068 reg_info_Rt->byte_size, eByteOrderLittle,
1069 error) == 0)
1070 return false;
1071
1072 if (!WriteRegister(context, *reg_info_Rt, data_Rt))
1073 return false;
1074 } break;
1075 default:
1076 return false;
1077 }
1078
1079 if (wback) {
1080 if (postindex)
1081 address += offset;
1082
1083 if (n == 31)
1085 else
1087 context.SetImmediateSigned(offset);
1088
1089 if (!WriteRegisterUnsigned(context, *reg_info_base, address))
1090 return false;
1091 }
1092 return true;
1093}
1094
1095bool EmulateInstructionARM64::EmulateBOrBl(const uint32_t opcode) {
1096#if 0
1097 // ARM64 pseudo code...
1098 if branch_type == BranchType_CALL then X[30] = PC[] + 4;
1099 BranchTo(PC[] + offset, branch_type);
1100#endif
1101
1102 bool success = false;
1103
1107 LLDB_REGNUM_GENERIC_PC, 0, &success);
1108 if (!success)
1109 return false;
1110
1111 int64_t offset = llvm::SignExtend64<28>(Bits32(opcode, 25, 0) << 2);
1112 BranchType branch_type = Bit32(opcode, 31) ? BranchType_CALL : BranchType_JMP;
1113 addr_t target = pc + offset;
1114 context.SetImmediateSigned(offset);
1115
1116 switch (branch_type) {
1117 case BranchType_CALL: {
1118 addr_t x30 = pc + 4;
1120 return false;
1121 } break;
1122 case BranchType_JMP:
1123 break;
1124 default:
1125 return false;
1126 }
1127
1128 return BranchTo(context, 64, target);
1129}
1130
1131bool EmulateInstructionARM64::EmulateBcond(const uint32_t opcode) {
1132#if 0
1133 // ARM64 pseudo code...
1134 bits(64) offset = SignExtend(imm19:'00', 64);
1135 bits(4) condition = cond;
1136 if ConditionHolds(condition) then
1137 BranchTo(PC[] + offset, BranchType_JMP);
1138#endif
1139
1140 if (ConditionHolds(Bits32(opcode, 3, 0))) {
1141 bool success = false;
1142
1143 const uint64_t pc = ReadRegisterUnsigned(
1145 if (!success)
1146 return false;
1147
1148 int64_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
1149 addr_t target = pc + offset;
1150
1153 context.SetImmediateSigned(offset);
1154 if (!BranchTo(context, 64, target))
1155 return false;
1156 }
1157 return true;
1158}
1159
1160bool EmulateInstructionARM64::EmulateCBZ(const uint32_t opcode) {
1161#if 0
1162 integer t = UInt(Rt);
1163 integer datasize = if sf == '1' then 64 else 32;
1164 boolean iszero = (op == '0');
1165 bits(64) offset = SignExtend(imm19:'00', 64);
1166
1167 bits(datasize) operand1 = X[t];
1168 if IsZero(operand1) == iszero then
1169 BranchTo(PC[] + offset, BranchType_JMP);
1170#endif
1171
1172 bool success = false;
1173
1174 uint32_t t = Bits32(opcode, 4, 0);
1175 bool is_zero = Bit32(opcode, 24) == 0;
1176 int32_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
1177
1178 const uint64_t operand =
1180 if (!success)
1181 return false;
1182
1183 if (m_ignore_conditions || ((operand == 0) == is_zero)) {
1184 const uint64_t pc = ReadRegisterUnsigned(
1186 if (!success)
1187 return false;
1188
1191 context.SetImmediateSigned(offset);
1192 if (!BranchTo(context, 64, pc + offset))
1193 return false;
1194 }
1195 return true;
1196}
1197
1198bool EmulateInstructionARM64::EmulateTBZ(const uint32_t opcode) {
1199#if 0
1200 integer t = UInt(Rt);
1201 integer datasize = if b5 == '1' then 64 else 32;
1202 integer bit_pos = UInt(b5:b40);
1203 bit bit_val = op;
1204 bits(64) offset = SignExtend(imm14:'00', 64);
1205#endif
1206
1207 bool success = false;
1208
1209 uint32_t t = Bits32(opcode, 4, 0);
1210 uint32_t bit_pos = (Bit32(opcode, 31) << 6) | (Bits32(opcode, 23, 19));
1211 uint32_t bit_val = Bit32(opcode, 24);
1212 int64_t offset = llvm::SignExtend64<16>(Bits32(opcode, 18, 5) << 2);
1213
1214 const uint64_t operand =
1216 if (!success)
1217 return false;
1218
1219 if (m_ignore_conditions || Bit32(operand, bit_pos) == bit_val) {
1220 const uint64_t pc = ReadRegisterUnsigned(
1222 if (!success)
1223 return false;
1224
1227 context.SetImmediateSigned(offset);
1228 if (!BranchTo(context, 64, pc + offset))
1229 return false;
1230 }
1231 return true;
1232}
1233
1235#if 0
1236 integer d = UInt(Rd);
1237 integer m = UInt(Rm);
1238 integer datasize = if sf == '1' then 64 else 32;
1239 bits(datasize) result = X[m];
1240 X[d] = ZeroExtend(result, 64);
1241#endif
1242 uint32_t d = Bits32(opcode, 4, 0);
1243 uint32_t m = Bits32(opcode, 20, 16);
1244 bool sf = BitIsSet(opcode, 31);
1245
1246 // Register 31 is xzr, writes to it are discarded.
1247 if (d == 31)
1248 return true;
1249
1250 uint64_t source_value;
1252 // xzr always reads as 0.
1253 if (m == 31) {
1254 source_value = 0;
1256 context.SetNoArgs();
1257 } else {
1258 std::optional<RegisterInfo> source_reg =
1260 if (!source_reg)
1261 return false;
1262 bool success;
1263 source_value = ReadRegisterUnsigned(*source_reg, 0, &success);
1264 if (!success)
1265 return false;
1266
1268 context.SetRegisterPlusOffset(*source_reg, 0);
1269 }
1270
1271 std::optional<RegisterInfo> dest_reg = GetRegisterInfo(eRegisterKindLLDB, d);
1272 if (!dest_reg)
1273 return false;
1274
1275 // If sf is not set, clear the top 32 bits.
1276 if (!sf)
1277 source_value &= 0xFFFFFFFF;
1278
1279 return WriteRegisterUnsigned(context, *dest_reg, source_value);
1280}
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)
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 EmulateBOrBl(const uint32_t opcode)
bool EmulateLDPSTP(const uint32_t opcode)
bool EmulateMOVRegister(const uint32_t opcode)
bool EmulateTBZ(const uint32_t opcode)
bool EmulateBcond(const uint32_t opcode)
static Opcode * GetOpcodeForInstruction(const uint32_t opcode)
EmulateInstructionARM64(const lldb_private::ArchSpec &arch)
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)
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:32
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:547
"lldb/Core/EmulateInstruction.h" A class that allows emulation of CPU opcodes.
lldb::ByteOrder GetByteOrder() const
bool 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)
llvm::SmallVector< uint8_t, kTypicalRegisterByteSize > BytesContainer
An error handling class.
Definition Status.h:118
void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset)
Definition UnwindPlan.h:240
bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace)
const FAValue & GetCFAValue() const
Definition UnwindPlan.h:365
void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)
Definition UnwindPlan.h:525
void SetRegisterKind(lldb::RegisterKind kind)
Definition UnwindPlan.h:462
void SetReturnAddressRegister(uint32_t regnum)
Definition UnwindPlan.h:464
void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)
Definition UnwindPlan.h:501
void SetSourceName(const char *)
void SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)
Definition UnwindPlan.h:513
#define LLDB_REGNUM_GENERIC_RA
#define LLDB_REGNUM_GENERIC_SP
#define LLDB_REGNUM_GENERIC_FLAGS
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_REGNUM
#define LLDB_REGNUM_GENERIC_PC
#define LLDB_REGNUM_GENERIC_FP
A class that represents a running process on the host machine.
static uint64_t Bits64(const uint64_t bits, const uint32_t msbit, const uint32_t lsbit)
InstructionType
Instruction types.
static bool BitIsSet(const uint64_t value, const uint64_t bit)
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)
uint64_t addr_t
Definition lldb-types.h:80
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)
Every register is described in detail including its name, alternate name (optional),...