1 //===-- EmulateInstructionARM64.cpp -------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "EmulateInstructionARM64.h"
11 
12 #include <stdlib.h>
13 
14 #include "lldb/Core/ArchSpec.h"
15 #include "lldb/Core/Address.h"
16 #include "lldb/Core/ConstString.h"
17 #include "lldb/Core/PluginManager.h"
18 #include "lldb/Core/Stream.h"
19 #include "lldb/Symbol/UnwindPlan.h"
20 
21 #include "Plugins/Process/Utility/ARMDefines.h"
22 #include "Plugins/Process/Utility/ARMUtils.h"
23 #include "Utility/ARM64_DWARF_Registers.h"
24 
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/Support/MathExtras.h" // for SignExtend32 template function
27                                      // and CountTrailingZeros_32 function
28 
29 #include "Plugins/Process/Utility/InstructionUtils.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 #define No_VFP  0
35 #define VFPv1   (1u << 1)
36 #define VFPv2   (1u << 2)
37 #define VFPv3   (1u << 3)
38 #define AdvancedSIMD (1u << 4)
39 
40 #define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)
41 #define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)
42 #define VFPv2v3     (VFPv2 | VFPv3)
43 
44 #define UInt(x) ((uint64_t)x)
45 #define SInt(x) ((int64_t)x)
46 #define bit bool
47 #define boolean bool
48 #define integer int64_t
49 
50 static inline bool
51 IsZero(uint64_t x)
52 {
53     return x == 0;
54 }
55 
56 static inline uint64_t
57 NOT(uint64_t x)
58 {
59     return ~x;
60 }
61 
62 #if 0
63 // LSL_C()
64 // =======
65 static inline uint64_t
66 LSL_C (uint64_t x, integer shift, bool &carry_out)
67 {
68     assert (shift >= 0);
69     uint64_t result = x << shift;
70     carry_out = ((1ull << (64-1)) >> (shift - 1)) != 0;
71     return result;
72 }
73 #endif
74 
75 // LSL()
76 // =====
77 
78 static inline uint64_t
79 LSL(uint64_t x, integer shift)
80 {
81     if (shift == 0)
82         return x;
83     return x << shift;
84 }
85 
86 // AddWithCarry()
87 // ===============
88 static inline uint64_t
89 AddWithCarry (uint32_t N, uint64_t x, uint64_t y, bit carry_in, EmulateInstructionARM64::ProcState &proc_state)
90 {
91     uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
92     int64_t signed_sum = SInt(x) + SInt(y) + UInt(carry_in);
93     uint64_t result = unsigned_sum;
94     if (N < 64)
95         result = Bits64 (result, N-1, 0);
96     proc_state.N = Bit64(result, N-1);
97     proc_state.Z = IsZero(result);
98     proc_state.C = UInt(result) == unsigned_sum;
99     proc_state.V = SInt(result) == signed_sum;
100     return result;
101 }
102 
103 // ConstrainUnpredictable()
104 // ========================
105 
106 EmulateInstructionARM64::ConstraintType
107 ConstrainUnpredictable (EmulateInstructionARM64::Unpredictable which)
108 {
109     EmulateInstructionARM64::ConstraintType result = EmulateInstructionARM64::Constraint_UNKNOWN;
110     switch (which)
111     {
112         case EmulateInstructionARM64::Unpredictable_WBOVERLAP:
113         case EmulateInstructionARM64::Unpredictable_LDPOVERLAP:
114             // TODO: don't know what to really do here? Pseudo code says:
115             // set result to one of above Constraint behaviours or UNDEFINED
116             break;
117     }
118     return result;
119 }
120 
121 
122 
123 //----------------------------------------------------------------------
124 //
125 // EmulateInstructionARM implementation
126 //
127 //----------------------------------------------------------------------
128 
129 void
130 EmulateInstructionARM64::Initialize ()
131 {
132     PluginManager::RegisterPlugin (GetPluginNameStatic (),
133                                    GetPluginDescriptionStatic (),
134                                    CreateInstance);
135 }
136 
137 void
138 EmulateInstructionARM64::Terminate ()
139 {
140     PluginManager::UnregisterPlugin (CreateInstance);
141 }
142 
143 ConstString
144 EmulateInstructionARM64::GetPluginNameStatic ()
145 {
146     ConstString g_plugin_name ("lldb.emulate-instruction.arm64");
147     return g_plugin_name;
148 }
149 
150 lldb_private::ConstString
151 EmulateInstructionARM64::GetPluginName()
152 {
153     static ConstString g_plugin_name ("EmulateInstructionARM64");
154     return g_plugin_name;
155 }
156 
157 const char *
158 EmulateInstructionARM64::GetPluginDescriptionStatic ()
159 {
160     return "Emulate instructions for the ARM64 architecture.";
161 }
162 
163 EmulateInstruction *
164 EmulateInstructionARM64::CreateInstance (const ArchSpec &arch, InstructionType inst_type)
165 {
166     if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic(inst_type))
167     {
168         if (arch.GetTriple().getArch() == llvm::Triple::aarch64)
169         {
170             std::auto_ptr<EmulateInstructionARM64> emulate_insn_ap (new EmulateInstructionARM64 (arch));
171             if (emulate_insn_ap.get())
172                 return emulate_insn_ap.release();
173         }
174     }
175 
176     return NULL;
177 }
178 
179 bool
180 EmulateInstructionARM64::SetTargetTriple (const ArchSpec &arch)
181 {
182     if (arch.GetTriple().getArch () == llvm::Triple::arm)
183         return true;
184     else if (arch.GetTriple().getArch () == llvm::Triple::thumb)
185         return true;
186 
187     return false;
188 }
189 
190 bool
191 EmulateInstructionARM64::GetRegisterInfo (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo &reg_info)
192 {
193     if (reg_kind == eRegisterKindGeneric)
194     {
195         switch (reg_num)
196         {
197             case LLDB_REGNUM_GENERIC_PC:    reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::pc; break;
198             case LLDB_REGNUM_GENERIC_SP:    reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::sp; break;
199             case LLDB_REGNUM_GENERIC_FP:    reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::fp; break;
200             case LLDB_REGNUM_GENERIC_RA:    reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::lr; break;
201             case LLDB_REGNUM_GENERIC_FLAGS:
202                 // There is no DWARF register number for the CPSR right now...
203                 reg_info.name = "cpsr";
204                 reg_info.alt_name = NULL;
205                 reg_info.byte_size = 4;
206                 reg_info.byte_offset = 0;
207                 reg_info.encoding = eEncodingUint;
208                 reg_info.format = eFormatHex;
209                 for (uint32_t i=0; i<lldb::kNumRegisterKinds; ++i)
210                     reg_info.kinds[reg_kind] = LLDB_INVALID_REGNUM;
211                 reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
212                 return true;
213 
214             default: return false;
215         }
216     }
217 
218     if (reg_kind == eRegisterKindDWARF)
219         return arm64_dwarf::GetRegisterInfo(reg_num, reg_info);
220     return false;
221 }
222 
223 EmulateInstructionARM64::Opcode*
224 EmulateInstructionARM64::GetOpcodeForInstruction (const uint32_t opcode)
225 {
226     static EmulateInstructionARM64::Opcode
227     g_opcodes[] =
228     {
229         //----------------------------------------------------------------------
230         // Prologue instructions
231         //----------------------------------------------------------------------
232 
233         // push register(s)
234         { 0xff000000, 0xd1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB  <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" },
235         { 0xff000000, 0xf1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS  <Xd>, <Xn|SP>, #<imm> {, <shift>}" },
236         { 0xff000000, 0x91000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD  <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" },
237         { 0xff000000, 0xb1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS  <Xd>, <Xn|SP>, #<imm> {, <shift>}" },
238 
239 
240         { 0xff000000, 0x51000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB  <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" },
241         { 0xff000000, 0x71000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS  <Wd>, <Wn|WSP>, #<imm> {, <shift>}" },
242         { 0xff000000, 0x11000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD  <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" },
243         { 0xff000000, 0x31000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS  <Wd>, <Wn|WSP>, #<imm> {, <shift>}" },
244 
245         { 0xffc00000, 0x29000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP  <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]" },
246         { 0xffc00000, 0xa9000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP  <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]" },
247         { 0xffc00000, 0x2d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP  <St>, <St2>, [<Xn|SP>{, #<imm>}]" },
248         { 0xffc00000, 0x6d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP  <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]" },
249         { 0xffc00000, 0xad000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP  <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]" },
250 
251         { 0xffc00000, 0xad800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP  <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
252         { 0xffc00000, 0x2d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP  <St>, <St2>, [<Xn|SP>, #<imm>]!" },
253         { 0xffc00000, 0x29800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP  <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
254         { 0xffc00000, 0x6d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP  <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
255         { 0xffc00000, 0xa9800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP  <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
256 
257     };
258     static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_opcodes);
259 
260     for (size_t i=0; i<k_num_arm_opcodes; ++i)
261     {
262         if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
263             return &g_opcodes[i];
264     }
265     return NULL;
266 }
267 
268 bool
269 EmulateInstructionARM64::ReadInstruction ()
270 {
271     bool success = false;
272     m_addr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
273     if (success)
274     {
275         Context read_inst_context;
276         read_inst_context.type = eContextReadOpcode;
277         read_inst_context.SetNoArgs ();
278         m_opcode.SetOpcode32 (ReadMemoryUnsigned (read_inst_context, m_addr, 4, 0, &success), GetByteOrder());
279     }
280     if (!success)
281         m_addr = LLDB_INVALID_ADDRESS;
282     return success;
283 }
284 
285 
286 bool
287 EmulateInstructionARM64::EvaluateInstruction (uint32_t evaluate_options)
288 {
289     const uint32_t opcode = m_opcode.GetOpcode32();
290     Opcode *opcode_data = GetOpcodeForInstruction(opcode);
291     if (opcode_data == NULL)
292         return false;
293 
294     //printf ("opcode template for 0x%8.8x: %s\n", opcode, opcode_data->name);
295     const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
296     m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions;
297 
298     bool success = false;
299 //    if (m_opcode_cpsr == 0 || m_ignore_conditions == false)
300 //    {
301 //        m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric,         // use eRegisterKindDWARF is we ever get a cpsr DWARF register number
302 //                                              LLDB_REGNUM_GENERIC_FLAGS,    // use arm64_dwarf::cpsr if we ever get one
303 //                                              0,
304 //                                              &success);
305 //    }
306 
307     // Only return false if we are unable to read the CPSR if we care about conditions
308     if (success == false && m_ignore_conditions == false)
309         return false;
310 
311     uint32_t orig_pc_value = 0;
312     if (auto_advance_pc)
313     {
314         orig_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::pc, 0, &success);
315         if (!success)
316             return false;
317     }
318 
319     // Call the Emulate... function.
320     success = (this->*opcode_data->callback) (opcode);
321     if (!success)
322         return false;
323 
324     if (auto_advance_pc)
325     {
326         uint32_t new_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::pc, 0, &success);
327         if (!success)
328             return false;
329 
330         if (auto_advance_pc && (new_pc_value == orig_pc_value))
331         {
332             EmulateInstruction::Context context;
333             context.type = eContextAdvancePC;
334             context.SetNoArgs();
335             if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::pc, orig_pc_value + 4))
336                 return false;
337         }
338     }
339     return true;
340 }
341 
342 bool
343 EmulateInstructionARM64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
344 {
345     unwind_plan.Clear();
346     unwind_plan.SetRegisterKind (eRegisterKindDWARF);
347 
348     UnwindPlan::RowSP row(new UnwindPlan::Row);
349     const bool can_replace = false;
350 
351     // Our previous Call Frame Address is the stack pointer
352     row->SetCFARegister (arm64_dwarf::sp);
353 
354     // Our previous PC is in the LR
355     row->SetRegisterLocationToRegister(arm64_dwarf::pc, arm64_dwarf::lr, can_replace);
356 
357     unwind_plan.AppendRow (row);
358 
359     // All other registers are the same.
360 
361     unwind_plan.SetSourceName ("EmulateInstructionARM64");
362     unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
363     unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
364     return true;
365 }
366 
367 
368 
369 bool
370 EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode)
371 {
372     // integer d = UInt(Rd);
373     // integer n = UInt(Rn);
374     // integer datasize = if sf == 1 then 64 else 32;
375     // boolean sub_op = (op == 1);
376     // boolean setflags = (S == 1);
377     // bits(datasize) imm;
378     //
379     // case shift of
380     //     when '00' imm = ZeroExtend(imm12, datasize);
381     //     when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize);
382     //    when '1x' UNDEFINED;
383     //
384     //
385     // bits(datasize) result;
386     // bits(datasize) operand1 = if n == 31 then SP[] else X[n];
387     // bits(datasize) operand2 = imm;
388     // bits(4) nzcv;
389     // bit carry_in;
390     //
391     // if sub_op then
392     //     operand2 = NOT(operand2);
393     //     carry_in = 1;
394     // else
395     //     carry_in = 0;
396     //
397     // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in);
398     //
399     // if setflags then
400     //     PSTATE.NZCV = nzcv;
401     //
402     // if d == 31 && !setflags then
403     //     SP[] = result;
404     // else
405     //     X[d] = result;
406 
407     const uint32_t sf = Bit32(opcode, 31);
408     const uint32_t op = Bit32(opcode, 30);
409     const uint32_t S = Bit32(opcode, 29);
410     const uint32_t shift = Bits32(opcode, 23, 22);
411     const uint32_t imm12 = Bits32(opcode, 21, 10);
412     const uint32_t Rn = Bits32(opcode, 9, 5);
413     const uint32_t Rd = Bits32(opcode, 4, 0);
414 
415     bool success = false;
416 
417     const uint32_t d = UInt(Rd);
418     const uint32_t n = UInt(Rn);
419     const uint32_t datasize = (sf == 1) ? 64 : 32;
420     boolean sub_op = op == 1;
421     boolean setflags = S == 1;
422     uint64_t imm;
423 
424     switch (shift)
425     {
426         case 0: imm = imm12; break;
427         case 1: imm = imm12 << 12; break;
428         default: return false;  // UNDEFINED;
429     }
430     uint64_t result;
431     uint64_t operand1 = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::x0 + n, 0, &success);
432     uint64_t operand2 = imm;
433     bit carry_in;
434 
435     if (sub_op)
436     {
437         operand2 = NOT(operand2);
438         carry_in = 1;
439         imm = -imm; // For the Register plug offset context below
440     }
441     else
442     {
443         carry_in = 0;
444     }
445 
446     ProcState proc_state;
447 
448     result = AddWithCarry (datasize, operand1, operand2, carry_in, proc_state);
449 
450     if (setflags)
451     {
452         m_emulated_pstate.N = proc_state.N;
453         m_emulated_pstate.Z = proc_state.Z;
454         m_emulated_pstate.C = proc_state.C;
455         m_emulated_pstate.V = proc_state.V;
456     }
457 
458     Context context;
459     RegisterInfo reg_info_Rn;
460     if (arm64_dwarf::GetRegisterInfo (n, reg_info_Rn))
461         context.SetRegisterPlusOffset (reg_info_Rn, imm);
462 
463     if ((n == arm64_dwarf::sp || n == arm64_dwarf::fp) &&
464         d == arm64_dwarf::sp &&
465         !setflags)
466     {
467         context.type = EmulateInstruction::eContextAdjustStackPointer;
468     }
469     else if (d == arm64_dwarf::fp &&
470              n == arm64_dwarf::sp &&
471              !setflags)
472     {
473         context.type = EmulateInstruction::eContextSetFramePointer;
474     }
475     else
476     {
477         context.type = EmulateInstruction::eContextImmediate;
478     }
479     WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x0 + d, result);
480 
481     return false;
482 }
483 
484 bool
485 EmulateInstructionARM64::Emulate_ldstpair_off (const uint32_t opcode)
486 {
487     return Emulate_ldstpair (opcode, AddrMode_OFF);
488 }
489 
490 
491 bool
492 EmulateInstructionARM64::Emulate_ldstpair_pre (const uint32_t opcode)
493 {
494     return Emulate_ldstpair (opcode, AddrMode_PRE);
495 }
496 
497 bool
498 EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode)
499 {
500     uint32_t opc = Bits32(opcode, 31, 30);
501     uint32_t V = Bit32(opcode, 26);
502     uint32_t L = Bit32(opcode, 22);
503     uint32_t imm7 = Bits32(opcode, 21, 15);
504     uint32_t Rt2 = Bits32(opcode, 14, 10);
505     uint32_t Rn = Bits32(opcode, 9, 5);
506     uint32_t Rt = Bits32(opcode, 4, 0);
507 
508     integer n = UInt(Rn);
509     integer t = UInt(Rt);
510     integer t2 = UInt(Rt2);
511     uint64_t idx;
512 
513     MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE;
514     boolean vector = (V == 1);
515     //AccType acctype = AccType_NORMAL;
516     boolean is_signed = false;
517     boolean wback = a_mode != AddrMode_OFF;
518     boolean wb_unknown = false;
519     boolean rt_unknown = false;
520     integer scale;
521     integer size;
522 
523     if (opc == 3)
524         return false; // UNDEFINED
525 
526     if (vector)
527     {
528         scale = 2 + UInt(opc);
529     }
530     else
531     {
532         scale = (opc & 2) ? 3 : 2;
533         is_signed = (opc & 1) != 0;
534         if (is_signed && memop == MemOp_STORE)
535             return false; // UNDEFINED
536     }
537 
538     if (!vector && wback && ((t == n) || (t2 == n)))
539     {
540         switch (ConstrainUnpredictable(Unpredictable_WBOVERLAP))
541         {
542             case Constraint_UNKNOWN:
543                 wb_unknown = true;  // writeback is UNKNOWN
544                 break;
545 
546             case Constraint_SUPPRESSWB:
547                 wback = false;      // writeback is suppressed
548                 break;
549 
550             case Constraint_NOP:
551                 memop = MemOp_NOP;  // do nothing
552                 wback = false;
553                 break;
554 
555             case Constraint_NONE:
556                 break;
557         }
558     }
559 
560     if (memop == MemOp_LOAD && t == t2)
561     {
562         switch (ConstrainUnpredictable(Unpredictable_LDPOVERLAP))
563         {
564             case Constraint_UNKNOWN:
565                 rt_unknown = true;  // result is UNKNOWN
566                 break;
567 
568             case Constraint_NOP:
569                 memop = MemOp_NOP;  // do nothing
570                 wback = false;
571                 break;
572 
573             default:
574                 break;
575         }
576     }
577 
578     idx = LSL(llvm::SignExtend64<7>(imm7), scale);
579     size = (integer)1 << scale;
580     uint64_t datasize = size * 8;
581     uint64_t address;
582     uint64_t wb_address;
583 
584     RegisterValue data_Rt;
585     RegisterValue data_Rt2;
586 
587     //    if (vector)
588     //        CheckFPEnabled(false);
589 
590     RegisterInfo reg_info_base;
591     RegisterInfo reg_info_Rt;
592     RegisterInfo reg_info_Rt2;
593     if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + n, reg_info_base))
594         return false;
595 
596     if (vector)
597     {
598         if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::v0 + n, reg_info_Rt))
599             return false;
600         if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::v0 + n, reg_info_Rt2))
601             return false;
602     }
603     else
604     {
605         if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + t, reg_info_Rt))
606             return false;
607         if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + t2, reg_info_Rt2))
608             return false;
609     }
610 
611     bool success = false;
612     if (n == 31)
613     {
614         //CheckSPAlignment();
615         address = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::sp, 0, &success);
616     }
617     else
618         address = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::x0 + n, 0, &success);
619 
620     wb_address = address + idx;
621     if (a_mode != AddrMode_POST)
622         address = wb_address;
623 
624     Context context_t;
625     Context context_t2;
626 
627     if (n == 31 || n == 29) // if this store is based off of the sp or fp register
628     {
629         context_t.type = eContextPushRegisterOnStack;
630         context_t2.type = eContextPushRegisterOnStack;
631     }
632     else
633     {
634         context_t.type = eContextRegisterPlusOffset;
635         context_t2.type = eContextRegisterPlusOffset;
636     }
637     context_t.SetRegisterToRegisterPlusOffset (reg_info_Rt, reg_info_base, 0);
638     context_t2.SetRegisterToRegisterPlusOffset (reg_info_Rt2, reg_info_base, size);
639     uint8_t buffer [RegisterValue::kMaxRegisterByteSize];
640     Error error;
641 
642     switch (memop)
643     {
644         case MemOp_STORE:
645         {
646             if (!ReadRegister (&reg_info_Rt, data_Rt))
647                 return false;
648 
649             if (data_Rt.GetAsMemoryData(&reg_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0)
650                 return false;
651 
652             if (!WriteMemory(context_t, address + 0, buffer, reg_info_Rt.byte_size))
653                 return false;
654 
655             if (!ReadRegister (&reg_info_Rt2, data_Rt2))
656                 return false;
657 
658             if (data_Rt2.GetAsMemoryData(&reg_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0)
659                 return false;
660 
661             if (!WriteMemory(context_t2, address + size, buffer, reg_info_Rt2.byte_size))
662                 return false;
663         }
664             break;
665 
666         case MemOp_LOAD:
667         {
668             if (rt_unknown)
669                 memset (buffer, 'U', reg_info_Rt.byte_size);
670             else
671             {
672                 if (!ReadMemory (context_t, address, buffer, reg_info_Rt.byte_size))
673                     return false;
674             }
675 
676             if (data_Rt.SetFromMemoryData(&reg_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0)
677                 return false;
678 
679             if (!vector && is_signed && !data_Rt.SignExtend (datasize))
680                 return false;
681 
682             if (!WriteRegister (context_t, &reg_info_Rt, data_Rt))
683                 return false;
684 
685             if (!rt_unknown)
686             {
687                 if (!ReadMemory (context_t2, address + size, buffer, reg_info_Rt2.byte_size))
688                     return false;
689             }
690 
691             if (data_Rt2.SetFromMemoryData(&reg_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0)
692                 return false;
693 
694             if (!vector && is_signed && !data_Rt2.SignExtend (datasize))
695                 return false;
696 
697             if (!WriteRegister (context_t2, &reg_info_Rt2, data_Rt2))
698                 return false;
699         }
700             break;
701 
702         default:
703             break;
704     }
705 
706     if (wback)
707     {
708         if (wb_unknown)
709             wb_address = LLDB_INVALID_ADDRESS;
710         Context context;
711         context.SetImmediateSigned (idx);
712         if (n == 31)
713             context.type = eContextAdjustStackPointer;
714         else
715             context.type = eContextAdjustBaseRegister;
716         WriteRegisterUnsigned (context, &reg_info_base, wb_address);
717     }
718     return true;
719 }
720