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
114}
115
118}
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,
216 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
217 "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},
218 {0xffc00000, 0xa9000000, No_VFP,
219 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
220 "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},
221 {0xffc00000, 0x2d000000, No_VFP,
222 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
223 "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},
224 {0xffc00000, 0x6d000000, No_VFP,
225 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
226 "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},
227 {0xffc00000, 0xad000000, No_VFP,
228 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
229 "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},
230
231 {0xffc00000, 0x29800000, No_VFP,
232 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
233 "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
234 {0xffc00000, 0xa9800000, No_VFP,
235 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
236 "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
237 {0xffc00000, 0x2d800000, No_VFP,
238 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
239 "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
240 {0xffc00000, 0x6d800000, No_VFP,
241 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
242 "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
243 {0xffc00000, 0xad800000, No_VFP,
244 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
245 "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
246
247 {0xffc00000, 0x28800000, No_VFP,
248 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
249 "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
250 {0xffc00000, 0xa8800000, No_VFP,
251 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
252 "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
253 {0xffc00000, 0x2c800000, No_VFP,
254 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
255 "STP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
256 {0xffc00000, 0x6c800000, No_VFP,
257 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
258 "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
259 {0xffc00000, 0xac800000, No_VFP,
260 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
261 "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
262
263 {0xffc00000, 0x29400000, No_VFP,
264 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
265 "LDP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]"},
266 {0xffc00000, 0xa9400000, No_VFP,
267 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
268 "LDP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]"},
269 {0xffc00000, 0x2d400000, No_VFP,
270 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
271 "LDP <St>, <St2>, [<Xn|SP>{, #<imm>}]"},
272 {0xffc00000, 0x6d400000, No_VFP,
273 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
274 "LDP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]"},
275 {0xffc00000, 0xad400000, No_VFP,
276 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_OFF>,
277 "LDP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]"},
278
279 {0xffc00000, 0x29c00000, No_VFP,
280 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
281 "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
282 {0xffc00000, 0xa9c00000, No_VFP,
283 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
284 "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
285 {0xffc00000, 0x2dc00000, No_VFP,
286 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
287 "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
288 {0xffc00000, 0x6dc00000, No_VFP,
289 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
290 "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
291 {0xffc00000, 0xadc00000, No_VFP,
292 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_PRE>,
293 "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
294
295 {0xffc00000, 0x28c00000, No_VFP,
296 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
297 "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!"},
298 {0xffc00000, 0xa8c00000, No_VFP,
299 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
300 "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!"},
301 {0xffc00000, 0x2cc00000, No_VFP,
302 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
303 "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!"},
304 {0xffc00000, 0x6cc00000, No_VFP,
305 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
306 "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!"},
307 {0xffc00000, 0xacc00000, No_VFP,
308 &EmulateInstructionARM64::EmulateLDPSTP<AddrMode_POST>,
309 "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!"},
310
311 {0xffe00c00, 0xb8000400, No_VFP,
312 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
313 "STR <Wt>, [<Xn|SP>], #<simm>"},
314 {0xffe00c00, 0xf8000400, No_VFP,
315 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
316 "STR <Xt>, [<Xn|SP>], #<simm>"},
317 {0xffe00c00, 0xb8000c00, No_VFP,
318 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
319 "STR <Wt>, [<Xn|SP>, #<simm>]!"},
320 {0xffe00c00, 0xf8000c00, No_VFP,
321 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
322 "STR <Xt>, [<Xn|SP>, #<simm>]!"},
323 {0xffc00000, 0xb9000000, No_VFP,
324 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
325 "STR <Wt>, [<Xn|SP>{, #<pimm>}]"},
326 {0xffc00000, 0xf9000000, No_VFP,
327 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
328 "STR <Xt>, [<Xn|SP>{, #<pimm>}]"},
329
330 {0xffe00c00, 0xb8400400, No_VFP,
331 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
332 "LDR <Wt>, [<Xn|SP>], #<simm>"},
333 {0xffe00c00, 0xf8400400, No_VFP,
334 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
335 "LDR <Xt>, [<Xn|SP>], #<simm>"},
336 {0xffe00c00, 0xb8400c00, No_VFP,
337 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
338 "LDR <Wt>, [<Xn|SP>, #<simm>]!"},
339 {0xffe00c00, 0xf8400c00, No_VFP,
340 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
341 "LDR <Xt>, [<Xn|SP>, #<simm>]!"},
342 {0xffc00000, 0xb9400000, No_VFP,
343 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
344 "LDR <Wt>, [<Xn|SP>{, #<pimm>}]"},
345 {0xffc00000, 0xf9400000, No_VFP,
346 &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
347 "LDR <Xt>, [<Xn|SP>{, #<pimm>}]"},
348
349 {0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB,
350 "B <label>"},
351 {0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond,
352 "B.<cond> <label>"},
353 {0x7f000000, 0x34000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,
354 "CBZ <Wt>, <label>"},
355 {0x7f000000, 0x35000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ,
356 "CBNZ <Wt>, <label>"},
357 {0x7f000000, 0x36000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,
358 "TBZ <R><t>, #<imm>, <label>"},
359 {0x7f000000, 0x37000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ,
360 "TBNZ <R><t>, #<imm>, <label>"},
361
362 };
363 static const size_t k_num_arm_opcodes = std::size(g_opcodes);
364
365 for (size_t i = 0; i < k_num_arm_opcodes; ++i) {
366 if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
367 return &g_opcodes[i];
368 }
369 return nullptr;
370}
371
373 bool success = false;
375 LLDB_INVALID_ADDRESS, &success);
376 if (success) {
377 Context read_inst_context;
378 read_inst_context.type = eContextReadOpcode;
379 read_inst_context.SetNoArgs();
380 m_opcode.SetOpcode32(
381 ReadMemoryUnsigned(read_inst_context, m_addr, 4, 0, &success),
382 GetByteOrder());
383 }
384 if (!success)
386 return success;
387}
388
389bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) {
390 const uint32_t opcode = m_opcode.GetOpcode32();
391 Opcode *opcode_data = GetOpcodeForInstruction(opcode);
392 if (opcode_data == nullptr)
393 return false;
394
395 const bool auto_advance_pc =
396 evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
398 evaluate_options & eEmulateInstructionOptionIgnoreConditions;
399
400 bool success = false;
401
402 // Only return false if we are unable to read the CPSR if we care about
403 // conditions
404 if (!success && !m_ignore_conditions)
405 return false;
406
407 uint32_t orig_pc_value = 0;
408 if (auto_advance_pc) {
409 orig_pc_value =
411 if (!success)
412 return false;
413 }
414
415 // Call the Emulate... function.
416 success = (this->*opcode_data->callback)(opcode);
417 if (!success)
418 return false;
419
420 if (auto_advance_pc) {
421 uint32_t new_pc_value =
423 if (!success)
424 return false;
425
426 if (new_pc_value == orig_pc_value) {
428 context.type = eContextAdvancePC;
429 context.SetNoArgs();
431 orig_pc_value + 4))
432 return false;
433 }
434 }
435 return true;
436}
437
439 UnwindPlan &unwind_plan) {
440 unwind_plan.Clear();
442
444
445 // Our previous Call Frame Address is the stack pointer
446 row->GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_arm64, 0);
447 row->SetRegisterLocationToSame(gpr_lr_arm64, /*must_replace=*/false);
448 row->SetRegisterLocationToSame(gpr_fp_arm64, /*must_replace=*/false);
449
450 unwind_plan.AppendRow(row);
451 unwind_plan.SetSourceName("EmulateInstructionARM64");
456 return true;
457}
458
460 if (m_arch.GetTriple().isAndroid())
461 return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
462
463 return gpr_fp_arm64;
464}
465
467 bool aarch32 = m_opcode_pstate.RW == 1;
468 // if !HaveAnyAArch32() then assert !aarch32;
469 // if HighestELUsingAArch32() then assert aarch32;
470 return aarch32;
471}
472
473bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N,
474 addr_t target) {
475#if 0
476 // Set program counter to a new address, with a branch reason hint for
477 // possible use by hardware fetching the next instruction.
478 BranchTo(bits(N) target, BranchType branch_type)
479 Hint_Branch(branch_type);
480 if N == 32 then
481 assert UsingAArch32();
482 _PC = ZeroExtend(target);
483 else
484 assert N == 64 && !UsingAArch32();
485 // Remove the tag bits from a tagged target
486 case PSTATE.EL of
487 when EL0, EL1
488 if target<55> == '1' && TCR_EL1.TBI1 == '1' then
489 target<63:56> = '11111111';
490 if target<55> == '0' && TCR_EL1.TBI0 == '1' then
491 target<63:56> = '00000000';
492 when EL2
493 if TCR_EL2.TBI == '1' then
494 target<63:56> = '00000000';
495 when EL3
496 if TCR_EL3.TBI == '1' then
497 target<63:56> = '00000000';
498 _PC = target<63:0>;
499 return;
500#endif
501
502 addr_t addr;
503
504 // Hint_Branch(branch_type);
505 if (N == 32) {
506 if (!UsingAArch32())
507 return false;
508 addr = target;
509 } else if (N == 64) {
510 if (UsingAArch32())
511 return false;
512 // TODO: Remove the tag bits from a tagged target
513 addr = target;
514 } else
515 return false;
516
519}
520
522 // If we are ignoring conditions, then always return true. this allows us to
523 // iterate over disassembly code and still emulate an instruction even if we
524 // don't have all the right bits set in the CPSR register...
526 return true;
527
528 bool result = false;
529 switch (UnsignedBits(cond, 3, 1)) {
530 case 0:
531 result = (m_opcode_pstate.Z == 1);
532 break;
533 case 1:
534 result = (m_opcode_pstate.C == 1);
535 break;
536 case 2:
537 result = (m_opcode_pstate.N == 1);
538 break;
539 case 3:
540 result = (m_opcode_pstate.V == 1);
541 break;
542 case 4:
543 result = (m_opcode_pstate.C == 1 && m_opcode_pstate.Z == 0);
544 break;
545 case 5:
546 result = (m_opcode_pstate.N == m_opcode_pstate.V);
547 break;
548 case 6:
549 result = (m_opcode_pstate.N == m_opcode_pstate.V && m_opcode_pstate.Z == 0);
550 break;
551 case 7:
552 // Always execute (cond == 0b1110, or the special 0b1111 which gives
553 // opcodes different meanings, but always means execution happens.
554 return true;
555 }
556
557 if (cond & 1)
558 result = !result;
559 return result;
560}
561
563AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in,
565 uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
566 std::optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y));
567 bool overflow = !signed_sum;
568 if (!overflow)
569 overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in));
570 uint64_t result = unsigned_sum;
571 if (N < 64)
572 result = Bits64(result, N - 1, 0);
573 proc_state.N = Bit64(result, N - 1);
574 proc_state.Z = IsZero(result);
575 proc_state.C = UInt(result) != unsigned_sum;
576 proc_state.V = overflow;
577 return result;
578}
579
580bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) {
581 // integer d = UInt(Rd);
582 // integer n = UInt(Rn);
583 // integer datasize = if sf == 1 then 64 else 32;
584 // boolean sub_op = (op == 1);
585 // boolean setflags = (S == 1);
586 // bits(datasize) imm;
587 //
588 // case shift of
589 // when '00' imm = ZeroExtend(imm12, datasize);
590 // when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize);
591 // when '1x' UNDEFINED;
592 //
593 //
594 // bits(datasize) result;
595 // bits(datasize) operand1 = if n == 31 then SP[] else X[n];
596 // bits(datasize) operand2 = imm;
597 // bits(4) nzcv;
598 // bit carry_in;
599 //
600 // if sub_op then
601 // operand2 = NOT(operand2);
602 // carry_in = 1;
603 // else
604 // carry_in = 0;
605 //
606 // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in);
607 //
608 // if setflags then
609 // PSTATE.NZCV = nzcv;
610 //
611 // if d == 31 && !setflags then
612 // SP[] = result;
613 // else
614 // X[d] = result;
615
616 const uint32_t sf = Bit32(opcode, 31);
617 const uint32_t op = Bit32(opcode, 30);
618 const uint32_t S = Bit32(opcode, 29);
619 const uint32_t shift = Bits32(opcode, 23, 22);
620 const uint32_t imm12 = Bits32(opcode, 21, 10);
621 const uint32_t Rn = Bits32(opcode, 9, 5);
622 const uint32_t Rd = Bits32(opcode, 4, 0);
623
624 bool success = false;
625
626 const uint32_t d = UInt(Rd);
627 const uint32_t n = UInt(Rn);
628 const uint32_t datasize = (sf == 1) ? 64 : 32;
629 boolean sub_op = op == 1;
630 boolean setflags = S == 1;
631 uint64_t imm;
632
633 switch (shift) {
634 case 0:
635 imm = imm12;
636 break;
637 case 1:
638 imm = static_cast<uint64_t>(imm12) << 12;
639 break;
640 default:
641 return false; // UNDEFINED;
642 }
643 uint64_t result;
644 uint64_t operand1 =
646 uint64_t operand2 = imm;
647 bit carry_in;
648
649 if (sub_op) {
650 operand2 = NOT(operand2);
651 carry_in = true;
652 imm = -imm; // For the Register plug offset context below
653 } else {
654 carry_in = false;
655 }
656
657 ProcState proc_state;
658
659 result = AddWithCarry(datasize, operand1, operand2, carry_in, proc_state);
660
661 if (setflags) {
662 m_emulated_pstate.N = proc_state.N;
663 m_emulated_pstate.Z = proc_state.Z;
664 m_emulated_pstate.C = proc_state.C;
665 m_emulated_pstate.V = proc_state.V;
666 }
667
668 Context context;
669 std::optional<RegisterInfo> reg_info_Rn =
671 if (reg_info_Rn)
672 context.SetRegisterPlusOffset(*reg_info_Rn, imm);
673
674 if (n == GetFramePointerRegisterNumber() && d == gpr_sp_arm64 && !setflags) {
675 // 'mov sp, fp' - common epilogue instruction, CFA is now in terms of the
676 // stack pointer, instead of frame pointer.
678 } else if ((n == gpr_sp_arm64 || n == GetFramePointerRegisterNumber()) &&
679 d == gpr_sp_arm64 && !setflags) {
681 } else if (d == GetFramePointerRegisterNumber() && n == gpr_sp_arm64 &&
682 !setflags) {
684 } else {
686 }
687
688 // If setflags && d == gpr_sp_arm64 then d = WZR/XZR. See CMN, CMP
689 if (!setflags || d != gpr_sp_arm64)
691
692 return false;
693}
694
695template <EmulateInstructionARM64::AddrMode a_mode>
696bool EmulateInstructionARM64::EmulateLDPSTP(const uint32_t opcode) {
697 uint32_t opc = Bits32(opcode, 31, 30);
698 uint32_t V = Bit32(opcode, 26);
699 uint32_t L = Bit32(opcode, 22);
700 uint32_t imm7 = Bits32(opcode, 21, 15);
701 uint32_t Rt2 = Bits32(opcode, 14, 10);
702 uint32_t Rn = Bits32(opcode, 9, 5);
703 uint32_t Rt = Bits32(opcode, 4, 0);
704
705 integer n = UInt(Rn);
706 integer t = UInt(Rt);
707 integer t2 = UInt(Rt2);
708 uint64_t idx;
709
710 MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE;
711 boolean vector = (V == 1);
712 // AccType acctype = AccType_NORMAL;
713 boolean is_signed = false;
714 boolean wback = a_mode != AddrMode_OFF;
715 boolean wb_unknown = false;
716 boolean rt_unknown = false;
717 integer scale;
718 integer size;
719
720 if (opc == 3)
721 return false; // UNDEFINED
722
723 if (vector) {
724 scale = 2 + UInt(opc);
725 } else {
726 scale = (opc & 2) ? 3 : 2;
727 is_signed = (opc & 1) != 0;
728 if (is_signed && memop == MemOp_STORE)
729 return false; // UNDEFINED
730 }
731
732 if (!vector && wback && ((t == n) || (t2 == n))) {
735 wb_unknown = true; // writeback is UNKNOWN
736 break;
737
739 wback = false; // writeback is suppressed
740 break;
741
742 case Constraint_NOP:
743 memop = MemOp_NOP; // do nothing
744 wback = false;
745 break;
746
747 case Constraint_NONE:
748 break;
749 }
750 }
751
752 if (memop == MemOp_LOAD && t == t2) {
755 rt_unknown = true; // result is UNKNOWN
756 break;
757
758 case Constraint_NOP:
759 memop = MemOp_NOP; // do nothing
760 wback = false;
761 break;
762
763 default:
764 break;
765 }
766 }
767
768 idx = LSL(llvm::SignExtend64<7>(imm7), scale);
769 size = (integer)1 << scale;
770 uint64_t datasize = size * 8;
771 uint64_t address;
772 uint64_t wb_address;
773
774 std::optional<RegisterInfo> reg_info_base =
776 if (!reg_info_base)
777 return false;
778
779 std::optional<RegisterInfo> reg_info_Rt;
780 std::optional<RegisterInfo> reg_info_Rt2;
781
782 if (vector) {
784 reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t2);
785 } else {
787 reg_info_Rt2 = GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t2);
788 }
789
790 if (!reg_info_Rt || !reg_info_Rt2)
791 return false;
792
793 bool success = false;
794 if (n == 31) {
795 // CheckSPAlignment();
796 address =
798 } else
799 address =
801
802 wb_address = address + idx;
803 if (a_mode != AddrMode_POST)
804 address = wb_address;
805
806 Context context_t;
807 Context context_t2;
808
811
812 switch (memop) {
813 case MemOp_STORE: {
814 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
815 // based off of the sp
816 // or fp register
817 {
820 } else {
821 context_t.type = eContextRegisterStore;
822 context_t2.type = eContextRegisterStore;
823 }
824 context_t.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base, 0);
825 context_t2.SetRegisterToRegisterPlusOffset(*reg_info_Rt2, *reg_info_base,
826 size);
827
828 std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt);
829 if (!data_Rt)
830 return false;
831
832 buffer.resize(reg_info_Rt->byte_size);
833 if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer.data(),
834 reg_info_Rt->byte_size, eByteOrderLittle,
835 error) == 0)
836 return false;
837
838 if (!WriteMemory(context_t, address + 0, buffer.data(),
839 reg_info_Rt->byte_size))
840 return false;
841
842 std::optional<RegisterValue> data_Rt2 = ReadRegister(*reg_info_Rt2);
843 if (!data_Rt2)
844 return false;
845
846 buffer.resize(reg_info_Rt2->byte_size);
847 if (data_Rt2->GetAsMemoryData(*reg_info_Rt2, buffer.data(),
848 reg_info_Rt2->byte_size, eByteOrderLittle,
849 error) == 0)
850 return false;
851
852 if (!WriteMemory(context_t2, address + size, buffer.data(),
853 reg_info_Rt2->byte_size))
854 return false;
855 } break;
856
857 case MemOp_LOAD: {
858 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this load is
859 // based off of the sp
860 // or fp register
861 {
864 } else {
865 context_t.type = eContextRegisterLoad;
866 context_t2.type = eContextRegisterLoad;
867 }
868 context_t.SetAddress(address);
869 context_t2.SetAddress(address + size);
870
871 buffer.resize(reg_info_Rt->byte_size);
872 if (rt_unknown)
873 std::fill(buffer.begin(), buffer.end(), 'U');
874 else {
875 if (!ReadMemory(context_t, address, buffer.data(),
876 reg_info_Rt->byte_size))
877 return false;
878 }
879
880 RegisterValue data_Rt;
881 if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer.data(),
882 reg_info_Rt->byte_size, eByteOrderLittle,
883 error) == 0)
884 return false;
885
886 if (!vector && is_signed && !data_Rt.SignExtend(datasize))
887 return false;
888
889 if (!WriteRegister(context_t, *reg_info_Rt, data_Rt))
890 return false;
891
892 buffer.resize(reg_info_Rt2->byte_size);
893 if (!rt_unknown)
894 if (!ReadMemory(context_t2, address + size, buffer.data(),
895 reg_info_Rt2->byte_size))
896 return false;
897
898 RegisterValue data_Rt2;
899 if (data_Rt2.SetFromMemoryData(*reg_info_Rt2, buffer.data(),
900 reg_info_Rt2->byte_size, eByteOrderLittle,
901 error) == 0)
902 return false;
903
904 if (!vector && is_signed && !data_Rt2.SignExtend(datasize))
905 return false;
906
907 if (!WriteRegister(context_t2, *reg_info_Rt2, data_Rt2))
908 return false;
909 } break;
910
911 default:
912 break;
913 }
914
915 if (wback) {
916 if (wb_unknown)
917 wb_address = LLDB_INVALID_ADDRESS;
918 Context context;
919 context.SetImmediateSigned(idx);
920 if (n == 31)
922 else
924 WriteRegisterUnsigned(context, *reg_info_base, wb_address);
925 }
926 return true;
927}
928
929template <EmulateInstructionARM64::AddrMode a_mode>
930bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
931 uint32_t size = Bits32(opcode, 31, 30);
932 uint32_t opc = Bits32(opcode, 23, 22);
933 uint32_t n = Bits32(opcode, 9, 5);
934 uint32_t t = Bits32(opcode, 4, 0);
935
936 bool wback;
937 bool postindex;
938 uint64_t offset;
939
940 switch (a_mode) {
941 case AddrMode_POST:
942 wback = true;
943 postindex = true;
944 offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));
945 break;
946 case AddrMode_PRE:
947 wback = true;
948 postindex = false;
949 offset = llvm::SignExtend64<9>(Bits32(opcode, 20, 12));
950 break;
951 case AddrMode_OFF:
952 wback = false;
953 postindex = false;
954 offset = LSL(Bits32(opcode, 21, 10), size);
955 break;
956 }
957
958 MemOp memop;
959
960 if (Bit32(opc, 1) == 0) {
961 memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
962 } else {
963 memop = MemOp_LOAD;
964 if (size == 2 && Bit32(opc, 0) == 1)
965 return false;
966 }
967
969 bool success = false;
970 uint64_t address;
972
973 if (n == 31)
974 address =
976 else
977 address =
979
980 if (!success)
981 return false;
982
983 if (!postindex)
984 address += offset;
985
986 std::optional<RegisterInfo> reg_info_base =
988 if (!reg_info_base)
989 return false;
990
991 std::optional<RegisterInfo> reg_info_Rt =
993 if (!reg_info_Rt)
994 return false;
995
996 Context context;
997 switch (memop) {
998 case MemOp_STORE: {
999 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
1000 // based off of the sp
1001 // or fp register
1003 else
1004 context.type = eContextRegisterStore;
1005 context.SetRegisterToRegisterPlusOffset(*reg_info_Rt, *reg_info_base,
1006 postindex ? 0 : offset);
1007
1008 std::optional<RegisterValue> data_Rt = ReadRegister(*reg_info_Rt);
1009 if (!data_Rt)
1010 return false;
1011
1012 buffer.resize(reg_info_Rt->byte_size);
1013 if (data_Rt->GetAsMemoryData(*reg_info_Rt, buffer.data(),
1014 reg_info_Rt->byte_size, eByteOrderLittle,
1015 error) == 0)
1016 return false;
1017
1018 if (!WriteMemory(context, address, buffer.data(), reg_info_Rt->byte_size))
1019 return false;
1020 } break;
1021
1022 case MemOp_LOAD: {
1023 if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is
1024 // based off of the sp
1025 // or fp register
1027 else
1028 context.type = eContextRegisterLoad;
1029 context.SetAddress(address);
1030
1031 buffer.resize(reg_info_Rt->byte_size);
1032 if (!ReadMemory(context, address, buffer.data(), reg_info_Rt->byte_size))
1033 return false;
1034
1035 RegisterValue data_Rt;
1036 if (data_Rt.SetFromMemoryData(*reg_info_Rt, buffer.data(),
1037 reg_info_Rt->byte_size, eByteOrderLittle,
1038 error) == 0)
1039 return false;
1040
1041 if (!WriteRegister(context, *reg_info_Rt, data_Rt))
1042 return false;
1043 } break;
1044 default:
1045 return false;
1046 }
1047
1048 if (wback) {
1049 if (postindex)
1050 address += offset;
1051
1052 if (n == 31)
1054 else
1056 context.SetImmediateSigned(offset);
1057
1058 if (!WriteRegisterUnsigned(context, *reg_info_base, address))
1059 return false;
1060 }
1061 return true;
1062}
1063
1064bool EmulateInstructionARM64::EmulateB(const uint32_t opcode) {
1065#if 0
1066 // ARM64 pseudo code...
1067 if branch_type == BranchType_CALL then X[30] = PC[] + 4;
1068 BranchTo(PC[] + offset, branch_type);
1069#endif
1070
1071 bool success = false;
1072
1076 LLDB_REGNUM_GENERIC_PC, 0, &success);
1077 if (!success)
1078 return false;
1079
1080 int64_t offset = llvm::SignExtend64<28>(Bits32(opcode, 25, 0) << 2);
1081 BranchType branch_type = Bit32(opcode, 31) ? BranchType_CALL : BranchType_JMP;
1082 addr_t target = pc + offset;
1083 context.SetImmediateSigned(offset);
1084
1085 switch (branch_type) {
1086 case BranchType_CALL: {
1087 addr_t x30 = pc + 4;
1089 return false;
1090 } break;
1091 case BranchType_JMP:
1092 break;
1093 default:
1094 return false;
1095 }
1096
1097 return BranchTo(context, 64, target);
1098}
1099
1100bool EmulateInstructionARM64::EmulateBcond(const uint32_t opcode) {
1101#if 0
1102 // ARM64 pseudo code...
1103 bits(64) offset = SignExtend(imm19:'00', 64);
1104 bits(4) condition = cond;
1105 if ConditionHolds(condition) then
1106 BranchTo(PC[] + offset, BranchType_JMP);
1107#endif
1108
1109 if (ConditionHolds(Bits32(opcode, 3, 0))) {
1110 bool success = false;
1111
1112 const uint64_t pc = ReadRegisterUnsigned(
1114 if (!success)
1115 return false;
1116
1117 int64_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
1118 addr_t target = pc + offset;
1119
1122 context.SetImmediateSigned(offset);
1123 if (!BranchTo(context, 64, target))
1124 return false;
1125 }
1126 return true;
1127}
1128
1129bool EmulateInstructionARM64::EmulateCBZ(const uint32_t opcode) {
1130#if 0
1131 integer t = UInt(Rt);
1132 integer datasize = if sf == '1' then 64 else 32;
1133 boolean iszero = (op == '0');
1134 bits(64) offset = SignExtend(imm19:'00', 64);
1135
1136 bits(datasize) operand1 = X[t];
1137 if IsZero(operand1) == iszero then
1138 BranchTo(PC[] + offset, BranchType_JMP);
1139#endif
1140
1141 bool success = false;
1142
1143 uint32_t t = Bits32(opcode, 4, 0);
1144 bool is_zero = Bit32(opcode, 24) == 0;
1145 int32_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
1146
1147 const uint64_t operand =
1149 if (!success)
1150 return false;
1151
1152 if (m_ignore_conditions || ((operand == 0) == is_zero)) {
1153 const uint64_t pc = ReadRegisterUnsigned(
1155 if (!success)
1156 return false;
1157
1160 context.SetImmediateSigned(offset);
1161 if (!BranchTo(context, 64, pc + offset))
1162 return false;
1163 }
1164 return true;
1165}
1166
1167bool EmulateInstructionARM64::EmulateTBZ(const uint32_t opcode) {
1168#if 0
1169 integer t = UInt(Rt);
1170 integer datasize = if b5 == '1' then 64 else 32;
1171 integer bit_pos = UInt(b5:b40);
1172 bit bit_val = op;
1173 bits(64) offset = SignExtend(imm14:'00', 64);
1174#endif
1175
1176 bool success = false;
1177
1178 uint32_t t = Bits32(opcode, 4, 0);
1179 uint32_t bit_pos = (Bit32(opcode, 31) << 6) | (Bits32(opcode, 23, 19));
1180 uint32_t bit_val = Bit32(opcode, 24);
1181 int64_t offset = llvm::SignExtend64<16>(Bits32(opcode, 18, 5) << 2);
1182
1183 const uint64_t operand =
1185 if (!success)
1186 return false;
1187
1188 if (m_ignore_conditions || Bit32(operand, bit_pos) == bit_val) {
1189 const uint64_t pc = ReadRegisterUnsigned(
1191 if (!success)
1192 return false;
1193
1196 context.SetImmediateSigned(offset);
1197 if (!BranchTo(context, 64, pc + offset))
1198 return false;
1199 }
1200 return true;
1201}
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:26
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)
llvm::SmallVector< uint8_t, kTypicalRegisterByteSize > BytesContainer
Definition: RegisterValue.h:41
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:59
#define LLDB_REGNUM_GENERIC_SP
Definition: lldb-defines.h:57
#define LLDB_REGNUM_GENERIC_FLAGS
Definition: lldb-defines.h:60
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:87
#define LLDB_REGNUM_GENERIC_PC
Definition: lldb-defines.h:56
#define LLDB_REGNUM_GENERIC_FP
Definition: lldb-defines.h:58
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 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: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),...