xref: /openbsd-src/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrick //===-- DNBArchImplARM64.cpp ------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick //
9061da546Spatrick //  Created by Greg Clayton on 6/25/07.
10061da546Spatrick //
11061da546Spatrick //===----------------------------------------------------------------------===//
12061da546Spatrick 
13061da546Spatrick #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
14061da546Spatrick 
15061da546Spatrick #include "MacOSX/arm64/DNBArchImplARM64.h"
16061da546Spatrick 
17061da546Spatrick #if defined(ARM_THREAD_STATE64_COUNT)
18061da546Spatrick 
19061da546Spatrick #include "DNB.h"
20061da546Spatrick #include "DNBBreakpoint.h"
21061da546Spatrick #include "DNBLog.h"
22061da546Spatrick #include "DNBRegisterInfo.h"
23061da546Spatrick #include "MacOSX/MachProcess.h"
24061da546Spatrick #include "MacOSX/MachThread.h"
25061da546Spatrick 
26be691f3bSpatrick #include <cinttypes>
27061da546Spatrick #include <sys/sysctl.h>
28061da546Spatrick 
29061da546Spatrick #if __has_feature(ptrauth_calls)
30061da546Spatrick #include <ptrauth.h>
31061da546Spatrick #endif
32061da546Spatrick 
33061da546Spatrick // Break only in privileged or user mode
34061da546Spatrick // (PAC bits in the DBGWVRn_EL1 watchpoint control register)
35061da546Spatrick #define S_USER ((uint32_t)(2u << 1))
36061da546Spatrick 
37061da546Spatrick #define BCR_ENABLE ((uint32_t)(1u))
38061da546Spatrick #define WCR_ENABLE ((uint32_t)(1u))
39061da546Spatrick 
40061da546Spatrick // Watchpoint load/store
41061da546Spatrick // (LSC bits in the DBGWVRn_EL1 watchpoint control register)
42061da546Spatrick #define WCR_LOAD ((uint32_t)(1u << 3))
43061da546Spatrick #define WCR_STORE ((uint32_t)(1u << 4))
44061da546Spatrick 
45061da546Spatrick // Enable breakpoint, watchpoint, and vector catch debug exceptions.
46061da546Spatrick // (MDE bit in the MDSCR_EL1 register.  Equivalent to the MDBGen bit in
47061da546Spatrick // DBGDSCRext in Aarch32)
48061da546Spatrick #define MDE_ENABLE ((uint32_t)(1u << 15))
49061da546Spatrick 
50061da546Spatrick // Single instruction step
51061da546Spatrick // (SS bit in the MDSCR_EL1 register)
52061da546Spatrick #define SS_ENABLE ((uint32_t)(1u))
53061da546Spatrick 
54061da546Spatrick static const uint8_t g_arm64_breakpoint_opcode[] = {
55061da546Spatrick     0x00, 0x00, 0x20, 0xD4}; // "brk #0", 0xd4200000 in BE byte order
56061da546Spatrick 
57061da546Spatrick // If we need to set one logical watchpoint by using
58061da546Spatrick // two hardware watchpoint registers, the watchpoint
59061da546Spatrick // will be split into a "high" and "low" watchpoint.
60061da546Spatrick // Record both of them in the LoHi array.
61061da546Spatrick 
62061da546Spatrick // It's safe to initialize to all 0's since
63061da546Spatrick // hi > lo and therefore LoHi[i] cannot be 0.
64061da546Spatrick static uint32_t LoHi[16] = {0};
65061da546Spatrick 
Initialize()66061da546Spatrick void DNBArchMachARM64::Initialize() {
67061da546Spatrick   DNBArchPluginInfo arch_plugin_info = {
68061da546Spatrick       CPU_TYPE_ARM64, DNBArchMachARM64::Create,
69061da546Spatrick       DNBArchMachARM64::GetRegisterSetInfo,
70061da546Spatrick       DNBArchMachARM64::SoftwareBreakpointOpcode};
71061da546Spatrick 
72061da546Spatrick   // Register this arch plug-in with the main protocol class
73061da546Spatrick   DNBArchProtocol::RegisterArchPlugin(arch_plugin_info);
74061da546Spatrick 
75061da546Spatrick   DNBArchPluginInfo arch_plugin_info_32 = {
76061da546Spatrick       CPU_TYPE_ARM64_32, DNBArchMachARM64::Create,
77061da546Spatrick       DNBArchMachARM64::GetRegisterSetInfo,
78061da546Spatrick       DNBArchMachARM64::SoftwareBreakpointOpcode};
79061da546Spatrick 
80061da546Spatrick   // Register this arch plug-in with the main protocol class
81061da546Spatrick   DNBArchProtocol::RegisterArchPlugin(arch_plugin_info_32);
82061da546Spatrick }
83061da546Spatrick 
Create(MachThread * thread)84061da546Spatrick DNBArchProtocol *DNBArchMachARM64::Create(MachThread *thread) {
85061da546Spatrick   DNBArchMachARM64 *obj = new DNBArchMachARM64(thread);
86061da546Spatrick 
87061da546Spatrick   return obj;
88061da546Spatrick }
89061da546Spatrick 
90061da546Spatrick const uint8_t *
SoftwareBreakpointOpcode(nub_size_t byte_size)91061da546Spatrick DNBArchMachARM64::SoftwareBreakpointOpcode(nub_size_t byte_size) {
92061da546Spatrick   return g_arm64_breakpoint_opcode;
93061da546Spatrick }
94061da546Spatrick 
GetCPUType()95061da546Spatrick uint32_t DNBArchMachARM64::GetCPUType() { return CPU_TYPE_ARM64; }
96061da546Spatrick 
clear_pac_bits(uint64_t value)97*f6aab3d8Srobert static uint64_t clear_pac_bits(uint64_t value) {
98*f6aab3d8Srobert   uint32_t addressing_bits = 0;
99*f6aab3d8Srobert   if (!DNBGetAddressingBits(addressing_bits))
100*f6aab3d8Srobert     return value;
101*f6aab3d8Srobert 
102*f6aab3d8Srobert     // On arm64_32, no ptrauth bits to clear
103*f6aab3d8Srobert #if !defined(__LP64__)
104*f6aab3d8Srobert   return value;
105*f6aab3d8Srobert #endif
106*f6aab3d8Srobert 
107*f6aab3d8Srobert   uint64_t mask = ((1ULL << addressing_bits) - 1);
108*f6aab3d8Srobert 
109*f6aab3d8Srobert   // Normally PAC bit clearing needs to check b55 and either set the
110*f6aab3d8Srobert   // non-addressing bits, or clear them.  But the register values we
111*f6aab3d8Srobert   // get from thread_get_state on an arm64e process don't follow this
112*f6aab3d8Srobert   // convention?, at least when there's been a PAC auth failure in
113*f6aab3d8Srobert   // the inferior.
114*f6aab3d8Srobert   // Userland processes are always in low memory, so this
115*f6aab3d8Srobert   // hardcoding b55 == 0 PAC stripping behavior here.
116*f6aab3d8Srobert 
117*f6aab3d8Srobert   return value & mask; // high bits cleared to 0
118*f6aab3d8Srobert }
119*f6aab3d8Srobert 
GetPC(uint64_t failValue)120061da546Spatrick uint64_t DNBArchMachARM64::GetPC(uint64_t failValue) {
121061da546Spatrick   // Get program counter
122061da546Spatrick   if (GetGPRState(false) == KERN_SUCCESS)
123*f6aab3d8Srobert #if __has_feature(ptrauth_calls) && defined(__LP64__)
124*f6aab3d8Srobert     return clear_pac_bits(
125*f6aab3d8Srobert         reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc));
126061da546Spatrick #else
127061da546Spatrick     return m_state.context.gpr.__pc;
128061da546Spatrick #endif
129061da546Spatrick   return failValue;
130061da546Spatrick }
131061da546Spatrick 
SetPC(uint64_t value)132061da546Spatrick kern_return_t DNBArchMachARM64::SetPC(uint64_t value) {
133061da546Spatrick   // Get program counter
134061da546Spatrick   kern_return_t err = GetGPRState(false);
135061da546Spatrick   if (err == KERN_SUCCESS) {
136061da546Spatrick #if defined(__LP64__)
137061da546Spatrick #if __has_feature(ptrauth_calls)
138061da546Spatrick     // The incoming value could be garbage.  Strip it to avoid
139061da546Spatrick     // trapping when it gets resigned in the thread state.
140061da546Spatrick     value = (uint64_t) ptrauth_strip((void*) value, ptrauth_key_function_pointer);
141061da546Spatrick     value = (uint64_t) ptrauth_sign_unauthenticated((void*) value, ptrauth_key_function_pointer, 0);
142061da546Spatrick #endif
143061da546Spatrick     arm_thread_state64_set_pc_fptr (m_state.context.gpr, (void*) value);
144061da546Spatrick #else
145061da546Spatrick     m_state.context.gpr.__pc = value;
146061da546Spatrick #endif
147061da546Spatrick     err = SetGPRState();
148061da546Spatrick   }
149061da546Spatrick   return err == KERN_SUCCESS;
150061da546Spatrick }
151061da546Spatrick 
GetSP(uint64_t failValue)152061da546Spatrick uint64_t DNBArchMachARM64::GetSP(uint64_t failValue) {
153061da546Spatrick   // Get stack pointer
154061da546Spatrick   if (GetGPRState(false) == KERN_SUCCESS)
155*f6aab3d8Srobert #if __has_feature(ptrauth_calls) && defined(__LP64__)
156*f6aab3d8Srobert     return clear_pac_bits(
157*f6aab3d8Srobert         reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_sp));
158061da546Spatrick #else
159061da546Spatrick     return m_state.context.gpr.__sp;
160061da546Spatrick #endif
161061da546Spatrick   return failValue;
162061da546Spatrick }
163061da546Spatrick 
GetGPRState(bool force)164061da546Spatrick kern_return_t DNBArchMachARM64::GetGPRState(bool force) {
165061da546Spatrick   int set = e_regSetGPR;
166061da546Spatrick   // Check if we have valid cached registers
167061da546Spatrick   if (!force && m_state.GetError(set, Read) == KERN_SUCCESS)
168061da546Spatrick     return KERN_SUCCESS;
169061da546Spatrick 
170061da546Spatrick   // Read the registers from our thread
171061da546Spatrick   mach_msg_type_number_t count = e_regSetGPRCount;
172061da546Spatrick   kern_return_t kret =
173061da546Spatrick       ::thread_get_state(m_thread->MachPortNumber(), ARM_THREAD_STATE64,
174061da546Spatrick                          (thread_state_t)&m_state.context.gpr, &count);
175061da546Spatrick   if (DNBLogEnabledForAny(LOG_THREAD)) {
176061da546Spatrick     uint64_t *x = &m_state.context.gpr.__x[0];
177be691f3bSpatrick 
178*f6aab3d8Srobert #if __has_feature(ptrauth_calls) && defined(__LP64__)
179*f6aab3d8Srobert     uint64_t log_fp = clear_pac_bits(
180*f6aab3d8Srobert         reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_fp));
181*f6aab3d8Srobert     uint64_t log_lr = clear_pac_bits(
182*f6aab3d8Srobert         reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_lr));
183*f6aab3d8Srobert     uint64_t log_sp = clear_pac_bits(
184*f6aab3d8Srobert         reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_sp));
185*f6aab3d8Srobert     uint64_t log_pc = clear_pac_bits(
186*f6aab3d8Srobert         reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc));
187be691f3bSpatrick #else
188be691f3bSpatrick     uint64_t log_fp = m_state.context.gpr.__fp;
189*f6aab3d8Srobert     uint64_t log_lr = m_state.context.gpr.__lr;
190*f6aab3d8Srobert     uint64_t log_sp = m_state.context.gpr.__sp;
191*f6aab3d8Srobert     uint64_t log_pc = m_state.context.gpr.__pc;
192be691f3bSpatrick #endif
193061da546Spatrick     DNBLogThreaded(
194061da546Spatrick         "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = %u) regs"
195061da546Spatrick         "\n   x0=%16.16llx"
196061da546Spatrick         "\n   x1=%16.16llx"
197061da546Spatrick         "\n   x2=%16.16llx"
198061da546Spatrick         "\n   x3=%16.16llx"
199061da546Spatrick         "\n   x4=%16.16llx"
200061da546Spatrick         "\n   x5=%16.16llx"
201061da546Spatrick         "\n   x6=%16.16llx"
202061da546Spatrick         "\n   x7=%16.16llx"
203061da546Spatrick         "\n   x8=%16.16llx"
204061da546Spatrick         "\n   x9=%16.16llx"
205061da546Spatrick         "\n  x10=%16.16llx"
206061da546Spatrick         "\n  x11=%16.16llx"
207061da546Spatrick         "\n  x12=%16.16llx"
208061da546Spatrick         "\n  x13=%16.16llx"
209061da546Spatrick         "\n  x14=%16.16llx"
210061da546Spatrick         "\n  x15=%16.16llx"
211061da546Spatrick         "\n  x16=%16.16llx"
212061da546Spatrick         "\n  x17=%16.16llx"
213061da546Spatrick         "\n  x18=%16.16llx"
214061da546Spatrick         "\n  x19=%16.16llx"
215061da546Spatrick         "\n  x20=%16.16llx"
216061da546Spatrick         "\n  x21=%16.16llx"
217061da546Spatrick         "\n  x22=%16.16llx"
218061da546Spatrick         "\n  x23=%16.16llx"
219061da546Spatrick         "\n  x24=%16.16llx"
220061da546Spatrick         "\n  x25=%16.16llx"
221061da546Spatrick         "\n  x26=%16.16llx"
222061da546Spatrick         "\n  x27=%16.16llx"
223061da546Spatrick         "\n  x28=%16.16llx"
224061da546Spatrick         "\n   fp=%16.16llx"
225061da546Spatrick         "\n   lr=%16.16llx"
226061da546Spatrick         "\n   sp=%16.16llx"
227061da546Spatrick         "\n   pc=%16.16llx"
228061da546Spatrick         "\n cpsr=%8.8x",
229061da546Spatrick         m_thread->MachPortNumber(), e_regSetGPR, e_regSetGPRCount, kret, count,
230061da546Spatrick         x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[0], x[11],
231061da546Spatrick         x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21],
232061da546Spatrick         x[22], x[23], x[24], x[25], x[26], x[27], x[28],
233be691f3bSpatrick         log_fp, log_lr, log_sp, log_pc, m_state.context.gpr.__cpsr);
234061da546Spatrick   }
235061da546Spatrick   m_state.SetError(set, Read, kret);
236061da546Spatrick   return kret;
237061da546Spatrick }
238061da546Spatrick 
GetVFPState(bool force)239061da546Spatrick kern_return_t DNBArchMachARM64::GetVFPState(bool force) {
240061da546Spatrick   int set = e_regSetVFP;
241061da546Spatrick   // Check if we have valid cached registers
242061da546Spatrick   if (!force && m_state.GetError(set, Read) == KERN_SUCCESS)
243061da546Spatrick     return KERN_SUCCESS;
244061da546Spatrick 
245061da546Spatrick   // Read the registers from our thread
246061da546Spatrick   mach_msg_type_number_t count = e_regSetVFPCount;
247061da546Spatrick   kern_return_t kret =
248061da546Spatrick       ::thread_get_state(m_thread->MachPortNumber(), ARM_NEON_STATE64,
249061da546Spatrick                          (thread_state_t)&m_state.context.vfp, &count);
250061da546Spatrick   if (DNBLogEnabledForAny(LOG_THREAD)) {
251061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
252061da546Spatrick     DNBLogThreaded(
253061da546Spatrick         "thread_get_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs"
254061da546Spatrick         "\n   q0  = 0x%16.16llx%16.16llx"
255061da546Spatrick         "\n   q1  = 0x%16.16llx%16.16llx"
256061da546Spatrick         "\n   q2  = 0x%16.16llx%16.16llx"
257061da546Spatrick         "\n   q3  = 0x%16.16llx%16.16llx"
258061da546Spatrick         "\n   q4  = 0x%16.16llx%16.16llx"
259061da546Spatrick         "\n   q5  = 0x%16.16llx%16.16llx"
260061da546Spatrick         "\n   q6  = 0x%16.16llx%16.16llx"
261061da546Spatrick         "\n   q7  = 0x%16.16llx%16.16llx"
262061da546Spatrick         "\n   q8  = 0x%16.16llx%16.16llx"
263061da546Spatrick         "\n   q9  = 0x%16.16llx%16.16llx"
264061da546Spatrick         "\n   q10 = 0x%16.16llx%16.16llx"
265061da546Spatrick         "\n   q11 = 0x%16.16llx%16.16llx"
266061da546Spatrick         "\n   q12 = 0x%16.16llx%16.16llx"
267061da546Spatrick         "\n   q13 = 0x%16.16llx%16.16llx"
268061da546Spatrick         "\n   q14 = 0x%16.16llx%16.16llx"
269061da546Spatrick         "\n   q15 = 0x%16.16llx%16.16llx"
270061da546Spatrick         "\n   q16 = 0x%16.16llx%16.16llx"
271061da546Spatrick         "\n   q17 = 0x%16.16llx%16.16llx"
272061da546Spatrick         "\n   q18 = 0x%16.16llx%16.16llx"
273061da546Spatrick         "\n   q19 = 0x%16.16llx%16.16llx"
274061da546Spatrick         "\n   q20 = 0x%16.16llx%16.16llx"
275061da546Spatrick         "\n   q21 = 0x%16.16llx%16.16llx"
276061da546Spatrick         "\n   q22 = 0x%16.16llx%16.16llx"
277061da546Spatrick         "\n   q23 = 0x%16.16llx%16.16llx"
278061da546Spatrick         "\n   q24 = 0x%16.16llx%16.16llx"
279061da546Spatrick         "\n   q25 = 0x%16.16llx%16.16llx"
280061da546Spatrick         "\n   q26 = 0x%16.16llx%16.16llx"
281061da546Spatrick         "\n   q27 = 0x%16.16llx%16.16llx"
282061da546Spatrick         "\n   q28 = 0x%16.16llx%16.16llx"
283061da546Spatrick         "\n   q29 = 0x%16.16llx%16.16llx"
284061da546Spatrick         "\n   q30 = 0x%16.16llx%16.16llx"
285061da546Spatrick         "\n   q31 = 0x%16.16llx%16.16llx"
286061da546Spatrick         "\n  fpsr = 0x%8.8x"
287061da546Spatrick         "\n  fpcr = 0x%8.8x\n\n",
288061da546Spatrick         m_thread->MachPortNumber(), e_regSetVFP, e_regSetVFPCount, kret, count,
289061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[0])[0],
290061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[0])[1],
291061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[1])[0],
292061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[1])[1],
293061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[2])[0],
294061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[2])[1],
295061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[3])[0],
296061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[3])[1],
297061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[4])[0],
298061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[4])[1],
299061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[5])[0],
300061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[5])[1],
301061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[6])[0],
302061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[6])[1],
303061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[7])[0],
304061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[7])[1],
305061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[8])[0],
306061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[8])[1],
307061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[9])[0],
308061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[9])[1],
309061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[10])[0],
310061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[10])[1],
311061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[11])[0],
312061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[11])[1],
313061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[12])[0],
314061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[12])[1],
315061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[13])[0],
316061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[13])[1],
317061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[14])[0],
318061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[14])[1],
319061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[15])[0],
320061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[15])[1],
321061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[16])[0],
322061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[16])[1],
323061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[17])[0],
324061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[17])[1],
325061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[18])[0],
326061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[18])[1],
327061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[19])[0],
328061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[19])[1],
329061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[20])[0],
330061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[20])[1],
331061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[21])[0],
332061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[21])[1],
333061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[22])[0],
334061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[22])[1],
335061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[23])[0],
336061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[23])[1],
337061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[24])[0],
338061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[24])[1],
339061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[25])[0],
340061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[25])[1],
341061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[26])[0],
342061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[26])[1],
343061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[27])[0],
344061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[27])[1],
345061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[28])[0],
346061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[28])[1],
347061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[29])[0],
348061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[29])[1],
349061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[30])[0],
350061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[30])[1],
351061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[31])[0],
352061da546Spatrick         ((uint64_t *)&m_state.context.vfp.__v[31])[1],
353061da546Spatrick         m_state.context.vfp.__fpsr, m_state.context.vfp.__fpcr);
354061da546Spatrick #endif
355061da546Spatrick   }
356061da546Spatrick   m_state.SetError(set, Read, kret);
357061da546Spatrick   return kret;
358061da546Spatrick }
359061da546Spatrick 
GetEXCState(bool force)360061da546Spatrick kern_return_t DNBArchMachARM64::GetEXCState(bool force) {
361061da546Spatrick   int set = e_regSetEXC;
362061da546Spatrick   // Check if we have valid cached registers
363061da546Spatrick   if (!force && m_state.GetError(set, Read) == KERN_SUCCESS)
364061da546Spatrick     return KERN_SUCCESS;
365061da546Spatrick 
366061da546Spatrick   // Read the registers from our thread
367061da546Spatrick   mach_msg_type_number_t count = e_regSetEXCCount;
368061da546Spatrick   kern_return_t kret =
369061da546Spatrick       ::thread_get_state(m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64,
370061da546Spatrick                          (thread_state_t)&m_state.context.exc, &count);
371061da546Spatrick   m_state.SetError(set, Read, kret);
372061da546Spatrick   return kret;
373061da546Spatrick }
374061da546Spatrick 
375be691f3bSpatrick #if 0
376061da546Spatrick static void DumpDBGState(const arm_debug_state_t &dbg) {
377061da546Spatrick   uint32_t i = 0;
378061da546Spatrick   for (i = 0; i < 16; i++)
379061da546Spatrick     DNBLogThreadedIf(LOG_STEP, "BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } "
380061da546Spatrick                                "WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }",
381061da546Spatrick                      i, i, dbg.__bvr[i], dbg.__bcr[i], i, i, dbg.__wvr[i],
382061da546Spatrick                      dbg.__wcr[i]);
383061da546Spatrick }
384be691f3bSpatrick #endif
385061da546Spatrick 
GetDBGState(bool force)386061da546Spatrick kern_return_t DNBArchMachARM64::GetDBGState(bool force) {
387061da546Spatrick   int set = e_regSetDBG;
388061da546Spatrick 
389061da546Spatrick   // Check if we have valid cached registers
390061da546Spatrick   if (!force && m_state.GetError(set, Read) == KERN_SUCCESS)
391061da546Spatrick     return KERN_SUCCESS;
392061da546Spatrick 
393061da546Spatrick   // Read the registers from our thread
394061da546Spatrick   mach_msg_type_number_t count = e_regSetDBGCount;
395061da546Spatrick   kern_return_t kret =
396061da546Spatrick       ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE64,
397061da546Spatrick                          (thread_state_t)&m_state.dbg, &count);
398061da546Spatrick   m_state.SetError(set, Read, kret);
399061da546Spatrick 
400061da546Spatrick   return kret;
401061da546Spatrick }
402061da546Spatrick 
SetGPRState()403061da546Spatrick kern_return_t DNBArchMachARM64::SetGPRState() {
404061da546Spatrick   int set = e_regSetGPR;
405061da546Spatrick   kern_return_t kret = ::thread_set_state(
406061da546Spatrick       m_thread->MachPortNumber(), ARM_THREAD_STATE64,
407061da546Spatrick       (thread_state_t)&m_state.context.gpr, e_regSetGPRCount);
408061da546Spatrick   m_state.SetError(set, Write,
409061da546Spatrick                    kret); // Set the current write error for this register set
410061da546Spatrick   m_state.InvalidateRegisterSetState(set); // Invalidate the current register
411061da546Spatrick                                            // state in case registers are read
412061da546Spatrick                                            // back differently
413061da546Spatrick   return kret;                             // Return the error code
414061da546Spatrick }
415061da546Spatrick 
SetVFPState()416061da546Spatrick kern_return_t DNBArchMachARM64::SetVFPState() {
417061da546Spatrick   int set = e_regSetVFP;
418061da546Spatrick   kern_return_t kret = ::thread_set_state(
419061da546Spatrick       m_thread->MachPortNumber(), ARM_NEON_STATE64,
420061da546Spatrick       (thread_state_t)&m_state.context.vfp, e_regSetVFPCount);
421061da546Spatrick   m_state.SetError(set, Write,
422061da546Spatrick                    kret); // Set the current write error for this register set
423061da546Spatrick   m_state.InvalidateRegisterSetState(set); // Invalidate the current register
424061da546Spatrick                                            // state in case registers are read
425061da546Spatrick                                            // back differently
426061da546Spatrick   return kret;                             // Return the error code
427061da546Spatrick }
428061da546Spatrick 
SetEXCState()429061da546Spatrick kern_return_t DNBArchMachARM64::SetEXCState() {
430061da546Spatrick   int set = e_regSetEXC;
431061da546Spatrick   kern_return_t kret = ::thread_set_state(
432061da546Spatrick       m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64,
433061da546Spatrick       (thread_state_t)&m_state.context.exc, e_regSetEXCCount);
434061da546Spatrick   m_state.SetError(set, Write,
435061da546Spatrick                    kret); // Set the current write error for this register set
436061da546Spatrick   m_state.InvalidateRegisterSetState(set); // Invalidate the current register
437061da546Spatrick                                            // state in case registers are read
438061da546Spatrick                                            // back differently
439061da546Spatrick   return kret;                             // Return the error code
440061da546Spatrick }
441061da546Spatrick 
SetDBGState(bool also_set_on_task)442061da546Spatrick kern_return_t DNBArchMachARM64::SetDBGState(bool also_set_on_task) {
443061da546Spatrick   int set = e_regSetDBG;
444061da546Spatrick   kern_return_t kret =
445061da546Spatrick       ::thread_set_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE64,
446061da546Spatrick                          (thread_state_t)&m_state.dbg, e_regSetDBGCount);
447061da546Spatrick   if (also_set_on_task) {
448061da546Spatrick     kern_return_t task_kret = task_set_state(
449061da546Spatrick         m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE64,
450061da546Spatrick         (thread_state_t)&m_state.dbg, e_regSetDBGCount);
451061da546Spatrick     if (task_kret != KERN_SUCCESS)
452061da546Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::SetDBGState failed "
453061da546Spatrick                                         "to set debug control register state: "
454061da546Spatrick                                         "0x%8.8x.",
455061da546Spatrick                        task_kret);
456061da546Spatrick   }
457061da546Spatrick   m_state.SetError(set, Write,
458061da546Spatrick                    kret); // Set the current write error for this register set
459061da546Spatrick   m_state.InvalidateRegisterSetState(set); // Invalidate the current register
460061da546Spatrick                                            // state in case registers are read
461061da546Spatrick                                            // back differently
462061da546Spatrick 
463061da546Spatrick   return kret; // Return the error code
464061da546Spatrick }
465061da546Spatrick 
ThreadWillResume()466061da546Spatrick void DNBArchMachARM64::ThreadWillResume() {
467061da546Spatrick   // Do we need to step this thread? If so, let the mach thread tell us so.
468061da546Spatrick   if (m_thread->IsStepping()) {
469061da546Spatrick     EnableHardwareSingleStep(true);
470061da546Spatrick   }
471061da546Spatrick 
472061da546Spatrick   // Disable the triggered watchpoint temporarily before we resume.
473061da546Spatrick   // Plus, we try to enable hardware single step to execute past the instruction
474061da546Spatrick   // which triggered our watchpoint.
475061da546Spatrick   if (m_watchpoint_did_occur) {
476061da546Spatrick     if (m_watchpoint_hw_index >= 0) {
477061da546Spatrick       kern_return_t kret = GetDBGState(false);
478061da546Spatrick       if (kret == KERN_SUCCESS &&
479061da546Spatrick           !IsWatchpointEnabled(m_state.dbg, m_watchpoint_hw_index)) {
480061da546Spatrick         // The watchpoint might have been disabled by the user.  We don't need
481061da546Spatrick         // to do anything at all
482061da546Spatrick         // to enable hardware single stepping.
483061da546Spatrick         m_watchpoint_did_occur = false;
484061da546Spatrick         m_watchpoint_hw_index = -1;
485061da546Spatrick         return;
486061da546Spatrick       }
487061da546Spatrick 
488061da546Spatrick       DisableHardwareWatchpoint(m_watchpoint_hw_index, false);
489061da546Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() "
490061da546Spatrick                                         "DisableHardwareWatchpoint(%d) called",
491061da546Spatrick                        m_watchpoint_hw_index);
492061da546Spatrick 
493061da546Spatrick       // Enable hardware single step to move past the watchpoint-triggering
494061da546Spatrick       // instruction.
495061da546Spatrick       m_watchpoint_resume_single_step_enabled =
496061da546Spatrick           (EnableHardwareSingleStep(true) == KERN_SUCCESS);
497061da546Spatrick 
498061da546Spatrick       // If we are not able to enable single step to move past the
499061da546Spatrick       // watchpoint-triggering instruction,
500061da546Spatrick       // at least we should reset the two watchpoint member variables so that
501061da546Spatrick       // the next time around
502061da546Spatrick       // this callback function is invoked, the enclosing logical branch is
503061da546Spatrick       // skipped.
504061da546Spatrick       if (!m_watchpoint_resume_single_step_enabled) {
505061da546Spatrick         // Reset the two watchpoint member variables.
506061da546Spatrick         m_watchpoint_did_occur = false;
507061da546Spatrick         m_watchpoint_hw_index = -1;
508061da546Spatrick         DNBLogThreadedIf(
509061da546Spatrick             LOG_WATCHPOINTS,
510061da546Spatrick             "DNBArchMachARM::ThreadWillResume() failed to enable single step");
511061da546Spatrick       } else
512061da546Spatrick         DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() "
513061da546Spatrick                                           "succeeded to enable single step");
514061da546Spatrick     }
515061da546Spatrick   }
516061da546Spatrick }
517061da546Spatrick 
NotifyException(MachException::Data & exc)518061da546Spatrick bool DNBArchMachARM64::NotifyException(MachException::Data &exc) {
519061da546Spatrick 
520061da546Spatrick   switch (exc.exc_type) {
521061da546Spatrick   default:
522061da546Spatrick     break;
523061da546Spatrick   case EXC_BREAKPOINT:
524061da546Spatrick     if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG) {
525061da546Spatrick       // The data break address is passed as exc_data[1].
526061da546Spatrick       nub_addr_t addr = exc.exc_data[1];
527061da546Spatrick       // Find the hardware index with the side effect of possibly massaging the
528061da546Spatrick       // addr to return the starting address as seen from the debugger side.
529061da546Spatrick       uint32_t hw_index = GetHardwareWatchpointHit(addr);
530061da546Spatrick 
531061da546Spatrick       // One logical watchpoint was split into two watchpoint locations because
532061da546Spatrick       // it was too big.  If the watchpoint exception is indicating the 2nd half
533061da546Spatrick       // of the two-parter, find the address of the 1st half and report that --
534061da546Spatrick       // that's what lldb is going to expect to see.
535061da546Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException "
536061da546Spatrick                                         "watchpoint %d was hit on address "
537061da546Spatrick                                         "0x%llx",
538061da546Spatrick                        hw_index, (uint64_t)addr);
539be691f3bSpatrick       const uint32_t num_watchpoints = NumSupportedHardwareWatchpoints();
540be691f3bSpatrick       for (uint32_t i = 0; i < num_watchpoints; i++) {
541061da546Spatrick         if (LoHi[i] != 0 && LoHi[i] == hw_index && LoHi[i] != i &&
542061da546Spatrick             GetWatchpointAddressByIndex(i) != INVALID_NUB_ADDRESS) {
543061da546Spatrick           addr = GetWatchpointAddressByIndex(i);
544061da546Spatrick           DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException "
545061da546Spatrick                                             "It is a linked watchpoint; "
546061da546Spatrick                                             "rewritten to index %d addr 0x%llx",
547061da546Spatrick                            LoHi[i], (uint64_t)addr);
548061da546Spatrick         }
549061da546Spatrick       }
550061da546Spatrick 
551061da546Spatrick       if (hw_index != INVALID_NUB_HW_INDEX) {
552061da546Spatrick         m_watchpoint_did_occur = true;
553061da546Spatrick         m_watchpoint_hw_index = hw_index;
554061da546Spatrick         exc.exc_data[1] = addr;
555061da546Spatrick         // Piggyback the hw_index in the exc.data.
556061da546Spatrick         exc.exc_data.push_back(hw_index);
557061da546Spatrick       }
558061da546Spatrick 
559061da546Spatrick       return true;
560061da546Spatrick     }
561be691f3bSpatrick     // detect a __builtin_debugtrap instruction pattern ("brk #0xf000")
562be691f3bSpatrick     // and advance the $pc past it, so that the user can continue execution.
563be691f3bSpatrick     // Generally speaking, this knowledge should be centralized in lldb,
564be691f3bSpatrick     // recognizing the builtin_trap instruction and knowing how to advance
565be691f3bSpatrick     // the pc past it, so that continue etc work.
566be691f3bSpatrick     if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_BREAKPOINT) {
567be691f3bSpatrick       nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS);
568be691f3bSpatrick       if (pc != INVALID_NUB_ADDRESS && pc > 0) {
569be691f3bSpatrick         DNBBreakpoint *bp =
570be691f3bSpatrick             m_thread->Process()->Breakpoints().FindByAddress(pc);
571be691f3bSpatrick         if (bp == nullptr) {
572be691f3bSpatrick           uint8_t insnbuf[4];
573be691f3bSpatrick           if (m_thread->Process()->ReadMemory(pc, 4, insnbuf) == 4) {
574be691f3bSpatrick             uint8_t builtin_debugtrap_insn[4] = {0x00, 0x00, 0x3e,
575be691f3bSpatrick                                                  0xd4}; // brk #0xf000
576be691f3bSpatrick             if (memcmp(insnbuf, builtin_debugtrap_insn, 4) == 0) {
577be691f3bSpatrick               SetPC(pc + 4);
578be691f3bSpatrick             }
579be691f3bSpatrick           }
580be691f3bSpatrick         }
581be691f3bSpatrick       }
582be691f3bSpatrick     }
583061da546Spatrick     break;
584061da546Spatrick   }
585061da546Spatrick   return false;
586061da546Spatrick }
587061da546Spatrick 
ThreadDidStop()588061da546Spatrick bool DNBArchMachARM64::ThreadDidStop() {
589061da546Spatrick   bool success = true;
590061da546Spatrick 
591061da546Spatrick   m_state.InvalidateAllRegisterStates();
592061da546Spatrick 
593061da546Spatrick   if (m_watchpoint_resume_single_step_enabled) {
594061da546Spatrick     // Great!  We now disable the hardware single step as well as re-enable the
595061da546Spatrick     // hardware watchpoint.
596061da546Spatrick     // See also ThreadWillResume().
597061da546Spatrick     if (EnableHardwareSingleStep(false) == KERN_SUCCESS) {
598061da546Spatrick       if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) {
599061da546Spatrick         ReenableHardwareWatchpoint(m_watchpoint_hw_index);
600061da546Spatrick         m_watchpoint_resume_single_step_enabled = false;
601061da546Spatrick         m_watchpoint_did_occur = false;
602061da546Spatrick         m_watchpoint_hw_index = -1;
603061da546Spatrick       } else {
604061da546Spatrick         DNBLogError("internal error detected: m_watchpoint_resume_step_enabled "
605061da546Spatrick                     "is true but (m_watchpoint_did_occur && "
606061da546Spatrick                     "m_watchpoint_hw_index >= 0) does not hold!");
607061da546Spatrick       }
608061da546Spatrick     } else {
609061da546Spatrick       DNBLogError("internal error detected: m_watchpoint_resume_step_enabled "
610061da546Spatrick                   "is true but unable to disable single step!");
611061da546Spatrick     }
612061da546Spatrick   }
613061da546Spatrick 
614061da546Spatrick   // Are we stepping a single instruction?
615061da546Spatrick   if (GetGPRState(true) == KERN_SUCCESS) {
616061da546Spatrick     // We are single stepping, was this the primary thread?
617061da546Spatrick     if (m_thread->IsStepping()) {
618061da546Spatrick       // This was the primary thread, we need to clear the trace
619061da546Spatrick       // bit if so.
620061da546Spatrick       success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
621061da546Spatrick     } else {
622061da546Spatrick       // The MachThread will automatically restore the suspend count
623061da546Spatrick       // in ThreadDidStop(), so we don't need to do anything here if
624061da546Spatrick       // we weren't the primary thread the last time
625061da546Spatrick     }
626061da546Spatrick   }
627061da546Spatrick   return success;
628061da546Spatrick }
629061da546Spatrick 
630061da546Spatrick // Set the single step bit in the processor status register.
EnableHardwareSingleStep(bool enable)631061da546Spatrick kern_return_t DNBArchMachARM64::EnableHardwareSingleStep(bool enable) {
632061da546Spatrick   DNBError err;
633061da546Spatrick   DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable);
634061da546Spatrick 
635061da546Spatrick   err = GetGPRState(false);
636061da546Spatrick 
637061da546Spatrick   if (err.Fail()) {
638061da546Spatrick     err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__);
639061da546Spatrick     return err.Status();
640061da546Spatrick   }
641061da546Spatrick 
642061da546Spatrick   err = GetDBGState(false);
643061da546Spatrick 
644061da546Spatrick   if (err.Fail()) {
645061da546Spatrick     err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__);
646061da546Spatrick     return err.Status();
647061da546Spatrick   }
648061da546Spatrick 
649*f6aab3d8Srobert #if __has_feature(ptrauth_calls) && defined(__LP64__)
650*f6aab3d8Srobert   uint64_t pc = clear_pac_bits(
651*f6aab3d8Srobert       reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc));
652dda28197Spatrick #else
653dda28197Spatrick   uint64_t pc = m_state.context.gpr.__pc;
654dda28197Spatrick #endif
655dda28197Spatrick 
656061da546Spatrick   if (enable) {
657061da546Spatrick     DNBLogThreadedIf(LOG_STEP,
658061da546Spatrick                      "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx",
659dda28197Spatrick                      __FUNCTION__, pc);
660061da546Spatrick     m_state.dbg.__mdscr_el1 |= SS_ENABLE;
661061da546Spatrick   } else {
662061da546Spatrick     DNBLogThreadedIf(LOG_STEP,
663061da546Spatrick                      "%s: Clearing MDSCR_EL1 Single Step bit at pc 0x%llx",
664dda28197Spatrick                      __FUNCTION__, pc);
665061da546Spatrick     m_state.dbg.__mdscr_el1 &= ~(SS_ENABLE);
666061da546Spatrick   }
667061da546Spatrick 
668061da546Spatrick   return SetDBGState(false);
669061da546Spatrick }
670061da546Spatrick 
671061da546Spatrick // return 1 if bit "BIT" is set in "value"
bit(uint32_t value,uint32_t bit)672061da546Spatrick static inline uint32_t bit(uint32_t value, uint32_t bit) {
673061da546Spatrick   return (value >> bit) & 1u;
674061da546Spatrick }
675061da546Spatrick 
676061da546Spatrick // return the bitfield "value[msbit:lsbit]".
bits(uint64_t value,uint32_t msbit,uint32_t lsbit)677061da546Spatrick static inline uint64_t bits(uint64_t value, uint32_t msbit, uint32_t lsbit) {
678061da546Spatrick   assert(msbit >= lsbit);
679061da546Spatrick   uint64_t shift_left = sizeof(value) * 8 - 1 - msbit;
680061da546Spatrick   value <<=
681061da546Spatrick       shift_left; // shift anything above the msbit off of the unsigned edge
682061da546Spatrick   value >>= shift_left + lsbit; // shift it back again down to the lsbit
683061da546Spatrick                                 // (including undoing any shift from above)
684061da546Spatrick   return value;                 // return our result
685061da546Spatrick }
686061da546Spatrick 
NumSupportedHardwareWatchpoints()687061da546Spatrick uint32_t DNBArchMachARM64::NumSupportedHardwareWatchpoints() {
688061da546Spatrick   // Set the init value to something that will let us know that we need to
689061da546Spatrick   // autodetect how many watchpoints are supported dynamically...
690061da546Spatrick   static uint32_t g_num_supported_hw_watchpoints = UINT_MAX;
691061da546Spatrick   if (g_num_supported_hw_watchpoints == UINT_MAX) {
692061da546Spatrick     // Set this to zero in case we can't tell if there are any HW breakpoints
693061da546Spatrick     g_num_supported_hw_watchpoints = 0;
694061da546Spatrick 
695061da546Spatrick     size_t len;
696061da546Spatrick     uint32_t n = 0;
697061da546Spatrick     len = sizeof(n);
698061da546Spatrick     if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) {
699061da546Spatrick       g_num_supported_hw_watchpoints = n;
700061da546Spatrick       DNBLogThreadedIf(LOG_THREAD, "hw.optional.watchpoint=%u", n);
701061da546Spatrick     } else {
702061da546Spatrick // For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in
703061da546Spatrick // EL0 so it can't
704061da546Spatrick // access that reg.  The kernel should have filled in the sysctls based on it
705061da546Spatrick // though.
706061da546Spatrick #if defined(__arm__)
707061da546Spatrick       uint32_t register_DBGDIDR;
708061da546Spatrick 
709061da546Spatrick       asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR));
710061da546Spatrick       uint32_t numWRPs = bits(register_DBGDIDR, 31, 28);
711061da546Spatrick       // Zero is reserved for the WRP count, so don't increment it if it is zero
712061da546Spatrick       if (numWRPs > 0)
713061da546Spatrick         numWRPs++;
714061da546Spatrick       g_num_supported_hw_watchpoints = numWRPs;
715061da546Spatrick       DNBLogThreadedIf(LOG_THREAD,
716061da546Spatrick                        "Number of supported hw watchpoints via asm():  %d",
717061da546Spatrick                        g_num_supported_hw_watchpoints);
718061da546Spatrick #endif
719061da546Spatrick     }
720061da546Spatrick   }
721061da546Spatrick   return g_num_supported_hw_watchpoints;
722061da546Spatrick }
723061da546Spatrick 
NumSupportedHardwareBreakpoints()724dda28197Spatrick uint32_t DNBArchMachARM64::NumSupportedHardwareBreakpoints() {
725dda28197Spatrick   // Set the init value to something that will let us know that we need to
726dda28197Spatrick   // autodetect how many breakpoints are supported dynamically...
727dda28197Spatrick   static uint32_t g_num_supported_hw_breakpoints = UINT_MAX;
728dda28197Spatrick   if (g_num_supported_hw_breakpoints == UINT_MAX) {
729dda28197Spatrick     // Set this to zero in case we can't tell if there are any HW breakpoints
730dda28197Spatrick     g_num_supported_hw_breakpoints = 0;
731dda28197Spatrick 
732dda28197Spatrick     size_t len;
733dda28197Spatrick     uint32_t n = 0;
734dda28197Spatrick     len = sizeof(n);
735dda28197Spatrick     if (::sysctlbyname("hw.optional.breakpoint", &n, &len, NULL, 0) == 0) {
736dda28197Spatrick       g_num_supported_hw_breakpoints = n;
737dda28197Spatrick       DNBLogThreadedIf(LOG_THREAD, "hw.optional.breakpoint=%u", n);
738dda28197Spatrick     } else {
739dda28197Spatrick // For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in
740dda28197Spatrick // EL0 so it can't access that reg.  The kernel should have filled in the
741dda28197Spatrick // sysctls based on it though.
742dda28197Spatrick #if defined(__arm__)
743dda28197Spatrick       uint32_t register_DBGDIDR;
744dda28197Spatrick 
745dda28197Spatrick       asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR));
746dda28197Spatrick       uint32_t numWRPs = bits(register_DBGDIDR, 31, 28);
747dda28197Spatrick       // Zero is reserved for the WRP count, so don't increment it if it is zero
748dda28197Spatrick       if (numWRPs > 0)
749dda28197Spatrick         numWRPs++;
750dda28197Spatrick       g_num_supported_hw_breakpoints = numWRPs;
751dda28197Spatrick       DNBLogThreadedIf(LOG_THREAD,
752dda28197Spatrick                        "Number of supported hw breakpoint via asm():  %d",
753dda28197Spatrick                        g_num_supported_hw_breakpoints);
754dda28197Spatrick #endif
755dda28197Spatrick     }
756dda28197Spatrick   }
757dda28197Spatrick   return g_num_supported_hw_breakpoints;
758dda28197Spatrick }
759dda28197Spatrick 
EnableHardwareBreakpoint(nub_addr_t addr,nub_size_t size,bool also_set_on_task)760dda28197Spatrick uint32_t DNBArchMachARM64::EnableHardwareBreakpoint(nub_addr_t addr,
761dda28197Spatrick                                                     nub_size_t size,
762dda28197Spatrick                                                     bool also_set_on_task) {
763dda28197Spatrick   DNBLogThreadedIf(LOG_WATCHPOINTS,
764dda28197Spatrick                    "DNBArchMachARM64::EnableHardwareBreakpoint(addr = "
765dda28197Spatrick                    "0x%8.8llx, size = %zu)",
766dda28197Spatrick                    (uint64_t)addr, size);
767dda28197Spatrick 
768dda28197Spatrick   const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints();
769dda28197Spatrick 
770dda28197Spatrick   nub_addr_t aligned_bp_address = addr;
771dda28197Spatrick   uint32_t control_value = 0;
772dda28197Spatrick 
773dda28197Spatrick   switch (size) {
774dda28197Spatrick   case 2:
775dda28197Spatrick     control_value = (0x3 << 5) | 7;
776dda28197Spatrick     aligned_bp_address &= ~1;
777dda28197Spatrick     break;
778dda28197Spatrick   case 4:
779dda28197Spatrick     control_value = (0xfu << 5) | 7;
780dda28197Spatrick     aligned_bp_address &= ~3;
781dda28197Spatrick     break;
782dda28197Spatrick   };
783dda28197Spatrick 
784dda28197Spatrick   // Read the debug state
785dda28197Spatrick   kern_return_t kret = GetDBGState(false);
786dda28197Spatrick   if (kret == KERN_SUCCESS) {
787dda28197Spatrick     // Check to make sure we have the needed hardware support
788dda28197Spatrick     uint32_t i = 0;
789dda28197Spatrick 
790dda28197Spatrick     for (i = 0; i < num_hw_breakpoints; ++i) {
791dda28197Spatrick       if ((m_state.dbg.__bcr[i] & BCR_ENABLE) == 0)
792dda28197Spatrick         break; // We found an available hw breakpoint slot (in i)
793dda28197Spatrick     }
794dda28197Spatrick 
795dda28197Spatrick     // See if we found an available hw breakpoint slot above
796dda28197Spatrick     if (i < num_hw_breakpoints) {
797dda28197Spatrick       m_state.dbg.__bvr[i] = aligned_bp_address;
798dda28197Spatrick       m_state.dbg.__bcr[i] = control_value;
799dda28197Spatrick 
800dda28197Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS,
801dda28197Spatrick                        "DNBArchMachARM64::EnableHardwareBreakpoint() "
802dda28197Spatrick                        "adding breakpoint on address 0x%llx with control "
803dda28197Spatrick                        "register value 0x%x",
804dda28197Spatrick                        (uint64_t)m_state.dbg.__bvr[i],
805dda28197Spatrick                        (uint32_t)m_state.dbg.__bcr[i]);
806dda28197Spatrick 
807dda28197Spatrick       // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us
808dda28197Spatrick       // automatically, don't need to do it here.
809dda28197Spatrick       kret = SetDBGState(also_set_on_task);
810dda28197Spatrick 
811dda28197Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS,
812dda28197Spatrick                        "DNBArchMachARM64::"
813dda28197Spatrick                        "EnableHardwareBreakpoint() "
814dda28197Spatrick                        "SetDBGState() => 0x%8.8x.",
815dda28197Spatrick                        kret);
816dda28197Spatrick 
817dda28197Spatrick       if (kret == KERN_SUCCESS)
818dda28197Spatrick         return i;
819dda28197Spatrick     } else {
820dda28197Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS,
821dda28197Spatrick                        "DNBArchMachARM64::"
822dda28197Spatrick                        "EnableHardwareBreakpoint(): All "
823dda28197Spatrick                        "hardware resources (%u) are in use.",
824dda28197Spatrick                        num_hw_breakpoints);
825dda28197Spatrick     }
826dda28197Spatrick   }
827dda28197Spatrick   return INVALID_NUB_HW_INDEX;
828dda28197Spatrick }
829dda28197Spatrick 
EnableHardwareWatchpoint(nub_addr_t addr,nub_size_t size,bool read,bool write,bool also_set_on_task)830061da546Spatrick uint32_t DNBArchMachARM64::EnableHardwareWatchpoint(nub_addr_t addr,
831061da546Spatrick                                                     nub_size_t size, bool read,
832061da546Spatrick                                                     bool write,
833061da546Spatrick                                                     bool also_set_on_task) {
834061da546Spatrick   DNBLogThreadedIf(LOG_WATCHPOINTS,
835061da546Spatrick                    "DNBArchMachARM64::EnableHardwareWatchpoint(addr = "
836061da546Spatrick                    "0x%8.8llx, size = %zu, read = %u, write = %u)",
837061da546Spatrick                    (uint64_t)addr, size, read, write);
838061da546Spatrick 
839061da546Spatrick   const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
840061da546Spatrick 
841061da546Spatrick   // Can't watch zero bytes
842061da546Spatrick   if (size == 0)
843061da546Spatrick     return INVALID_NUB_HW_INDEX;
844061da546Spatrick 
845061da546Spatrick   // We must watch for either read or write
846061da546Spatrick   if (read == false && write == false)
847061da546Spatrick     return INVALID_NUB_HW_INDEX;
848061da546Spatrick 
849061da546Spatrick   // Otherwise, can't watch more than 8 bytes per WVR/WCR pair
850061da546Spatrick   if (size > 8)
851061da546Spatrick     return INVALID_NUB_HW_INDEX;
852061da546Spatrick 
853061da546Spatrick   // Aarch64 watchpoints are in one of two forms: (1) 1-8 bytes, aligned to
854061da546Spatrick   // an 8 byte address, or (2) a power-of-two size region of memory; minimum
855061da546Spatrick   // 8 bytes, maximum 2GB; the starting address must be aligned to that power
856061da546Spatrick   // of two.
857061da546Spatrick   //
858061da546Spatrick   // For (1), 1-8 byte watchpoints, using the Byte Address Selector field in
859061da546Spatrick   // DBGWCR<n>.BAS.  Any of the bytes may be watched, but if multiple bytes
860061da546Spatrick   // are watched, the bytes selected must be contiguous.  The start address
861061da546Spatrick   // watched must be doubleword (8-byte) aligned; if the start address is
862061da546Spatrick   // word (4-byte) aligned, only 4 bytes can be watched.
863061da546Spatrick   //
864061da546Spatrick   // For (2), the MASK field in DBGWCR<n>.MASK is used.
865061da546Spatrick   //
866061da546Spatrick   // See the ARM ARM, section "Watchpoint exceptions", and more specifically,
867061da546Spatrick   // "Watchpoint data address comparisons".
868061da546Spatrick   //
869061da546Spatrick   // debugserver today only supports (1) - the Byte Address Selector 1-8 byte
870061da546Spatrick   // watchpoints that are 8-byte aligned.  To support larger watchpoints,
871061da546Spatrick   // debugserver would need to interpret the mach exception when the watched
872061da546Spatrick   // region was hit, see if the address accessed lies within the subset
873061da546Spatrick   // of the power-of-two region that lldb asked us to watch (v. ARM ARM,
874061da546Spatrick   // "Determining the memory location that caused a Watchpoint exception"),
875061da546Spatrick   // and silently resume the inferior (disable watchpoint, stepi, re-enable
876061da546Spatrick   // watchpoint) if the address lies outside the region that lldb asked us
877061da546Spatrick   // to watch.
878061da546Spatrick   //
879061da546Spatrick   // Alternatively, lldb would need to be prepared for a larger region
880061da546Spatrick   // being watched than it requested, and silently resume the inferior if
881061da546Spatrick   // the accessed address is outside the region lldb wants to watch.
882061da546Spatrick 
883061da546Spatrick   nub_addr_t aligned_wp_address = addr & ~0x7;
884061da546Spatrick   uint32_t addr_dword_offset = addr & 0x7;
885061da546Spatrick 
886061da546Spatrick   // Do we need to split up this logical watchpoint into two hardware watchpoint
887061da546Spatrick   // registers?
888061da546Spatrick   // e.g. a watchpoint of length 4 on address 6.  We need do this with
889061da546Spatrick   //   one watchpoint on address 0 with bytes 6 & 7 being monitored
890061da546Spatrick   //   one watchpoint on address 8 with bytes 0, 1, 2, 3 being monitored
891061da546Spatrick 
892061da546Spatrick   if (addr_dword_offset + size > 8) {
893061da546Spatrick     DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::"
894061da546Spatrick                                       "EnableHardwareWatchpoint(addr = "
895061da546Spatrick                                       "0x%8.8llx, size = %zu) needs two "
896061da546Spatrick                                       "hardware watchpoints slots to monitor",
897061da546Spatrick                      (uint64_t)addr, size);
898061da546Spatrick     int low_watchpoint_size = 8 - addr_dword_offset;
899061da546Spatrick     int high_watchpoint_size = addr_dword_offset + size - 8;
900061da546Spatrick 
901061da546Spatrick     uint32_t lo = EnableHardwareWatchpoint(addr, low_watchpoint_size, read,
902061da546Spatrick                                            write, also_set_on_task);
903061da546Spatrick     if (lo == INVALID_NUB_HW_INDEX)
904061da546Spatrick       return INVALID_NUB_HW_INDEX;
905061da546Spatrick     uint32_t hi =
906061da546Spatrick         EnableHardwareWatchpoint(aligned_wp_address + 8, high_watchpoint_size,
907061da546Spatrick                                  read, write, also_set_on_task);
908061da546Spatrick     if (hi == INVALID_NUB_HW_INDEX) {
909061da546Spatrick       DisableHardwareWatchpoint(lo, also_set_on_task);
910061da546Spatrick       return INVALID_NUB_HW_INDEX;
911061da546Spatrick     }
912061da546Spatrick     // Tag this lo->hi mapping in our database.
913061da546Spatrick     LoHi[lo] = hi;
914061da546Spatrick     return lo;
915061da546Spatrick   }
916061da546Spatrick 
917061da546Spatrick   // At this point
918061da546Spatrick   //  1 aligned_wp_address is the requested address rounded down to 8-byte
919061da546Spatrick   //  alignment
920061da546Spatrick   //  2 addr_dword_offset is the offset into that double word (8-byte) region
921061da546Spatrick   //  that we are watching
922061da546Spatrick   //  3 size is the number of bytes within that 8-byte region that we are
923061da546Spatrick   //  watching
924061da546Spatrick 
925061da546Spatrick   // Set the Byte Address Selects bits DBGWCRn_EL1 bits [12:5] based on the
926061da546Spatrick   // above.
927061da546Spatrick   // The bit shift and negation operation will give us 0b11 for 2, 0b1111 for 4,
928061da546Spatrick   // etc, up to 0b11111111 for 8.
929061da546Spatrick   // then we shift those bits left by the offset into this dword that we are
930061da546Spatrick   // interested in.
931061da546Spatrick   // e.g. if we are watching bytes 4,5,6,7 in a dword we want a BAS of
932061da546Spatrick   // 0b11110000.
933061da546Spatrick   uint32_t byte_address_select = ((1 << size) - 1) << addr_dword_offset;
934061da546Spatrick 
935061da546Spatrick   // Read the debug state
936061da546Spatrick   kern_return_t kret = GetDBGState(false);
937061da546Spatrick 
938061da546Spatrick   if (kret == KERN_SUCCESS) {
939061da546Spatrick     // Check to make sure we have the needed hardware support
940061da546Spatrick     uint32_t i = 0;
941061da546Spatrick 
942061da546Spatrick     for (i = 0; i < num_hw_watchpoints; ++i) {
943061da546Spatrick       if ((m_state.dbg.__wcr[i] & WCR_ENABLE) == 0)
944061da546Spatrick         break; // We found an available hw watchpoint slot (in i)
945061da546Spatrick     }
946061da546Spatrick 
947061da546Spatrick     // See if we found an available hw watchpoint slot above
948061da546Spatrick     if (i < num_hw_watchpoints) {
949061da546Spatrick       // DumpDBGState(m_state.dbg);
950061da546Spatrick 
951061da546Spatrick       // Clear any previous LoHi joined-watchpoint that may have been in use
952061da546Spatrick       LoHi[i] = 0;
953061da546Spatrick 
954061da546Spatrick       // shift our Byte Address Select bits up to the correct bit range for the
955061da546Spatrick       // DBGWCRn_EL1
956061da546Spatrick       byte_address_select = byte_address_select << 5;
957061da546Spatrick 
958061da546Spatrick       // Make sure bits 1:0 are clear in our address
959061da546Spatrick       m_state.dbg.__wvr[i] = aligned_wp_address;   // DVA (Data Virtual Address)
960061da546Spatrick       m_state.dbg.__wcr[i] = byte_address_select | // Which bytes that follow
961061da546Spatrick                                                    // the DVA that we will watch
962061da546Spatrick                              S_USER |              // Stop only in user mode
963061da546Spatrick                              (read ? WCR_LOAD : 0) |   // Stop on read access?
964061da546Spatrick                              (write ? WCR_STORE : 0) | // Stop on write access?
965061da546Spatrick                              WCR_ENABLE; // Enable this watchpoint;
966061da546Spatrick 
967061da546Spatrick       DNBLogThreadedIf(
968061da546Spatrick           LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint() "
969061da546Spatrick                            "adding watchpoint on address 0x%llx with control "
970061da546Spatrick                            "register value 0x%x",
971061da546Spatrick           (uint64_t)m_state.dbg.__wvr[i], (uint32_t)m_state.dbg.__wcr[i]);
972061da546Spatrick 
973061da546Spatrick       // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us
974061da546Spatrick       // automatically, don't need to do it here.
975061da546Spatrick 
976061da546Spatrick       kret = SetDBGState(also_set_on_task);
977061da546Spatrick       // DumpDBGState(m_state.dbg);
978061da546Spatrick 
979061da546Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::"
980061da546Spatrick                                         "EnableHardwareWatchpoint() "
981061da546Spatrick                                         "SetDBGState() => 0x%8.8x.",
982061da546Spatrick                        kret);
983061da546Spatrick 
984061da546Spatrick       if (kret == KERN_SUCCESS)
985061da546Spatrick         return i;
986061da546Spatrick     } else {
987061da546Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::"
988061da546Spatrick                                         "EnableHardwareWatchpoint(): All "
989061da546Spatrick                                         "hardware resources (%u) are in use.",
990061da546Spatrick                        num_hw_watchpoints);
991061da546Spatrick     }
992061da546Spatrick   }
993061da546Spatrick   return INVALID_NUB_HW_INDEX;
994061da546Spatrick }
995061da546Spatrick 
ReenableHardwareWatchpoint(uint32_t hw_index)996061da546Spatrick bool DNBArchMachARM64::ReenableHardwareWatchpoint(uint32_t hw_index) {
997061da546Spatrick   // If this logical watchpoint # is actually implemented using
998061da546Spatrick   // two hardware watchpoint registers, re-enable both of them.
999061da546Spatrick 
1000061da546Spatrick   if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) {
1001061da546Spatrick     return ReenableHardwareWatchpoint_helper(hw_index) &&
1002061da546Spatrick            ReenableHardwareWatchpoint_helper(LoHi[hw_index]);
1003061da546Spatrick   } else {
1004061da546Spatrick     return ReenableHardwareWatchpoint_helper(hw_index);
1005061da546Spatrick   }
1006061da546Spatrick }
1007061da546Spatrick 
ReenableHardwareWatchpoint_helper(uint32_t hw_index)1008061da546Spatrick bool DNBArchMachARM64::ReenableHardwareWatchpoint_helper(uint32_t hw_index) {
1009061da546Spatrick   kern_return_t kret = GetDBGState(false);
1010061da546Spatrick   if (kret != KERN_SUCCESS)
1011061da546Spatrick     return false;
1012061da546Spatrick 
1013061da546Spatrick   const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
1014061da546Spatrick   if (hw_index >= num_hw_points)
1015061da546Spatrick     return false;
1016061da546Spatrick 
1017061da546Spatrick   m_state.dbg.__wvr[hw_index] = m_disabled_watchpoints[hw_index].addr;
1018061da546Spatrick   m_state.dbg.__wcr[hw_index] = m_disabled_watchpoints[hw_index].control;
1019061da546Spatrick 
1020061da546Spatrick   DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::"
1021061da546Spatrick                                     "EnableHardwareWatchpoint( %u ) - WVR%u = "
1022061da546Spatrick                                     "0x%8.8llx  WCR%u = 0x%8.8llx",
1023061da546Spatrick                    hw_index, hw_index, (uint64_t)m_state.dbg.__wvr[hw_index],
1024061da546Spatrick                    hw_index, (uint64_t)m_state.dbg.__wcr[hw_index]);
1025061da546Spatrick 
1026061da546Spatrick   // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us
1027061da546Spatrick   // automatically, don't need to do it here.
1028061da546Spatrick 
1029061da546Spatrick   kret = SetDBGState(false);
1030061da546Spatrick 
1031061da546Spatrick   return (kret == KERN_SUCCESS);
1032061da546Spatrick }
1033061da546Spatrick 
DisableHardwareWatchpoint(uint32_t hw_index,bool also_set_on_task)1034061da546Spatrick bool DNBArchMachARM64::DisableHardwareWatchpoint(uint32_t hw_index,
1035061da546Spatrick                                                  bool also_set_on_task) {
1036061da546Spatrick   if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) {
1037061da546Spatrick     return DisableHardwareWatchpoint_helper(hw_index, also_set_on_task) &&
1038061da546Spatrick            DisableHardwareWatchpoint_helper(LoHi[hw_index], also_set_on_task);
1039061da546Spatrick   } else {
1040061da546Spatrick     return DisableHardwareWatchpoint_helper(hw_index, also_set_on_task);
1041061da546Spatrick   }
1042061da546Spatrick }
1043061da546Spatrick 
DisableHardwareWatchpoint_helper(uint32_t hw_index,bool also_set_on_task)1044061da546Spatrick bool DNBArchMachARM64::DisableHardwareWatchpoint_helper(uint32_t hw_index,
1045061da546Spatrick                                                         bool also_set_on_task) {
1046061da546Spatrick   kern_return_t kret = GetDBGState(false);
1047061da546Spatrick   if (kret != KERN_SUCCESS)
1048061da546Spatrick     return false;
1049061da546Spatrick 
1050061da546Spatrick   const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
1051061da546Spatrick   if (hw_index >= num_hw_points)
1052061da546Spatrick     return false;
1053061da546Spatrick 
1054061da546Spatrick   m_disabled_watchpoints[hw_index].addr = m_state.dbg.__wvr[hw_index];
1055061da546Spatrick   m_disabled_watchpoints[hw_index].control = m_state.dbg.__wcr[hw_index];
1056061da546Spatrick 
1057061da546Spatrick   m_state.dbg.__wcr[hw_index] &= ~((nub_addr_t)WCR_ENABLE);
1058061da546Spatrick   DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::"
1059061da546Spatrick                                     "DisableHardwareWatchpoint( %u ) - WVR%u = "
1060061da546Spatrick                                     "0x%8.8llx  WCR%u = 0x%8.8llx",
1061061da546Spatrick                    hw_index, hw_index, (uint64_t)m_state.dbg.__wvr[hw_index],
1062061da546Spatrick                    hw_index, (uint64_t)m_state.dbg.__wcr[hw_index]);
1063061da546Spatrick 
1064061da546Spatrick   kret = SetDBGState(also_set_on_task);
1065061da546Spatrick 
1066061da546Spatrick   return (kret == KERN_SUCCESS);
1067061da546Spatrick }
1068061da546Spatrick 
DisableHardwareBreakpoint(uint32_t hw_index,bool also_set_on_task)1069dda28197Spatrick bool DNBArchMachARM64::DisableHardwareBreakpoint(uint32_t hw_index,
1070dda28197Spatrick                                                  bool also_set_on_task) {
1071dda28197Spatrick   kern_return_t kret = GetDBGState(false);
1072dda28197Spatrick   if (kret != KERN_SUCCESS)
1073dda28197Spatrick     return false;
1074dda28197Spatrick 
1075dda28197Spatrick   const uint32_t num_hw_points = NumSupportedHardwareBreakpoints();
1076dda28197Spatrick   if (hw_index >= num_hw_points)
1077dda28197Spatrick     return false;
1078dda28197Spatrick 
1079dda28197Spatrick   m_disabled_breakpoints[hw_index].addr = m_state.dbg.__bvr[hw_index];
1080dda28197Spatrick   m_disabled_breakpoints[hw_index].control = m_state.dbg.__bcr[hw_index];
1081dda28197Spatrick 
1082dda28197Spatrick   m_state.dbg.__bcr[hw_index] = 0;
1083dda28197Spatrick   DNBLogThreadedIf(LOG_WATCHPOINTS,
1084dda28197Spatrick                    "DNBArchMachARM64::"
1085dda28197Spatrick                    "DisableHardwareBreakpoint( %u ) - WVR%u = "
1086dda28197Spatrick                    "0x%8.8llx  BCR%u = 0x%8.8llx",
1087dda28197Spatrick                    hw_index, hw_index, (uint64_t)m_state.dbg.__bvr[hw_index],
1088dda28197Spatrick                    hw_index, (uint64_t)m_state.dbg.__bcr[hw_index]);
1089dda28197Spatrick 
1090dda28197Spatrick   kret = SetDBGState(also_set_on_task);
1091dda28197Spatrick 
1092dda28197Spatrick   return (kret == KERN_SUCCESS);
1093dda28197Spatrick }
1094dda28197Spatrick 
1095061da546Spatrick // This is for checking the Byte Address Select bits in the DBRWCRn_EL1 control
1096061da546Spatrick // register.
1097061da546Spatrick // Returns -1 if the trailing bit patterns are not one of:
1098061da546Spatrick // { 0b???????1, 0b??????10, 0b?????100, 0b????1000, 0b???10000, 0b??100000,
1099061da546Spatrick // 0b?1000000, 0b10000000 }.
LowestBitSet(uint32_t val)1100061da546Spatrick static inline int32_t LowestBitSet(uint32_t val) {
1101061da546Spatrick   for (unsigned i = 0; i < 8; ++i) {
1102061da546Spatrick     if (bit(val, i))
1103061da546Spatrick       return i;
1104061da546Spatrick   }
1105061da546Spatrick   return -1;
1106061da546Spatrick }
1107061da546Spatrick 
1108061da546Spatrick // Iterate through the debug registers; return the index of the first watchpoint
1109061da546Spatrick // whose address matches.
1110061da546Spatrick // As a side effect, the starting address as understood by the debugger is
1111061da546Spatrick // returned which could be
1112061da546Spatrick // different from 'addr' passed as an in/out argument.
GetHardwareWatchpointHit(nub_addr_t & addr)1113061da546Spatrick uint32_t DNBArchMachARM64::GetHardwareWatchpointHit(nub_addr_t &addr) {
1114061da546Spatrick   // Read the debug state
1115061da546Spatrick   kern_return_t kret = GetDBGState(true);
1116061da546Spatrick   // DumpDBGState(m_state.dbg);
1117061da546Spatrick   DNBLogThreadedIf(
1118061da546Spatrick       LOG_WATCHPOINTS,
1119061da546Spatrick       "DNBArchMachARM64::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.",
1120061da546Spatrick       kret);
1121061da546Spatrick   DNBLogThreadedIf(LOG_WATCHPOINTS,
1122061da546Spatrick                    "DNBArchMachARM64::GetHardwareWatchpointHit() addr = 0x%llx",
1123061da546Spatrick                    (uint64_t)addr);
1124061da546Spatrick 
1125061da546Spatrick   if (kret == KERN_SUCCESS) {
1126061da546Spatrick     DBG &debug_state = m_state.dbg;
1127061da546Spatrick     uint32_t i, num = NumSupportedHardwareWatchpoints();
1128061da546Spatrick     for (i = 0; i < num; ++i) {
1129061da546Spatrick       nub_addr_t wp_addr = GetWatchAddress(debug_state, i);
1130061da546Spatrick       uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5);
1131061da546Spatrick 
1132dda28197Spatrick       DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::"
1133dda28197Spatrick                        "GetHardwareWatchpointHit() slot: %u "
1134dda28197Spatrick                        "(addr = 0x%llx; byte_mask = 0x%x)",
1135dda28197Spatrick                        i, static_cast<uint64_t>(wp_addr),
1136dda28197Spatrick                        byte_mask);
1137061da546Spatrick 
1138061da546Spatrick       if (!IsWatchpointEnabled(debug_state, i))
1139061da546Spatrick         continue;
1140061da546Spatrick 
1141dda28197Spatrick       if (bits(wp_addr, 48, 3) != bits(addr, 48, 3))
1142dda28197Spatrick         continue;
1143dda28197Spatrick 
1144dda28197Spatrick       // Sanity check the byte_mask
1145dda28197Spatrick       uint32_t lsb = LowestBitSet(byte_mask);
1146dda28197Spatrick       if (lsb < 0)
1147dda28197Spatrick         continue;
1148dda28197Spatrick 
1149dda28197Spatrick       uint64_t byte_to_match = bits(addr, 2, 0);
1150dda28197Spatrick 
1151dda28197Spatrick       if (byte_mask & (1 << byte_to_match)) {
1152dda28197Spatrick         addr = wp_addr + lsb;
1153061da546Spatrick         return i;
1154061da546Spatrick       }
1155061da546Spatrick     }
1156061da546Spatrick   }
1157061da546Spatrick   return INVALID_NUB_HW_INDEX;
1158061da546Spatrick }
1159061da546Spatrick 
GetWatchpointAddressByIndex(uint32_t hw_index)1160061da546Spatrick nub_addr_t DNBArchMachARM64::GetWatchpointAddressByIndex(uint32_t hw_index) {
1161061da546Spatrick   kern_return_t kret = GetDBGState(true);
1162061da546Spatrick   if (kret != KERN_SUCCESS)
1163061da546Spatrick     return INVALID_NUB_ADDRESS;
1164061da546Spatrick   const uint32_t num = NumSupportedHardwareWatchpoints();
1165061da546Spatrick   if (hw_index >= num)
1166061da546Spatrick     return INVALID_NUB_ADDRESS;
1167061da546Spatrick   if (IsWatchpointEnabled(m_state.dbg, hw_index))
1168061da546Spatrick     return GetWatchAddress(m_state.dbg, hw_index);
1169061da546Spatrick   return INVALID_NUB_ADDRESS;
1170061da546Spatrick }
1171061da546Spatrick 
IsWatchpointEnabled(const DBG & debug_state,uint32_t hw_index)1172061da546Spatrick bool DNBArchMachARM64::IsWatchpointEnabled(const DBG &debug_state,
1173061da546Spatrick                                            uint32_t hw_index) {
1174061da546Spatrick   // Watchpoint Control Registers, bitfield definitions
1175061da546Spatrick   // ...
1176061da546Spatrick   // Bits    Value    Description
1177061da546Spatrick   // [0]     0        Watchpoint disabled
1178061da546Spatrick   //         1        Watchpoint enabled.
1179061da546Spatrick   return (debug_state.__wcr[hw_index] & 1u);
1180061da546Spatrick }
1181061da546Spatrick 
GetWatchAddress(const DBG & debug_state,uint32_t hw_index)1182061da546Spatrick nub_addr_t DNBArchMachARM64::GetWatchAddress(const DBG &debug_state,
1183061da546Spatrick                                              uint32_t hw_index) {
1184061da546Spatrick   // Watchpoint Value Registers, bitfield definitions
1185061da546Spatrick   // Bits        Description
1186061da546Spatrick   // [31:2]      Watchpoint value (word address, i.e., 4-byte aligned)
1187061da546Spatrick   // [1:0]       RAZ/SBZP
1188061da546Spatrick   return bits(debug_state.__wvr[hw_index], 63, 0);
1189061da546Spatrick }
1190061da546Spatrick 
1191061da546Spatrick // Register information definitions for 64 bit ARMv8.
1192061da546Spatrick enum gpr_regnums {
1193061da546Spatrick   gpr_x0 = 0,
1194061da546Spatrick   gpr_x1,
1195061da546Spatrick   gpr_x2,
1196061da546Spatrick   gpr_x3,
1197061da546Spatrick   gpr_x4,
1198061da546Spatrick   gpr_x5,
1199061da546Spatrick   gpr_x6,
1200061da546Spatrick   gpr_x7,
1201061da546Spatrick   gpr_x8,
1202061da546Spatrick   gpr_x9,
1203061da546Spatrick   gpr_x10,
1204061da546Spatrick   gpr_x11,
1205061da546Spatrick   gpr_x12,
1206061da546Spatrick   gpr_x13,
1207061da546Spatrick   gpr_x14,
1208061da546Spatrick   gpr_x15,
1209061da546Spatrick   gpr_x16,
1210061da546Spatrick   gpr_x17,
1211061da546Spatrick   gpr_x18,
1212061da546Spatrick   gpr_x19,
1213061da546Spatrick   gpr_x20,
1214061da546Spatrick   gpr_x21,
1215061da546Spatrick   gpr_x22,
1216061da546Spatrick   gpr_x23,
1217061da546Spatrick   gpr_x24,
1218061da546Spatrick   gpr_x25,
1219061da546Spatrick   gpr_x26,
1220061da546Spatrick   gpr_x27,
1221061da546Spatrick   gpr_x28,
1222061da546Spatrick   gpr_fp,
1223061da546Spatrick   gpr_x29 = gpr_fp,
1224061da546Spatrick   gpr_lr,
1225061da546Spatrick   gpr_x30 = gpr_lr,
1226061da546Spatrick   gpr_sp,
1227061da546Spatrick   gpr_x31 = gpr_sp,
1228061da546Spatrick   gpr_pc,
1229061da546Spatrick   gpr_cpsr,
1230061da546Spatrick   gpr_w0,
1231061da546Spatrick   gpr_w1,
1232061da546Spatrick   gpr_w2,
1233061da546Spatrick   gpr_w3,
1234061da546Spatrick   gpr_w4,
1235061da546Spatrick   gpr_w5,
1236061da546Spatrick   gpr_w6,
1237061da546Spatrick   gpr_w7,
1238061da546Spatrick   gpr_w8,
1239061da546Spatrick   gpr_w9,
1240061da546Spatrick   gpr_w10,
1241061da546Spatrick   gpr_w11,
1242061da546Spatrick   gpr_w12,
1243061da546Spatrick   gpr_w13,
1244061da546Spatrick   gpr_w14,
1245061da546Spatrick   gpr_w15,
1246061da546Spatrick   gpr_w16,
1247061da546Spatrick   gpr_w17,
1248061da546Spatrick   gpr_w18,
1249061da546Spatrick   gpr_w19,
1250061da546Spatrick   gpr_w20,
1251061da546Spatrick   gpr_w21,
1252061da546Spatrick   gpr_w22,
1253061da546Spatrick   gpr_w23,
1254061da546Spatrick   gpr_w24,
1255061da546Spatrick   gpr_w25,
1256061da546Spatrick   gpr_w26,
1257061da546Spatrick   gpr_w27,
1258061da546Spatrick   gpr_w28
1259061da546Spatrick 
1260061da546Spatrick };
1261061da546Spatrick 
1262061da546Spatrick enum {
1263061da546Spatrick   vfp_v0 = 0,
1264061da546Spatrick   vfp_v1,
1265061da546Spatrick   vfp_v2,
1266061da546Spatrick   vfp_v3,
1267061da546Spatrick   vfp_v4,
1268061da546Spatrick   vfp_v5,
1269061da546Spatrick   vfp_v6,
1270061da546Spatrick   vfp_v7,
1271061da546Spatrick   vfp_v8,
1272061da546Spatrick   vfp_v9,
1273061da546Spatrick   vfp_v10,
1274061da546Spatrick   vfp_v11,
1275061da546Spatrick   vfp_v12,
1276061da546Spatrick   vfp_v13,
1277061da546Spatrick   vfp_v14,
1278061da546Spatrick   vfp_v15,
1279061da546Spatrick   vfp_v16,
1280061da546Spatrick   vfp_v17,
1281061da546Spatrick   vfp_v18,
1282061da546Spatrick   vfp_v19,
1283061da546Spatrick   vfp_v20,
1284061da546Spatrick   vfp_v21,
1285061da546Spatrick   vfp_v22,
1286061da546Spatrick   vfp_v23,
1287061da546Spatrick   vfp_v24,
1288061da546Spatrick   vfp_v25,
1289061da546Spatrick   vfp_v26,
1290061da546Spatrick   vfp_v27,
1291061da546Spatrick   vfp_v28,
1292061da546Spatrick   vfp_v29,
1293061da546Spatrick   vfp_v30,
1294061da546Spatrick   vfp_v31,
1295061da546Spatrick   vfp_fpsr,
1296061da546Spatrick   vfp_fpcr,
1297061da546Spatrick 
1298061da546Spatrick   // lower 32 bits of the corresponding vfp_v<n> reg.
1299061da546Spatrick   vfp_s0,
1300061da546Spatrick   vfp_s1,
1301061da546Spatrick   vfp_s2,
1302061da546Spatrick   vfp_s3,
1303061da546Spatrick   vfp_s4,
1304061da546Spatrick   vfp_s5,
1305061da546Spatrick   vfp_s6,
1306061da546Spatrick   vfp_s7,
1307061da546Spatrick   vfp_s8,
1308061da546Spatrick   vfp_s9,
1309061da546Spatrick   vfp_s10,
1310061da546Spatrick   vfp_s11,
1311061da546Spatrick   vfp_s12,
1312061da546Spatrick   vfp_s13,
1313061da546Spatrick   vfp_s14,
1314061da546Spatrick   vfp_s15,
1315061da546Spatrick   vfp_s16,
1316061da546Spatrick   vfp_s17,
1317061da546Spatrick   vfp_s18,
1318061da546Spatrick   vfp_s19,
1319061da546Spatrick   vfp_s20,
1320061da546Spatrick   vfp_s21,
1321061da546Spatrick   vfp_s22,
1322061da546Spatrick   vfp_s23,
1323061da546Spatrick   vfp_s24,
1324061da546Spatrick   vfp_s25,
1325061da546Spatrick   vfp_s26,
1326061da546Spatrick   vfp_s27,
1327061da546Spatrick   vfp_s28,
1328061da546Spatrick   vfp_s29,
1329061da546Spatrick   vfp_s30,
1330061da546Spatrick   vfp_s31,
1331061da546Spatrick 
1332061da546Spatrick   // lower 64 bits of the corresponding vfp_v<n> reg.
1333061da546Spatrick   vfp_d0,
1334061da546Spatrick   vfp_d1,
1335061da546Spatrick   vfp_d2,
1336061da546Spatrick   vfp_d3,
1337061da546Spatrick   vfp_d4,
1338061da546Spatrick   vfp_d5,
1339061da546Spatrick   vfp_d6,
1340061da546Spatrick   vfp_d7,
1341061da546Spatrick   vfp_d8,
1342061da546Spatrick   vfp_d9,
1343061da546Spatrick   vfp_d10,
1344061da546Spatrick   vfp_d11,
1345061da546Spatrick   vfp_d12,
1346061da546Spatrick   vfp_d13,
1347061da546Spatrick   vfp_d14,
1348061da546Spatrick   vfp_d15,
1349061da546Spatrick   vfp_d16,
1350061da546Spatrick   vfp_d17,
1351061da546Spatrick   vfp_d18,
1352061da546Spatrick   vfp_d19,
1353061da546Spatrick   vfp_d20,
1354061da546Spatrick   vfp_d21,
1355061da546Spatrick   vfp_d22,
1356061da546Spatrick   vfp_d23,
1357061da546Spatrick   vfp_d24,
1358061da546Spatrick   vfp_d25,
1359061da546Spatrick   vfp_d26,
1360061da546Spatrick   vfp_d27,
1361061da546Spatrick   vfp_d28,
1362061da546Spatrick   vfp_d29,
1363061da546Spatrick   vfp_d30,
1364061da546Spatrick   vfp_d31
1365061da546Spatrick };
1366061da546Spatrick 
1367061da546Spatrick enum { exc_far = 0, exc_esr, exc_exception };
1368061da546Spatrick 
1369061da546Spatrick // These numbers from the "DWARF for the ARM 64-bit Architecture (AArch64)"
1370061da546Spatrick // document.
1371061da546Spatrick 
1372061da546Spatrick enum {
1373061da546Spatrick   dwarf_x0 = 0,
1374061da546Spatrick   dwarf_x1,
1375061da546Spatrick   dwarf_x2,
1376061da546Spatrick   dwarf_x3,
1377061da546Spatrick   dwarf_x4,
1378061da546Spatrick   dwarf_x5,
1379061da546Spatrick   dwarf_x6,
1380061da546Spatrick   dwarf_x7,
1381061da546Spatrick   dwarf_x8,
1382061da546Spatrick   dwarf_x9,
1383061da546Spatrick   dwarf_x10,
1384061da546Spatrick   dwarf_x11,
1385061da546Spatrick   dwarf_x12,
1386061da546Spatrick   dwarf_x13,
1387061da546Spatrick   dwarf_x14,
1388061da546Spatrick   dwarf_x15,
1389061da546Spatrick   dwarf_x16,
1390061da546Spatrick   dwarf_x17,
1391061da546Spatrick   dwarf_x18,
1392061da546Spatrick   dwarf_x19,
1393061da546Spatrick   dwarf_x20,
1394061da546Spatrick   dwarf_x21,
1395061da546Spatrick   dwarf_x22,
1396061da546Spatrick   dwarf_x23,
1397061da546Spatrick   dwarf_x24,
1398061da546Spatrick   dwarf_x25,
1399061da546Spatrick   dwarf_x26,
1400061da546Spatrick   dwarf_x27,
1401061da546Spatrick   dwarf_x28,
1402061da546Spatrick   dwarf_x29,
1403061da546Spatrick   dwarf_x30,
1404061da546Spatrick   dwarf_x31,
1405061da546Spatrick   dwarf_pc = 32,
1406061da546Spatrick   dwarf_elr_mode = 33,
1407061da546Spatrick   dwarf_fp = dwarf_x29,
1408061da546Spatrick   dwarf_lr = dwarf_x30,
1409061da546Spatrick   dwarf_sp = dwarf_x31,
1410061da546Spatrick   // 34-63 reserved
1411061da546Spatrick 
1412061da546Spatrick   // V0-V31 (128 bit vector registers)
1413061da546Spatrick   dwarf_v0 = 64,
1414061da546Spatrick   dwarf_v1,
1415061da546Spatrick   dwarf_v2,
1416061da546Spatrick   dwarf_v3,
1417061da546Spatrick   dwarf_v4,
1418061da546Spatrick   dwarf_v5,
1419061da546Spatrick   dwarf_v6,
1420061da546Spatrick   dwarf_v7,
1421061da546Spatrick   dwarf_v8,
1422061da546Spatrick   dwarf_v9,
1423061da546Spatrick   dwarf_v10,
1424061da546Spatrick   dwarf_v11,
1425061da546Spatrick   dwarf_v12,
1426061da546Spatrick   dwarf_v13,
1427061da546Spatrick   dwarf_v14,
1428061da546Spatrick   dwarf_v15,
1429061da546Spatrick   dwarf_v16,
1430061da546Spatrick   dwarf_v17,
1431061da546Spatrick   dwarf_v18,
1432061da546Spatrick   dwarf_v19,
1433061da546Spatrick   dwarf_v20,
1434061da546Spatrick   dwarf_v21,
1435061da546Spatrick   dwarf_v22,
1436061da546Spatrick   dwarf_v23,
1437061da546Spatrick   dwarf_v24,
1438061da546Spatrick   dwarf_v25,
1439061da546Spatrick   dwarf_v26,
1440061da546Spatrick   dwarf_v27,
1441061da546Spatrick   dwarf_v28,
1442061da546Spatrick   dwarf_v29,
1443061da546Spatrick   dwarf_v30,
1444061da546Spatrick   dwarf_v31
1445061da546Spatrick 
1446061da546Spatrick   // 96-127 reserved
1447061da546Spatrick };
1448061da546Spatrick 
1449061da546Spatrick enum {
1450061da546Spatrick   debugserver_gpr_x0 = 0,
1451061da546Spatrick   debugserver_gpr_x1,
1452061da546Spatrick   debugserver_gpr_x2,
1453061da546Spatrick   debugserver_gpr_x3,
1454061da546Spatrick   debugserver_gpr_x4,
1455061da546Spatrick   debugserver_gpr_x5,
1456061da546Spatrick   debugserver_gpr_x6,
1457061da546Spatrick   debugserver_gpr_x7,
1458061da546Spatrick   debugserver_gpr_x8,
1459061da546Spatrick   debugserver_gpr_x9,
1460061da546Spatrick   debugserver_gpr_x10,
1461061da546Spatrick   debugserver_gpr_x11,
1462061da546Spatrick   debugserver_gpr_x12,
1463061da546Spatrick   debugserver_gpr_x13,
1464061da546Spatrick   debugserver_gpr_x14,
1465061da546Spatrick   debugserver_gpr_x15,
1466061da546Spatrick   debugserver_gpr_x16,
1467061da546Spatrick   debugserver_gpr_x17,
1468061da546Spatrick   debugserver_gpr_x18,
1469061da546Spatrick   debugserver_gpr_x19,
1470061da546Spatrick   debugserver_gpr_x20,
1471061da546Spatrick   debugserver_gpr_x21,
1472061da546Spatrick   debugserver_gpr_x22,
1473061da546Spatrick   debugserver_gpr_x23,
1474061da546Spatrick   debugserver_gpr_x24,
1475061da546Spatrick   debugserver_gpr_x25,
1476061da546Spatrick   debugserver_gpr_x26,
1477061da546Spatrick   debugserver_gpr_x27,
1478061da546Spatrick   debugserver_gpr_x28,
1479061da546Spatrick   debugserver_gpr_fp, // x29
1480061da546Spatrick   debugserver_gpr_lr, // x30
1481061da546Spatrick   debugserver_gpr_sp, // sp aka xsp
1482061da546Spatrick   debugserver_gpr_pc,
1483061da546Spatrick   debugserver_gpr_cpsr,
1484061da546Spatrick   debugserver_vfp_v0,
1485061da546Spatrick   debugserver_vfp_v1,
1486061da546Spatrick   debugserver_vfp_v2,
1487061da546Spatrick   debugserver_vfp_v3,
1488061da546Spatrick   debugserver_vfp_v4,
1489061da546Spatrick   debugserver_vfp_v5,
1490061da546Spatrick   debugserver_vfp_v6,
1491061da546Spatrick   debugserver_vfp_v7,
1492061da546Spatrick   debugserver_vfp_v8,
1493061da546Spatrick   debugserver_vfp_v9,
1494061da546Spatrick   debugserver_vfp_v10,
1495061da546Spatrick   debugserver_vfp_v11,
1496061da546Spatrick   debugserver_vfp_v12,
1497061da546Spatrick   debugserver_vfp_v13,
1498061da546Spatrick   debugserver_vfp_v14,
1499061da546Spatrick   debugserver_vfp_v15,
1500061da546Spatrick   debugserver_vfp_v16,
1501061da546Spatrick   debugserver_vfp_v17,
1502061da546Spatrick   debugserver_vfp_v18,
1503061da546Spatrick   debugserver_vfp_v19,
1504061da546Spatrick   debugserver_vfp_v20,
1505061da546Spatrick   debugserver_vfp_v21,
1506061da546Spatrick   debugserver_vfp_v22,
1507061da546Spatrick   debugserver_vfp_v23,
1508061da546Spatrick   debugserver_vfp_v24,
1509061da546Spatrick   debugserver_vfp_v25,
1510061da546Spatrick   debugserver_vfp_v26,
1511061da546Spatrick   debugserver_vfp_v27,
1512061da546Spatrick   debugserver_vfp_v28,
1513061da546Spatrick   debugserver_vfp_v29,
1514061da546Spatrick   debugserver_vfp_v30,
1515061da546Spatrick   debugserver_vfp_v31,
1516061da546Spatrick   debugserver_vfp_fpsr,
1517061da546Spatrick   debugserver_vfp_fpcr
1518061da546Spatrick };
1519061da546Spatrick 
1520061da546Spatrick const char *g_contained_x0[]{"x0", NULL};
1521061da546Spatrick const char *g_contained_x1[]{"x1", NULL};
1522061da546Spatrick const char *g_contained_x2[]{"x2", NULL};
1523061da546Spatrick const char *g_contained_x3[]{"x3", NULL};
1524061da546Spatrick const char *g_contained_x4[]{"x4", NULL};
1525061da546Spatrick const char *g_contained_x5[]{"x5", NULL};
1526061da546Spatrick const char *g_contained_x6[]{"x6", NULL};
1527061da546Spatrick const char *g_contained_x7[]{"x7", NULL};
1528061da546Spatrick const char *g_contained_x8[]{"x8", NULL};
1529061da546Spatrick const char *g_contained_x9[]{"x9", NULL};
1530061da546Spatrick const char *g_contained_x10[]{"x10", NULL};
1531061da546Spatrick const char *g_contained_x11[]{"x11", NULL};
1532061da546Spatrick const char *g_contained_x12[]{"x12", NULL};
1533061da546Spatrick const char *g_contained_x13[]{"x13", NULL};
1534061da546Spatrick const char *g_contained_x14[]{"x14", NULL};
1535061da546Spatrick const char *g_contained_x15[]{"x15", NULL};
1536061da546Spatrick const char *g_contained_x16[]{"x16", NULL};
1537061da546Spatrick const char *g_contained_x17[]{"x17", NULL};
1538061da546Spatrick const char *g_contained_x18[]{"x18", NULL};
1539061da546Spatrick const char *g_contained_x19[]{"x19", NULL};
1540061da546Spatrick const char *g_contained_x20[]{"x20", NULL};
1541061da546Spatrick const char *g_contained_x21[]{"x21", NULL};
1542061da546Spatrick const char *g_contained_x22[]{"x22", NULL};
1543061da546Spatrick const char *g_contained_x23[]{"x23", NULL};
1544061da546Spatrick const char *g_contained_x24[]{"x24", NULL};
1545061da546Spatrick const char *g_contained_x25[]{"x25", NULL};
1546061da546Spatrick const char *g_contained_x26[]{"x26", NULL};
1547061da546Spatrick const char *g_contained_x27[]{"x27", NULL};
1548061da546Spatrick const char *g_contained_x28[]{"x28", NULL};
1549061da546Spatrick 
1550061da546Spatrick const char *g_invalidate_x0[]{"x0", "w0", NULL};
1551061da546Spatrick const char *g_invalidate_x1[]{"x1", "w1", NULL};
1552061da546Spatrick const char *g_invalidate_x2[]{"x2", "w2", NULL};
1553061da546Spatrick const char *g_invalidate_x3[]{"x3", "w3", NULL};
1554061da546Spatrick const char *g_invalidate_x4[]{"x4", "w4", NULL};
1555061da546Spatrick const char *g_invalidate_x5[]{"x5", "w5", NULL};
1556061da546Spatrick const char *g_invalidate_x6[]{"x6", "w6", NULL};
1557061da546Spatrick const char *g_invalidate_x7[]{"x7", "w7", NULL};
1558061da546Spatrick const char *g_invalidate_x8[]{"x8", "w8", NULL};
1559061da546Spatrick const char *g_invalidate_x9[]{"x9", "w9", NULL};
1560061da546Spatrick const char *g_invalidate_x10[]{"x10", "w10", NULL};
1561061da546Spatrick const char *g_invalidate_x11[]{"x11", "w11", NULL};
1562061da546Spatrick const char *g_invalidate_x12[]{"x12", "w12", NULL};
1563061da546Spatrick const char *g_invalidate_x13[]{"x13", "w13", NULL};
1564061da546Spatrick const char *g_invalidate_x14[]{"x14", "w14", NULL};
1565061da546Spatrick const char *g_invalidate_x15[]{"x15", "w15", NULL};
1566061da546Spatrick const char *g_invalidate_x16[]{"x16", "w16", NULL};
1567061da546Spatrick const char *g_invalidate_x17[]{"x17", "w17", NULL};
1568061da546Spatrick const char *g_invalidate_x18[]{"x18", "w18", NULL};
1569061da546Spatrick const char *g_invalidate_x19[]{"x19", "w19", NULL};
1570061da546Spatrick const char *g_invalidate_x20[]{"x20", "w20", NULL};
1571061da546Spatrick const char *g_invalidate_x21[]{"x21", "w21", NULL};
1572061da546Spatrick const char *g_invalidate_x22[]{"x22", "w22", NULL};
1573061da546Spatrick const char *g_invalidate_x23[]{"x23", "w23", NULL};
1574061da546Spatrick const char *g_invalidate_x24[]{"x24", "w24", NULL};
1575061da546Spatrick const char *g_invalidate_x25[]{"x25", "w25", NULL};
1576061da546Spatrick const char *g_invalidate_x26[]{"x26", "w26", NULL};
1577061da546Spatrick const char *g_invalidate_x27[]{"x27", "w27", NULL};
1578061da546Spatrick const char *g_invalidate_x28[]{"x28", "w28", NULL};
1579061da546Spatrick 
1580061da546Spatrick #define GPR_OFFSET_IDX(idx) (offsetof(DNBArchMachARM64::GPR, __x[idx]))
1581061da546Spatrick 
1582061da546Spatrick #define GPR_OFFSET_NAME(reg) (offsetof(DNBArchMachARM64::GPR, __##reg))
1583061da546Spatrick 
1584061da546Spatrick // These macros will auto define the register name, alt name, register size,
1585061da546Spatrick // register offset, encoding, format and native register. This ensures that
1586061da546Spatrick // the register state structures are defined correctly and have the correct
1587061da546Spatrick // sizes and offsets.
1588061da546Spatrick #define DEFINE_GPR_IDX(idx, reg, alt, gen)                                     \
1589061da546Spatrick   {                                                                            \
1590061da546Spatrick     e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_IDX(idx),      \
1591061da546Spatrick         dwarf_##reg, dwarf_##reg, gen, debugserver_gpr_##reg, NULL,            \
1592061da546Spatrick         g_invalidate_x##idx                                                    \
1593061da546Spatrick   }
1594061da546Spatrick #define DEFINE_GPR_NAME(reg, alt, gen)                                         \
1595061da546Spatrick   {                                                                            \
1596061da546Spatrick     e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_NAME(reg),     \
1597061da546Spatrick         dwarf_##reg, dwarf_##reg, gen, debugserver_gpr_##reg, NULL, NULL       \
1598061da546Spatrick   }
1599061da546Spatrick #define DEFINE_PSEUDO_GPR_IDX(idx, reg)                                        \
1600061da546Spatrick   {                                                                            \
1601061da546Spatrick     e_regSetGPR, gpr_##reg, #reg, NULL, Uint, Hex, 4, 0, INVALID_NUB_REGNUM,   \
1602061da546Spatrick         INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,            \
1603061da546Spatrick         g_contained_x##idx, g_invalidate_x##idx                                \
1604061da546Spatrick   }
1605061da546Spatrick 
1606061da546Spatrick //_STRUCT_ARM_THREAD_STATE64
1607061da546Spatrick //{
1608061da546Spatrick //	uint64_t    x[29];	/* General purpose registers x0-x28 */
1609061da546Spatrick //	uint64_t    fp;		/* Frame pointer x29 */
1610061da546Spatrick //	uint64_t    lr;		/* Link register x30 */
1611061da546Spatrick //	uint64_t    sp;		/* Stack pointer x31 */
1612061da546Spatrick //	uint64_t    pc;		/* Program counter */
1613061da546Spatrick //	uint32_t    cpsr;	/* Current program status register */
1614061da546Spatrick //};
1615061da546Spatrick 
1616061da546Spatrick // General purpose registers
1617061da546Spatrick const DNBRegisterInfo DNBArchMachARM64::g_gpr_registers[] = {
1618061da546Spatrick     DEFINE_GPR_IDX(0, x0, "arg1", GENERIC_REGNUM_ARG1),
1619061da546Spatrick     DEFINE_GPR_IDX(1, x1, "arg2", GENERIC_REGNUM_ARG2),
1620061da546Spatrick     DEFINE_GPR_IDX(2, x2, "arg3", GENERIC_REGNUM_ARG3),
1621061da546Spatrick     DEFINE_GPR_IDX(3, x3, "arg4", GENERIC_REGNUM_ARG4),
1622061da546Spatrick     DEFINE_GPR_IDX(4, x4, "arg5", GENERIC_REGNUM_ARG5),
1623061da546Spatrick     DEFINE_GPR_IDX(5, x5, "arg6", GENERIC_REGNUM_ARG6),
1624061da546Spatrick     DEFINE_GPR_IDX(6, x6, "arg7", GENERIC_REGNUM_ARG7),
1625061da546Spatrick     DEFINE_GPR_IDX(7, x7, "arg8", GENERIC_REGNUM_ARG8),
1626061da546Spatrick     DEFINE_GPR_IDX(8, x8, NULL, INVALID_NUB_REGNUM),
1627061da546Spatrick     DEFINE_GPR_IDX(9, x9, NULL, INVALID_NUB_REGNUM),
1628061da546Spatrick     DEFINE_GPR_IDX(10, x10, NULL, INVALID_NUB_REGNUM),
1629061da546Spatrick     DEFINE_GPR_IDX(11, x11, NULL, INVALID_NUB_REGNUM),
1630061da546Spatrick     DEFINE_GPR_IDX(12, x12, NULL, INVALID_NUB_REGNUM),
1631061da546Spatrick     DEFINE_GPR_IDX(13, x13, NULL, INVALID_NUB_REGNUM),
1632061da546Spatrick     DEFINE_GPR_IDX(14, x14, NULL, INVALID_NUB_REGNUM),
1633061da546Spatrick     DEFINE_GPR_IDX(15, x15, NULL, INVALID_NUB_REGNUM),
1634061da546Spatrick     DEFINE_GPR_IDX(16, x16, NULL, INVALID_NUB_REGNUM),
1635061da546Spatrick     DEFINE_GPR_IDX(17, x17, NULL, INVALID_NUB_REGNUM),
1636061da546Spatrick     DEFINE_GPR_IDX(18, x18, NULL, INVALID_NUB_REGNUM),
1637061da546Spatrick     DEFINE_GPR_IDX(19, x19, NULL, INVALID_NUB_REGNUM),
1638061da546Spatrick     DEFINE_GPR_IDX(20, x20, NULL, INVALID_NUB_REGNUM),
1639061da546Spatrick     DEFINE_GPR_IDX(21, x21, NULL, INVALID_NUB_REGNUM),
1640061da546Spatrick     DEFINE_GPR_IDX(22, x22, NULL, INVALID_NUB_REGNUM),
1641061da546Spatrick     DEFINE_GPR_IDX(23, x23, NULL, INVALID_NUB_REGNUM),
1642061da546Spatrick     DEFINE_GPR_IDX(24, x24, NULL, INVALID_NUB_REGNUM),
1643061da546Spatrick     DEFINE_GPR_IDX(25, x25, NULL, INVALID_NUB_REGNUM),
1644061da546Spatrick     DEFINE_GPR_IDX(26, x26, NULL, INVALID_NUB_REGNUM),
1645061da546Spatrick     DEFINE_GPR_IDX(27, x27, NULL, INVALID_NUB_REGNUM),
1646061da546Spatrick     DEFINE_GPR_IDX(28, x28, NULL, INVALID_NUB_REGNUM),
1647061da546Spatrick     // For the G/g packet we want to show where the offset into the regctx
1648061da546Spatrick     // is for fp/lr/sp/pc, but we cannot directly access them on arm64e
1649061da546Spatrick     // devices (and therefore can't offsetof() them)) - add the offset based
1650061da546Spatrick     // on the last accessible register by hand for advertising the location
1651061da546Spatrick     // in the regctx to lldb.  We'll go through the accessor functions when
1652061da546Spatrick     // we read/write them here.
1653061da546Spatrick     {
1654061da546Spatrick        e_regSetGPR, gpr_fp, "fp", "x29", Uint, Hex, 8, GPR_OFFSET_IDX(28) + 8,
1655061da546Spatrick        dwarf_fp, dwarf_fp, GENERIC_REGNUM_FP, debugserver_gpr_fp, NULL, NULL
1656061da546Spatrick     },
1657061da546Spatrick     {
1658061da546Spatrick        e_regSetGPR, gpr_lr, "lr", "x30", Uint, Hex, 8, GPR_OFFSET_IDX(28) + 16,
1659061da546Spatrick        dwarf_lr, dwarf_lr, GENERIC_REGNUM_RA, debugserver_gpr_lr, NULL, NULL
1660061da546Spatrick     },
1661061da546Spatrick     {
1662061da546Spatrick        e_regSetGPR, gpr_sp, "sp", "xsp", Uint, Hex, 8, GPR_OFFSET_IDX(28) + 24,
1663061da546Spatrick        dwarf_sp, dwarf_sp, GENERIC_REGNUM_SP, debugserver_gpr_sp, NULL, NULL
1664061da546Spatrick     },
1665061da546Spatrick     {
1666061da546Spatrick        e_regSetGPR, gpr_pc, "pc", NULL, Uint, Hex, 8, GPR_OFFSET_IDX(28) + 32,
1667061da546Spatrick        dwarf_pc, dwarf_pc, GENERIC_REGNUM_PC, debugserver_gpr_pc, NULL, NULL
1668061da546Spatrick     },
1669061da546Spatrick 
1670061da546Spatrick     // in armv7 we specify that writing to the CPSR should invalidate r8-12, sp,
1671061da546Spatrick     // lr.
1672061da546Spatrick     // this should be specified for arm64 too even though debugserver is only
1673061da546Spatrick     // used for
1674061da546Spatrick     // userland debugging.
1675061da546Spatrick     {e_regSetGPR, gpr_cpsr, "cpsr", "flags", Uint, Hex, 4,
1676*f6aab3d8Srobert      GPR_OFFSET_NAME(cpsr), dwarf_elr_mode, dwarf_elr_mode, GENERIC_REGNUM_FLAGS,
1677061da546Spatrick      debugserver_gpr_cpsr, NULL, NULL},
1678061da546Spatrick 
1679061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(0, w0),
1680061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(1, w1),
1681061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(2, w2),
1682061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(3, w3),
1683061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(4, w4),
1684061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(5, w5),
1685061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(6, w6),
1686061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(7, w7),
1687061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(8, w8),
1688061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(9, w9),
1689061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(10, w10),
1690061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(11, w11),
1691061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(12, w12),
1692061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(13, w13),
1693061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(14, w14),
1694061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(15, w15),
1695061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(16, w16),
1696061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(17, w17),
1697061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(18, w18),
1698061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(19, w19),
1699061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(20, w20),
1700061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(21, w21),
1701061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(22, w22),
1702061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(23, w23),
1703061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(24, w24),
1704061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(25, w25),
1705061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(26, w26),
1706061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(27, w27),
1707061da546Spatrick     DEFINE_PSEUDO_GPR_IDX(28, w28)};
1708061da546Spatrick 
1709061da546Spatrick const char *g_contained_v0[]{"v0", NULL};
1710061da546Spatrick const char *g_contained_v1[]{"v1", NULL};
1711061da546Spatrick const char *g_contained_v2[]{"v2", NULL};
1712061da546Spatrick const char *g_contained_v3[]{"v3", NULL};
1713061da546Spatrick const char *g_contained_v4[]{"v4", NULL};
1714061da546Spatrick const char *g_contained_v5[]{"v5", NULL};
1715061da546Spatrick const char *g_contained_v6[]{"v6", NULL};
1716061da546Spatrick const char *g_contained_v7[]{"v7", NULL};
1717061da546Spatrick const char *g_contained_v8[]{"v8", NULL};
1718061da546Spatrick const char *g_contained_v9[]{"v9", NULL};
1719061da546Spatrick const char *g_contained_v10[]{"v10", NULL};
1720061da546Spatrick const char *g_contained_v11[]{"v11", NULL};
1721061da546Spatrick const char *g_contained_v12[]{"v12", NULL};
1722061da546Spatrick const char *g_contained_v13[]{"v13", NULL};
1723061da546Spatrick const char *g_contained_v14[]{"v14", NULL};
1724061da546Spatrick const char *g_contained_v15[]{"v15", NULL};
1725061da546Spatrick const char *g_contained_v16[]{"v16", NULL};
1726061da546Spatrick const char *g_contained_v17[]{"v17", NULL};
1727061da546Spatrick const char *g_contained_v18[]{"v18", NULL};
1728061da546Spatrick const char *g_contained_v19[]{"v19", NULL};
1729061da546Spatrick const char *g_contained_v20[]{"v20", NULL};
1730061da546Spatrick const char *g_contained_v21[]{"v21", NULL};
1731061da546Spatrick const char *g_contained_v22[]{"v22", NULL};
1732061da546Spatrick const char *g_contained_v23[]{"v23", NULL};
1733061da546Spatrick const char *g_contained_v24[]{"v24", NULL};
1734061da546Spatrick const char *g_contained_v25[]{"v25", NULL};
1735061da546Spatrick const char *g_contained_v26[]{"v26", NULL};
1736061da546Spatrick const char *g_contained_v27[]{"v27", NULL};
1737061da546Spatrick const char *g_contained_v28[]{"v28", NULL};
1738061da546Spatrick const char *g_contained_v29[]{"v29", NULL};
1739061da546Spatrick const char *g_contained_v30[]{"v30", NULL};
1740061da546Spatrick const char *g_contained_v31[]{"v31", NULL};
1741061da546Spatrick 
1742061da546Spatrick const char *g_invalidate_v0[]{"v0", "d0", "s0", NULL};
1743061da546Spatrick const char *g_invalidate_v1[]{"v1", "d1", "s1", NULL};
1744061da546Spatrick const char *g_invalidate_v2[]{"v2", "d2", "s2", NULL};
1745061da546Spatrick const char *g_invalidate_v3[]{"v3", "d3", "s3", NULL};
1746061da546Spatrick const char *g_invalidate_v4[]{"v4", "d4", "s4", NULL};
1747061da546Spatrick const char *g_invalidate_v5[]{"v5", "d5", "s5", NULL};
1748061da546Spatrick const char *g_invalidate_v6[]{"v6", "d6", "s6", NULL};
1749061da546Spatrick const char *g_invalidate_v7[]{"v7", "d7", "s7", NULL};
1750061da546Spatrick const char *g_invalidate_v8[]{"v8", "d8", "s8", NULL};
1751061da546Spatrick const char *g_invalidate_v9[]{"v9", "d9", "s9", NULL};
1752061da546Spatrick const char *g_invalidate_v10[]{"v10", "d10", "s10", NULL};
1753061da546Spatrick const char *g_invalidate_v11[]{"v11", "d11", "s11", NULL};
1754061da546Spatrick const char *g_invalidate_v12[]{"v12", "d12", "s12", NULL};
1755061da546Spatrick const char *g_invalidate_v13[]{"v13", "d13", "s13", NULL};
1756061da546Spatrick const char *g_invalidate_v14[]{"v14", "d14", "s14", NULL};
1757061da546Spatrick const char *g_invalidate_v15[]{"v15", "d15", "s15", NULL};
1758061da546Spatrick const char *g_invalidate_v16[]{"v16", "d16", "s16", NULL};
1759061da546Spatrick const char *g_invalidate_v17[]{"v17", "d17", "s17", NULL};
1760061da546Spatrick const char *g_invalidate_v18[]{"v18", "d18", "s18", NULL};
1761061da546Spatrick const char *g_invalidate_v19[]{"v19", "d19", "s19", NULL};
1762061da546Spatrick const char *g_invalidate_v20[]{"v20", "d20", "s20", NULL};
1763061da546Spatrick const char *g_invalidate_v21[]{"v21", "d21", "s21", NULL};
1764061da546Spatrick const char *g_invalidate_v22[]{"v22", "d22", "s22", NULL};
1765061da546Spatrick const char *g_invalidate_v23[]{"v23", "d23", "s23", NULL};
1766061da546Spatrick const char *g_invalidate_v24[]{"v24", "d24", "s24", NULL};
1767061da546Spatrick const char *g_invalidate_v25[]{"v25", "d25", "s25", NULL};
1768061da546Spatrick const char *g_invalidate_v26[]{"v26", "d26", "s26", NULL};
1769061da546Spatrick const char *g_invalidate_v27[]{"v27", "d27", "s27", NULL};
1770061da546Spatrick const char *g_invalidate_v28[]{"v28", "d28", "s28", NULL};
1771061da546Spatrick const char *g_invalidate_v29[]{"v29", "d29", "s29", NULL};
1772061da546Spatrick const char *g_invalidate_v30[]{"v30", "d30", "s30", NULL};
1773061da546Spatrick const char *g_invalidate_v31[]{"v31", "d31", "s31", NULL};
1774061da546Spatrick 
1775061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
1776061da546Spatrick #define VFP_V_OFFSET_IDX(idx)                                                  \
1777061da546Spatrick   (offsetof(DNBArchMachARM64::FPU, __v) + (idx * 16) +                         \
1778061da546Spatrick    offsetof(DNBArchMachARM64::Context, vfp))
1779061da546Spatrick #else
1780061da546Spatrick #define VFP_V_OFFSET_IDX(idx)                                                  \
1781061da546Spatrick   (offsetof(DNBArchMachARM64::FPU, opaque) + (idx * 16) +                      \
1782061da546Spatrick    offsetof(DNBArchMachARM64::Context, vfp))
1783061da546Spatrick #endif
1784061da546Spatrick #define VFP_OFFSET_NAME(reg)                                                   \
1785061da546Spatrick   (offsetof(DNBArchMachARM64::FPU, reg) +                                      \
1786061da546Spatrick    offsetof(DNBArchMachARM64::Context, vfp))
1787061da546Spatrick #define EXC_OFFSET(reg)                                                        \
1788061da546Spatrick   (offsetof(DNBArchMachARM64::EXC, reg) +                                      \
1789061da546Spatrick    offsetof(DNBArchMachARM64::Context, exc))
1790061da546Spatrick 
1791061da546Spatrick //#define FLOAT_FORMAT Float
1792061da546Spatrick #define DEFINE_VFP_V_IDX(idx)                                                  \
1793061da546Spatrick   {                                                                            \
1794061da546Spatrick     e_regSetVFP, vfp_v##idx, "v" #idx, "q" #idx, Vector, VectorOfUInt8, 16,    \
1795061da546Spatrick         VFP_V_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_v##idx,               \
1796061da546Spatrick         INVALID_NUB_REGNUM, debugserver_vfp_v##idx, NULL, g_invalidate_v##idx  \
1797061da546Spatrick   }
1798061da546Spatrick #define DEFINE_PSEUDO_VFP_S_IDX(idx)                                           \
1799061da546Spatrick   {                                                                            \
1800061da546Spatrick     e_regSetVFP, vfp_s##idx, "s" #idx, NULL, IEEE754, Float, 4, 0,             \
1801061da546Spatrick         INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,            \
1802061da546Spatrick         INVALID_NUB_REGNUM, g_contained_v##idx, g_invalidate_v##idx            \
1803061da546Spatrick   }
1804061da546Spatrick #define DEFINE_PSEUDO_VFP_D_IDX(idx)                                           \
1805061da546Spatrick   {                                                                            \
1806061da546Spatrick     e_regSetVFP, vfp_d##idx, "d" #idx, NULL, IEEE754, Float, 8, 0,             \
1807061da546Spatrick         INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,            \
1808061da546Spatrick         INVALID_NUB_REGNUM, g_contained_v##idx, g_invalidate_v##idx            \
1809061da546Spatrick   }
1810061da546Spatrick 
1811061da546Spatrick // Floating point registers
1812061da546Spatrick const DNBRegisterInfo DNBArchMachARM64::g_vfp_registers[] = {
1813061da546Spatrick     DEFINE_VFP_V_IDX(0),
1814061da546Spatrick     DEFINE_VFP_V_IDX(1),
1815061da546Spatrick     DEFINE_VFP_V_IDX(2),
1816061da546Spatrick     DEFINE_VFP_V_IDX(3),
1817061da546Spatrick     DEFINE_VFP_V_IDX(4),
1818061da546Spatrick     DEFINE_VFP_V_IDX(5),
1819061da546Spatrick     DEFINE_VFP_V_IDX(6),
1820061da546Spatrick     DEFINE_VFP_V_IDX(7),
1821061da546Spatrick     DEFINE_VFP_V_IDX(8),
1822061da546Spatrick     DEFINE_VFP_V_IDX(9),
1823061da546Spatrick     DEFINE_VFP_V_IDX(10),
1824061da546Spatrick     DEFINE_VFP_V_IDX(11),
1825061da546Spatrick     DEFINE_VFP_V_IDX(12),
1826061da546Spatrick     DEFINE_VFP_V_IDX(13),
1827061da546Spatrick     DEFINE_VFP_V_IDX(14),
1828061da546Spatrick     DEFINE_VFP_V_IDX(15),
1829061da546Spatrick     DEFINE_VFP_V_IDX(16),
1830061da546Spatrick     DEFINE_VFP_V_IDX(17),
1831061da546Spatrick     DEFINE_VFP_V_IDX(18),
1832061da546Spatrick     DEFINE_VFP_V_IDX(19),
1833061da546Spatrick     DEFINE_VFP_V_IDX(20),
1834061da546Spatrick     DEFINE_VFP_V_IDX(21),
1835061da546Spatrick     DEFINE_VFP_V_IDX(22),
1836061da546Spatrick     DEFINE_VFP_V_IDX(23),
1837061da546Spatrick     DEFINE_VFP_V_IDX(24),
1838061da546Spatrick     DEFINE_VFP_V_IDX(25),
1839061da546Spatrick     DEFINE_VFP_V_IDX(26),
1840061da546Spatrick     DEFINE_VFP_V_IDX(27),
1841061da546Spatrick     DEFINE_VFP_V_IDX(28),
1842061da546Spatrick     DEFINE_VFP_V_IDX(29),
1843061da546Spatrick     DEFINE_VFP_V_IDX(30),
1844061da546Spatrick     DEFINE_VFP_V_IDX(31),
1845061da546Spatrick     {e_regSetVFP, vfp_fpsr, "fpsr", NULL, Uint, Hex, 4,
1846061da546Spatrick      VFP_V_OFFSET_IDX(32) + 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1847061da546Spatrick      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1848061da546Spatrick     {e_regSetVFP, vfp_fpcr, "fpcr", NULL, Uint, Hex, 4,
1849061da546Spatrick      VFP_V_OFFSET_IDX(32) + 4, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1850061da546Spatrick      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL},
1851061da546Spatrick 
1852061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(0),
1853061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(1),
1854061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(2),
1855061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(3),
1856061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(4),
1857061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(5),
1858061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(6),
1859061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(7),
1860061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(8),
1861061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(9),
1862061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(10),
1863061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(11),
1864061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(12),
1865061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(13),
1866061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(14),
1867061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(15),
1868061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(16),
1869061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(17),
1870061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(18),
1871061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(19),
1872061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(20),
1873061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(21),
1874061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(22),
1875061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(23),
1876061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(24),
1877061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(25),
1878061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(26),
1879061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(27),
1880061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(28),
1881061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(29),
1882061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(30),
1883061da546Spatrick     DEFINE_PSEUDO_VFP_S_IDX(31),
1884061da546Spatrick 
1885061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(0),
1886061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(1),
1887061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(2),
1888061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(3),
1889061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(4),
1890061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(5),
1891061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(6),
1892061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(7),
1893061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(8),
1894061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(9),
1895061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(10),
1896061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(11),
1897061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(12),
1898061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(13),
1899061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(14),
1900061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(15),
1901061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(16),
1902061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(17),
1903061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(18),
1904061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(19),
1905061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(20),
1906061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(21),
1907061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(22),
1908061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(23),
1909061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(24),
1910061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(25),
1911061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(26),
1912061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(27),
1913061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(28),
1914061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(29),
1915061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(30),
1916061da546Spatrick     DEFINE_PSEUDO_VFP_D_IDX(31)
1917061da546Spatrick 
1918061da546Spatrick };
1919061da546Spatrick 
1920061da546Spatrick //_STRUCT_ARM_EXCEPTION_STATE64
1921061da546Spatrick //{
1922061da546Spatrick //	uint64_t	far; /* Virtual Fault Address */
1923061da546Spatrick //	uint32_t	esr; /* Exception syndrome */
1924061da546Spatrick //	uint32_t	exception; /* number of arm exception taken */
1925061da546Spatrick //};
1926061da546Spatrick 
1927061da546Spatrick // Exception registers
1928061da546Spatrick const DNBRegisterInfo DNBArchMachARM64::g_exc_registers[] = {
1929061da546Spatrick     {e_regSetEXC, exc_far, "far", NULL, Uint, Hex, 8, EXC_OFFSET(__far),
1930061da546Spatrick      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1931061da546Spatrick      INVALID_NUB_REGNUM, NULL, NULL},
1932061da546Spatrick     {e_regSetEXC, exc_esr, "esr", NULL, Uint, Hex, 4, EXC_OFFSET(__esr),
1933061da546Spatrick      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1934061da546Spatrick      INVALID_NUB_REGNUM, NULL, NULL},
1935061da546Spatrick     {e_regSetEXC, exc_exception, "exception", NULL, Uint, Hex, 4,
1936061da546Spatrick      EXC_OFFSET(__exception), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM,
1937061da546Spatrick      INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}};
1938061da546Spatrick 
1939061da546Spatrick // Number of registers in each register set
1940061da546Spatrick const size_t DNBArchMachARM64::k_num_gpr_registers =
1941061da546Spatrick     sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo);
1942061da546Spatrick const size_t DNBArchMachARM64::k_num_vfp_registers =
1943061da546Spatrick     sizeof(g_vfp_registers) / sizeof(DNBRegisterInfo);
1944061da546Spatrick const size_t DNBArchMachARM64::k_num_exc_registers =
1945061da546Spatrick     sizeof(g_exc_registers) / sizeof(DNBRegisterInfo);
1946061da546Spatrick const size_t DNBArchMachARM64::k_num_all_registers =
1947061da546Spatrick     k_num_gpr_registers + k_num_vfp_registers + k_num_exc_registers;
1948061da546Spatrick 
1949061da546Spatrick // Register set definitions. The first definitions at register set index
1950061da546Spatrick // of zero is for all registers, followed by other registers sets. The
1951061da546Spatrick // register information for the all register set need not be filled in.
1952061da546Spatrick const DNBRegisterSetInfo DNBArchMachARM64::g_reg_sets[] = {
1953061da546Spatrick     {"ARM64 Registers", NULL, k_num_all_registers},
1954061da546Spatrick     {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers},
1955061da546Spatrick     {"Floating Point Registers", g_vfp_registers, k_num_vfp_registers},
1956061da546Spatrick     {"Exception State Registers", g_exc_registers, k_num_exc_registers}};
1957061da546Spatrick // Total number of register sets for this architecture
1958061da546Spatrick const size_t DNBArchMachARM64::k_num_register_sets =
1959061da546Spatrick     sizeof(g_reg_sets) / sizeof(DNBRegisterSetInfo);
1960061da546Spatrick 
1961061da546Spatrick const DNBRegisterSetInfo *
GetRegisterSetInfo(nub_size_t * num_reg_sets)1962061da546Spatrick DNBArchMachARM64::GetRegisterSetInfo(nub_size_t *num_reg_sets) {
1963061da546Spatrick   *num_reg_sets = k_num_register_sets;
1964061da546Spatrick   return g_reg_sets;
1965061da546Spatrick }
1966061da546Spatrick 
FixGenericRegisterNumber(uint32_t & set,uint32_t & reg)1967061da546Spatrick bool DNBArchMachARM64::FixGenericRegisterNumber(uint32_t &set, uint32_t &reg) {
1968061da546Spatrick   if (set == REGISTER_SET_GENERIC) {
1969061da546Spatrick     switch (reg) {
1970061da546Spatrick     case GENERIC_REGNUM_PC: // Program Counter
1971061da546Spatrick       set = e_regSetGPR;
1972061da546Spatrick       reg = gpr_pc;
1973061da546Spatrick       break;
1974061da546Spatrick 
1975061da546Spatrick     case GENERIC_REGNUM_SP: // Stack Pointer
1976061da546Spatrick       set = e_regSetGPR;
1977061da546Spatrick       reg = gpr_sp;
1978061da546Spatrick       break;
1979061da546Spatrick 
1980061da546Spatrick     case GENERIC_REGNUM_FP: // Frame Pointer
1981061da546Spatrick       set = e_regSetGPR;
1982061da546Spatrick       reg = gpr_fp;
1983061da546Spatrick       break;
1984061da546Spatrick 
1985061da546Spatrick     case GENERIC_REGNUM_RA: // Return Address
1986061da546Spatrick       set = e_regSetGPR;
1987061da546Spatrick       reg = gpr_lr;
1988061da546Spatrick       break;
1989061da546Spatrick 
1990061da546Spatrick     case GENERIC_REGNUM_FLAGS: // Processor flags register
1991061da546Spatrick       set = e_regSetGPR;
1992061da546Spatrick       reg = gpr_cpsr;
1993061da546Spatrick       break;
1994061da546Spatrick 
1995061da546Spatrick     case GENERIC_REGNUM_ARG1:
1996061da546Spatrick     case GENERIC_REGNUM_ARG2:
1997061da546Spatrick     case GENERIC_REGNUM_ARG3:
1998061da546Spatrick     case GENERIC_REGNUM_ARG4:
1999061da546Spatrick     case GENERIC_REGNUM_ARG5:
2000061da546Spatrick     case GENERIC_REGNUM_ARG6:
2001061da546Spatrick       set = e_regSetGPR;
2002061da546Spatrick       reg = gpr_x0 + reg - GENERIC_REGNUM_ARG1;
2003061da546Spatrick       break;
2004061da546Spatrick 
2005061da546Spatrick     default:
2006061da546Spatrick       return false;
2007061da546Spatrick     }
2008061da546Spatrick   }
2009061da546Spatrick   return true;
2010061da546Spatrick }
GetRegisterValue(uint32_t set,uint32_t reg,DNBRegisterValue * value)2011061da546Spatrick bool DNBArchMachARM64::GetRegisterValue(uint32_t set, uint32_t reg,
2012061da546Spatrick                                         DNBRegisterValue *value) {
2013061da546Spatrick   if (!FixGenericRegisterNumber(set, reg))
2014061da546Spatrick     return false;
2015061da546Spatrick 
2016061da546Spatrick   if (GetRegisterState(set, false) != KERN_SUCCESS)
2017061da546Spatrick     return false;
2018061da546Spatrick 
2019061da546Spatrick   const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
2020061da546Spatrick   if (regInfo) {
2021061da546Spatrick     value->info = *regInfo;
2022061da546Spatrick     switch (set) {
2023061da546Spatrick     case e_regSetGPR:
2024061da546Spatrick       if (reg <= gpr_pc) {
2025*f6aab3d8Srobert         switch (reg) {
2026*f6aab3d8Srobert #if __has_feature(ptrauth_calls) && defined(__LP64__)
2027*f6aab3d8Srobert         case gpr_pc:
2028*f6aab3d8Srobert           value->value.uint64 = clear_pac_bits(
2029*f6aab3d8Srobert               reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc));
2030*f6aab3d8Srobert           break;
2031*f6aab3d8Srobert         case gpr_lr:
2032*f6aab3d8Srobert           value->value.uint64 = clear_pac_bits(
2033*f6aab3d8Srobert               reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_lr));
2034*f6aab3d8Srobert           break;
2035*f6aab3d8Srobert         case gpr_sp:
2036*f6aab3d8Srobert           value->value.uint64 = clear_pac_bits(
2037*f6aab3d8Srobert               reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_sp));
2038*f6aab3d8Srobert           break;
2039*f6aab3d8Srobert         case gpr_fp:
2040*f6aab3d8Srobert           value->value.uint64 = clear_pac_bits(
2041*f6aab3d8Srobert               reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_fp));
2042*f6aab3d8Srobert           break;
2043061da546Spatrick #else
2044*f6aab3d8Srobert         case gpr_pc:
2045*f6aab3d8Srobert           value->value.uint64 = clear_pac_bits(m_state.context.gpr.__pc);
2046*f6aab3d8Srobert           break;
2047*f6aab3d8Srobert         case gpr_lr:
2048*f6aab3d8Srobert           value->value.uint64 = clear_pac_bits(m_state.context.gpr.__lr);
2049*f6aab3d8Srobert           break;
2050*f6aab3d8Srobert         case gpr_sp:
2051*f6aab3d8Srobert           value->value.uint64 = clear_pac_bits(m_state.context.gpr.__sp);
2052*f6aab3d8Srobert           break;
2053*f6aab3d8Srobert         case gpr_fp:
2054*f6aab3d8Srobert           value->value.uint64 = clear_pac_bits(m_state.context.gpr.__fp);
2055*f6aab3d8Srobert           break;
2056061da546Spatrick #endif
2057*f6aab3d8Srobert         default:
2058*f6aab3d8Srobert           value->value.uint64 = m_state.context.gpr.__x[reg];
2059*f6aab3d8Srobert         }
2060061da546Spatrick         return true;
2061061da546Spatrick       } else if (reg == gpr_cpsr) {
2062061da546Spatrick         value->value.uint32 = m_state.context.gpr.__cpsr;
2063061da546Spatrick         return true;
2064061da546Spatrick       }
2065061da546Spatrick       break;
2066061da546Spatrick 
2067061da546Spatrick     case e_regSetVFP:
2068061da546Spatrick 
2069061da546Spatrick       if (reg >= vfp_v0 && reg <= vfp_v31) {
2070061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2071061da546Spatrick         memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_v0],
2072061da546Spatrick                16);
2073061da546Spatrick #else
2074061da546Spatrick         memcpy(&value->value.v_uint8,
2075061da546Spatrick                ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16),
2076061da546Spatrick                16);
2077061da546Spatrick #endif
2078061da546Spatrick         return true;
2079061da546Spatrick       } else if (reg == vfp_fpsr) {
2080061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2081061da546Spatrick         memcpy(&value->value.uint32, &m_state.context.vfp.__fpsr, 4);
2082061da546Spatrick #else
2083061da546Spatrick         memcpy(&value->value.uint32,
2084061da546Spatrick                ((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 0, 4);
2085061da546Spatrick #endif
2086061da546Spatrick         return true;
2087061da546Spatrick       } else if (reg == vfp_fpcr) {
2088061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2089061da546Spatrick         memcpy(&value->value.uint32, &m_state.context.vfp.__fpcr, 4);
2090061da546Spatrick #else
2091061da546Spatrick         memcpy(&value->value.uint32,
2092061da546Spatrick                ((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 4, 4);
2093061da546Spatrick #endif
2094061da546Spatrick         return true;
2095061da546Spatrick       } else if (reg >= vfp_s0 && reg <= vfp_s31) {
2096061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2097061da546Spatrick         memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_s0],
2098061da546Spatrick                4);
2099061da546Spatrick #else
2100061da546Spatrick         memcpy(&value->value.v_uint8,
2101061da546Spatrick                ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16),
2102061da546Spatrick                4);
2103061da546Spatrick #endif
2104061da546Spatrick         return true;
2105061da546Spatrick       } else if (reg >= vfp_d0 && reg <= vfp_d31) {
2106061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2107061da546Spatrick         memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_d0],
2108061da546Spatrick                8);
2109061da546Spatrick #else
2110061da546Spatrick         memcpy(&value->value.v_uint8,
2111061da546Spatrick                ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16),
2112061da546Spatrick                8);
2113061da546Spatrick #endif
2114061da546Spatrick         return true;
2115061da546Spatrick       }
2116061da546Spatrick       break;
2117061da546Spatrick 
2118061da546Spatrick     case e_regSetEXC:
2119061da546Spatrick       if (reg == exc_far) {
2120061da546Spatrick         value->value.uint64 = m_state.context.exc.__far;
2121061da546Spatrick         return true;
2122061da546Spatrick       } else if (reg == exc_esr) {
2123061da546Spatrick         value->value.uint32 = m_state.context.exc.__esr;
2124061da546Spatrick         return true;
2125061da546Spatrick       } else if (reg == exc_exception) {
2126061da546Spatrick         value->value.uint32 = m_state.context.exc.__exception;
2127061da546Spatrick         return true;
2128061da546Spatrick       }
2129061da546Spatrick       break;
2130061da546Spatrick     }
2131061da546Spatrick   }
2132061da546Spatrick   return false;
2133061da546Spatrick }
2134061da546Spatrick 
SetRegisterValue(uint32_t set,uint32_t reg,const DNBRegisterValue * value)2135061da546Spatrick bool DNBArchMachARM64::SetRegisterValue(uint32_t set, uint32_t reg,
2136061da546Spatrick                                         const DNBRegisterValue *value) {
2137061da546Spatrick   if (!FixGenericRegisterNumber(set, reg))
2138061da546Spatrick     return false;
2139061da546Spatrick 
2140061da546Spatrick   if (GetRegisterState(set, false) != KERN_SUCCESS)
2141061da546Spatrick     return false;
2142061da546Spatrick 
2143061da546Spatrick   bool success = false;
2144061da546Spatrick   const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
2145061da546Spatrick   if (regInfo) {
2146061da546Spatrick     switch (set) {
2147061da546Spatrick     case e_regSetGPR:
2148061da546Spatrick       if (reg <= gpr_pc) {
2149061da546Spatrick #if defined(__LP64__)
2150061da546Spatrick           uint64_t signed_value = value->value.uint64;
2151061da546Spatrick #if __has_feature(ptrauth_calls)
2152061da546Spatrick           // The incoming value could be garbage.  Strip it to avoid
2153061da546Spatrick           // trapping when it gets resigned in the thread state.
2154061da546Spatrick           signed_value = (uint64_t) ptrauth_strip((void*) signed_value, ptrauth_key_function_pointer);
2155061da546Spatrick           signed_value = (uint64_t) ptrauth_sign_unauthenticated((void*) signed_value, ptrauth_key_function_pointer, 0);
2156061da546Spatrick #endif
2157061da546Spatrick         if (reg == gpr_pc)
2158061da546Spatrick          arm_thread_state64_set_pc_fptr (m_state.context.gpr, (void*) signed_value);
2159061da546Spatrick         else if (reg == gpr_lr)
2160061da546Spatrick           arm_thread_state64_set_lr_fptr (m_state.context.gpr, (void*) signed_value);
2161061da546Spatrick         else if (reg == gpr_sp)
2162061da546Spatrick           arm_thread_state64_set_sp (m_state.context.gpr, value->value.uint64);
2163061da546Spatrick         else if (reg == gpr_fp)
2164061da546Spatrick           arm_thread_state64_set_fp (m_state.context.gpr, value->value.uint64);
2165061da546Spatrick         else
2166061da546Spatrick           m_state.context.gpr.__x[reg] = value->value.uint64;
2167061da546Spatrick #else
2168061da546Spatrick         m_state.context.gpr.__x[reg] = value->value.uint64;
2169061da546Spatrick #endif
2170061da546Spatrick         success = true;
2171061da546Spatrick       } else if (reg == gpr_cpsr) {
2172061da546Spatrick         m_state.context.gpr.__cpsr = value->value.uint32;
2173061da546Spatrick         success = true;
2174061da546Spatrick       }
2175061da546Spatrick       break;
2176061da546Spatrick 
2177061da546Spatrick     case e_regSetVFP:
2178061da546Spatrick       if (reg >= vfp_v0 && reg <= vfp_v31) {
2179061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2180061da546Spatrick         memcpy(&m_state.context.vfp.__v[reg - vfp_v0], &value->value.v_uint8,
2181061da546Spatrick                16);
2182061da546Spatrick #else
2183061da546Spatrick         memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16),
2184061da546Spatrick                &value->value.v_uint8, 16);
2185061da546Spatrick #endif
2186061da546Spatrick         success = true;
2187061da546Spatrick       } else if (reg == vfp_fpsr) {
2188061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2189061da546Spatrick         memcpy(&m_state.context.vfp.__fpsr, &value->value.uint32, 4);
2190061da546Spatrick #else
2191061da546Spatrick         memcpy(((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 0,
2192061da546Spatrick                &value->value.uint32, 4);
2193061da546Spatrick #endif
2194061da546Spatrick         success = true;
2195061da546Spatrick       } else if (reg == vfp_fpcr) {
2196061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2197061da546Spatrick         memcpy(&m_state.context.vfp.__fpcr, &value->value.uint32, 4);
2198061da546Spatrick #else
2199061da546Spatrick         memcpy(((uint8_t *)m_state.context.vfp.opaque) + (32 * 16) + 4,
2200061da546Spatrick                &value->value.uint32, 4);
2201061da546Spatrick #endif
2202061da546Spatrick         success = true;
2203061da546Spatrick       } else if (reg >= vfp_s0 && reg <= vfp_s31) {
2204061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2205061da546Spatrick         memcpy(&m_state.context.vfp.__v[reg - vfp_s0], &value->value.v_uint8,
2206061da546Spatrick                4);
2207061da546Spatrick #else
2208061da546Spatrick         memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16),
2209061da546Spatrick                &value->value.v_uint8, 4);
2210061da546Spatrick #endif
2211061da546Spatrick         success = true;
2212061da546Spatrick       } else if (reg >= vfp_d0 && reg <= vfp_d31) {
2213061da546Spatrick #if defined(__arm64__) || defined(__aarch64__)
2214061da546Spatrick         memcpy(&m_state.context.vfp.__v[reg - vfp_d0], &value->value.v_uint8,
2215061da546Spatrick                8);
2216061da546Spatrick #else
2217061da546Spatrick         memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16),
2218061da546Spatrick                &value->value.v_uint8, 8);
2219061da546Spatrick #endif
2220061da546Spatrick         success = true;
2221061da546Spatrick       }
2222061da546Spatrick       break;
2223061da546Spatrick 
2224061da546Spatrick     case e_regSetEXC:
2225061da546Spatrick       if (reg == exc_far) {
2226061da546Spatrick         m_state.context.exc.__far = value->value.uint64;
2227061da546Spatrick         success = true;
2228061da546Spatrick       } else if (reg == exc_esr) {
2229061da546Spatrick         m_state.context.exc.__esr = value->value.uint32;
2230061da546Spatrick         success = true;
2231061da546Spatrick       } else if (reg == exc_exception) {
2232061da546Spatrick         m_state.context.exc.__exception = value->value.uint32;
2233061da546Spatrick         success = true;
2234061da546Spatrick       }
2235061da546Spatrick       break;
2236061da546Spatrick     }
2237061da546Spatrick   }
2238061da546Spatrick   if (success)
2239061da546Spatrick     return SetRegisterState(set) == KERN_SUCCESS;
2240061da546Spatrick   return false;
2241061da546Spatrick }
2242061da546Spatrick 
GetRegisterState(int set,bool force)2243061da546Spatrick kern_return_t DNBArchMachARM64::GetRegisterState(int set, bool force) {
2244061da546Spatrick   switch (set) {
2245061da546Spatrick   case e_regSetALL:
2246061da546Spatrick     return GetGPRState(force) | GetVFPState(force) | GetEXCState(force) |
2247061da546Spatrick            GetDBGState(force);
2248061da546Spatrick   case e_regSetGPR:
2249061da546Spatrick     return GetGPRState(force);
2250061da546Spatrick   case e_regSetVFP:
2251061da546Spatrick     return GetVFPState(force);
2252061da546Spatrick   case e_regSetEXC:
2253061da546Spatrick     return GetEXCState(force);
2254061da546Spatrick   case e_regSetDBG:
2255061da546Spatrick     return GetDBGState(force);
2256061da546Spatrick   default:
2257061da546Spatrick     break;
2258061da546Spatrick   }
2259061da546Spatrick   return KERN_INVALID_ARGUMENT;
2260061da546Spatrick }
2261061da546Spatrick 
SetRegisterState(int set)2262061da546Spatrick kern_return_t DNBArchMachARM64::SetRegisterState(int set) {
2263061da546Spatrick   // Make sure we have a valid context to set.
2264061da546Spatrick   kern_return_t err = GetRegisterState(set, false);
2265061da546Spatrick   if (err != KERN_SUCCESS)
2266061da546Spatrick     return err;
2267061da546Spatrick 
2268061da546Spatrick   switch (set) {
2269061da546Spatrick   case e_regSetALL:
2270061da546Spatrick     return SetGPRState() | SetVFPState() | SetEXCState() | SetDBGState(false);
2271061da546Spatrick   case e_regSetGPR:
2272061da546Spatrick     return SetGPRState();
2273061da546Spatrick   case e_regSetVFP:
2274061da546Spatrick     return SetVFPState();
2275061da546Spatrick   case e_regSetEXC:
2276061da546Spatrick     return SetEXCState();
2277061da546Spatrick   case e_regSetDBG:
2278061da546Spatrick     return SetDBGState(false);
2279061da546Spatrick   default:
2280061da546Spatrick     break;
2281061da546Spatrick   }
2282061da546Spatrick   return KERN_INVALID_ARGUMENT;
2283061da546Spatrick }
2284061da546Spatrick 
RegisterSetStateIsValid(int set) const2285061da546Spatrick bool DNBArchMachARM64::RegisterSetStateIsValid(int set) const {
2286061da546Spatrick   return m_state.RegsAreValid(set);
2287061da546Spatrick }
2288061da546Spatrick 
GetRegisterContext(void * buf,nub_size_t buf_len)2289061da546Spatrick nub_size_t DNBArchMachARM64::GetRegisterContext(void *buf, nub_size_t buf_len) {
2290061da546Spatrick   nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) +
2291061da546Spatrick                     sizeof(m_state.context.exc);
2292061da546Spatrick 
2293061da546Spatrick   if (buf && buf_len) {
2294061da546Spatrick     if (size > buf_len)
2295061da546Spatrick       size = buf_len;
2296061da546Spatrick 
2297061da546Spatrick     bool force = false;
2298061da546Spatrick     if (GetGPRState(force) | GetVFPState(force) | GetEXCState(force))
2299061da546Spatrick       return 0;
2300061da546Spatrick 
2301061da546Spatrick     // Copy each struct individually to avoid any padding that might be between
2302061da546Spatrick     // the structs in m_state.context
2303061da546Spatrick     uint8_t *p = (uint8_t *)buf;
2304061da546Spatrick     ::memcpy(p, &m_state.context.gpr, sizeof(m_state.context.gpr));
2305061da546Spatrick     p += sizeof(m_state.context.gpr);
2306061da546Spatrick     ::memcpy(p, &m_state.context.vfp, sizeof(m_state.context.vfp));
2307061da546Spatrick     p += sizeof(m_state.context.vfp);
2308061da546Spatrick     ::memcpy(p, &m_state.context.exc, sizeof(m_state.context.exc));
2309061da546Spatrick     p += sizeof(m_state.context.exc);
2310061da546Spatrick 
2311061da546Spatrick     size_t bytes_written = p - (uint8_t *)buf;
2312061da546Spatrick     UNUSED_IF_ASSERT_DISABLED(bytes_written);
2313061da546Spatrick     assert(bytes_written == size);
2314061da546Spatrick   }
2315061da546Spatrick   DNBLogThreadedIf(
2316061da546Spatrick       LOG_THREAD,
2317061da546Spatrick       "DNBArchMachARM64::GetRegisterContext (buf = %p, len = %zu) => %zu", buf,
2318061da546Spatrick       buf_len, size);
2319061da546Spatrick   // Return the size of the register context even if NULL was passed in
2320061da546Spatrick   return size;
2321061da546Spatrick }
2322061da546Spatrick 
SetRegisterContext(const void * buf,nub_size_t buf_len)2323061da546Spatrick nub_size_t DNBArchMachARM64::SetRegisterContext(const void *buf,
2324061da546Spatrick                                                 nub_size_t buf_len) {
2325061da546Spatrick   nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) +
2326061da546Spatrick                     sizeof(m_state.context.exc);
2327061da546Spatrick 
2328061da546Spatrick   if (buf == NULL || buf_len == 0)
2329061da546Spatrick     size = 0;
2330061da546Spatrick 
2331061da546Spatrick   if (size) {
2332061da546Spatrick     if (size > buf_len)
2333061da546Spatrick       size = buf_len;
2334061da546Spatrick 
2335061da546Spatrick     // Copy each struct individually to avoid any padding that might be between
2336061da546Spatrick     // the structs in m_state.context
2337be691f3bSpatrick     uint8_t *p = const_cast<uint8_t*>(reinterpret_cast<const uint8_t *>(buf));
2338061da546Spatrick     ::memcpy(&m_state.context.gpr, p, sizeof(m_state.context.gpr));
2339061da546Spatrick     p += sizeof(m_state.context.gpr);
2340061da546Spatrick     ::memcpy(&m_state.context.vfp, p, sizeof(m_state.context.vfp));
2341061da546Spatrick     p += sizeof(m_state.context.vfp);
2342061da546Spatrick     ::memcpy(&m_state.context.exc, p, sizeof(m_state.context.exc));
2343061da546Spatrick     p += sizeof(m_state.context.exc);
2344061da546Spatrick 
2345be691f3bSpatrick     size_t bytes_written = p - reinterpret_cast<const uint8_t *>(buf);
2346061da546Spatrick     UNUSED_IF_ASSERT_DISABLED(bytes_written);
2347061da546Spatrick     assert(bytes_written == size);
2348061da546Spatrick     SetGPRState();
2349061da546Spatrick     SetVFPState();
2350061da546Spatrick     SetEXCState();
2351061da546Spatrick   }
2352061da546Spatrick   DNBLogThreadedIf(
2353061da546Spatrick       LOG_THREAD,
2354061da546Spatrick       "DNBArchMachARM64::SetRegisterContext (buf = %p, len = %zu) => %zu", buf,
2355061da546Spatrick       buf_len, size);
2356061da546Spatrick   return size;
2357061da546Spatrick }
2358061da546Spatrick 
SaveRegisterState()2359061da546Spatrick uint32_t DNBArchMachARM64::SaveRegisterState() {
2360061da546Spatrick   kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber());
2361061da546Spatrick   DNBLogThreadedIf(
2362061da546Spatrick       LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u "
2363061da546Spatrick                   "(SetGPRState() for stop_count = %u)",
2364061da546Spatrick       m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
2365061da546Spatrick 
2366061da546Spatrick   // Always re-read the registers because above we call thread_abort_safely();
2367061da546Spatrick   bool force = true;
2368061da546Spatrick 
2369061da546Spatrick   if ((kret = GetGPRState(force)) != KERN_SUCCESS) {
2370061da546Spatrick     DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () "
2371061da546Spatrick                                  "error: GPR regs failed to read: %u ",
2372061da546Spatrick                      kret);
2373061da546Spatrick   } else if ((kret = GetVFPState(force)) != KERN_SUCCESS) {
2374061da546Spatrick     DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () "
2375061da546Spatrick                                  "error: %s regs failed to read: %u",
2376061da546Spatrick                      "VFP", kret);
2377061da546Spatrick   } else {
2378061da546Spatrick     const uint32_t save_id = GetNextRegisterStateSaveID();
2379061da546Spatrick     m_saved_register_states[save_id] = m_state.context;
2380061da546Spatrick     return save_id;
2381061da546Spatrick   }
2382061da546Spatrick   return UINT32_MAX;
2383061da546Spatrick }
2384061da546Spatrick 
RestoreRegisterState(uint32_t save_id)2385061da546Spatrick bool DNBArchMachARM64::RestoreRegisterState(uint32_t save_id) {
2386061da546Spatrick   SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id);
2387061da546Spatrick   if (pos != m_saved_register_states.end()) {
2388061da546Spatrick     m_state.context.gpr = pos->second.gpr;
2389061da546Spatrick     m_state.context.vfp = pos->second.vfp;
2390061da546Spatrick     kern_return_t kret;
2391061da546Spatrick     bool success = true;
2392061da546Spatrick     if ((kret = SetGPRState()) != KERN_SUCCESS) {
2393061da546Spatrick       DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState "
2394061da546Spatrick                                    "(save_id = %u) error: GPR regs failed to "
2395061da546Spatrick                                    "write: %u",
2396061da546Spatrick                        save_id, kret);
2397061da546Spatrick       success = false;
2398061da546Spatrick     } else if ((kret = SetVFPState()) != KERN_SUCCESS) {
2399061da546Spatrick       DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState "
2400061da546Spatrick                                    "(save_id = %u) error: %s regs failed to "
2401061da546Spatrick                                    "write: %u",
2402061da546Spatrick                        save_id, "VFP", kret);
2403061da546Spatrick       success = false;
2404061da546Spatrick     }
2405061da546Spatrick     m_saved_register_states.erase(pos);
2406061da546Spatrick     return success;
2407061da546Spatrick   }
2408061da546Spatrick   return false;
2409061da546Spatrick }
2410061da546Spatrick 
2411061da546Spatrick #endif // #if defined (ARM_THREAD_STATE64_COUNT)
2412061da546Spatrick #endif // #if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
2413