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