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