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