llvm-project/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp

llvm-project source @ eb96d65 2026-09-08 · 3175 lines · view on GitHub
1//===-- DNBArchImplARM64.cpp ------------------------------------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// Created by Greg Clayton on 6/25/07. 10// 11//===----------------------------------------------------------------------===// 12 13#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 14 15#include "MacOSX/arm64/DNBArchImplARM64.h" 16 17#if defined(ARM_THREAD_STATE64_COUNT) 18 19#include "DNB.h" 20#include "DNBBreakpoint.h" 21#include "DNBLog.h" 22#include "DNBRegisterInfo.h" 23#include "MacOSX/MachProcess.h" 24#include "MacOSX/MachThread.h" 25 26#include <cinttypes> 27#include <sys/sysctl.h> 28 29#undef DEBUGSERVER_IS_ARM64E 30#if __has_feature(ptrauth_calls) 31#include <ptrauth.h> 32#if defined(__LP64__) 33#define DEBUGSERVER_IS_ARM64E 1 34#endif 35#endif 36 37// Break only in privileged or user mode 38// (PAC bits in the DBGWVRn_EL1 watchpoint control register) 39#define S_USER ((uint32_t)(2u << 1)) 40 41#define BCR_ENABLE ((uint32_t)(1u)) 42#define WCR_ENABLE ((uint32_t)(1u)) 43 44// Watchpoint load/store 45// (LSC bits in the DBGWVRn_EL1 watchpoint control register) 46#define WCR_LOAD ((uint32_t)(1u << 3)) 47#define WCR_STORE ((uint32_t)(1u << 4)) 48 49// Single instruction step 50// (SS bit in the MDSCR_EL1 register) 51#define SS_ENABLE ((uint32_t)(1u)) 52 53static const uint8_t g_arm64_breakpoint_opcode[] = { 54 0x00, 0x00, 0x20, 0xD4}; // "brk #0", 0xd4200000 in BE byte order 55 56// If we need to set one logical watchpoint by using 57// two hardware watchpoint registers, the watchpoint 58// will be split into a "high" and "low" watchpoint. 59// Record both of them in the LoHi array. 60 61// It's safe to initialize to all 0's since 62// hi > lo and therefore LoHi[i] cannot be 0. 63static uint32_t LoHi[16] = {0}; 64 65void DNBArchMachARM64::Initialize() { 66 DNBArchPluginInfo arch_plugin_info = { 67 CPU_TYPE_ARM64, DNBArchMachARM64::Create, 68 DNBArchMachARM64::GetRegisterSetInfo, 69 DNBArchMachARM64::SoftwareBreakpointOpcode}; 70 71 // Register this arch plug-in with the main protocol class 72 DNBArchProtocol::RegisterArchPlugin(arch_plugin_info); 73 74 DNBArchPluginInfo arch_plugin_info_32 = { 75 CPU_TYPE_ARM64_32, DNBArchMachARM64::Create, 76 DNBArchMachARM64::GetRegisterSetInfo, 77 DNBArchMachARM64::SoftwareBreakpointOpcode}; 78 79 // Register this arch plug-in with the main protocol class 80 DNBArchProtocol::RegisterArchPlugin(arch_plugin_info_32); 81} 82 83DNBArchProtocol *DNBArchMachARM64::Create(MachThread *thread) { 84 DNBArchMachARM64 *obj = new DNBArchMachARM64(thread); 85 86 return obj; 87} 88 89const uint8_t * 90DNBArchMachARM64::SoftwareBreakpointOpcode(nub_size_t byte_size) { 91 return g_arm64_breakpoint_opcode; 92} 93 94uint32_t DNBArchMachARM64::GetCPUType() { return CPU_TYPE_ARM64; } 95 96static std::once_flag g_cpu_has_sme_once; 97bool DNBArchMachARM64::CPUHasSME() { 98 static bool g_has_sme = false; 99 std::call_once(g_cpu_has_sme_once, []() { 100 int ret = 0; 101 size_t size = sizeof(ret); 102 if (sysctlbyname("hw.optional.arm.FEAT_SME", &ret, &size, NULL, 0) != -1) 103 g_has_sme = ret == 1; 104 }); 105 return g_has_sme; 106} 107 108static std::once_flag g_cpu_has_sme2_once; 109bool DNBArchMachARM64::CPUHasSME2() { 110 static bool g_has_sme2 = false; 111 std::call_once(g_cpu_has_sme2_once, []() { 112 int ret = 0; 113 size_t size = sizeof(ret); 114 if (sysctlbyname("hw.optional.arm.FEAT_SME2", &ret, &size, NULL, 0) != -1) 115 g_has_sme2 = ret == 1; 116 }); 117 return g_has_sme2; 118} 119 120static std::once_flag g_sme_max_svl_once; 121unsigned int DNBArchMachARM64::GetSMEMaxSVL() { 122 static unsigned int g_sme_max_svl = 0; 123 std::call_once(g_sme_max_svl_once, []() { 124 if (CPUHasSME()) { 125 unsigned int ret = 0; 126 size_t size = sizeof(ret); 127 if (sysctlbyname("hw.optional.arm.sme_max_svl_b", &ret, &size, NULL, 0) != 128 -1) 129 g_sme_max_svl = ret; 130 } 131 }); 132 return g_sme_max_svl; 133} 134 135uint64_t DNBArchMachARM64::GetPC(uint64_t failValue) { 136 // Get program counter 137 if (GetGPRState(false) == KERN_SUCCESS) 138#if defined(DEBUGSERVER_IS_ARM64E) 139 return DNBFixAddress( 140 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc)); 141#else 142 return m_state.context.gpr.__pc; 143#endif 144 return failValue; 145} 146 147kern_return_t DNBArchMachARM64::SetPC(uint64_t value) { 148 // Get program counter 149 kern_return_t err = GetGPRState(false); 150 if (err == KERN_SUCCESS) { 151#if defined(__LP64__) 152#if __has_feature(ptrauth_calls) 153 // The incoming value could be garbage. Strip it to avoid 154 // trapping when it gets resigned in the thread state. 155 value = (uint64_t) ptrauth_strip((void*) value, ptrauth_key_function_pointer); 156 value = (uint64_t) ptrauth_sign_unauthenticated((void*) value, ptrauth_key_function_pointer, 0); 157#endif 158 arm_thread_state64_set_pc_fptr (m_state.context.gpr, (void*) value); 159#else 160 m_state.context.gpr.__pc = value; 161#endif 162 err = SetGPRState(); 163 } 164 return err == KERN_SUCCESS; 165} 166 167uint64_t DNBArchMachARM64::GetSP(uint64_t failValue) { 168 // Get stack pointer 169 if (GetGPRState(false) == KERN_SUCCESS) 170#if defined(DEBUGSERVER_IS_ARM64E) 171 return DNBFixAddress( 172 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_sp)); 173#else 174 return m_state.context.gpr.__sp; 175#endif 176 return failValue; 177} 178 179static void log_signed_registers(arm_thread_state64_t *gpr, const char *desc) { 180 if (DNBLogEnabledForAny(LOG_THREAD)) { 181 const char *log_str = "%s signed regs " 182 "\n fp=%16.16llx" 183 "\n lr=%16.16llx" 184 "\n sp=%16.16llx" 185 "\n pc=%16.16llx"; 186#if defined(DEBUGSERVER_IS_ARM64E) 187 DNBLogThreaded(log_str, desc, reinterpret_cast<uint64_t>(gpr->__opaque_fp), 188 reinterpret_cast<uint64_t>(gpr->__opaque_lr), 189 reinterpret_cast<uint64_t>(gpr->__opaque_sp), 190 reinterpret_cast<uint64_t>(gpr->__opaque_pc)); 191#else 192 DNBLogThreaded(log_str, desc, gpr->__fp, gpr->__lr, gpr->__sp, gpr->__pc); 193#endif 194 } 195} 196 197kern_return_t DNBArchMachARM64::GetGPRState(bool force) { 198 int set = e_regSetGPR; 199 // Check if we have valid cached registers 200 if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) 201 return KERN_SUCCESS; 202 203 // Read the registers from our thread 204 mach_msg_type_number_t count = e_regSetGPRCount; 205 kern_return_t kret = 206 ::thread_get_state(m_thread->MachPortNumber(), ARM_THREAD_STATE64, 207 (thread_state_t)&m_state.context.gpr, &count); 208 log_signed_registers(&m_state.context.gpr, "Values from thread_get_state"); 209 210#if defined(THREAD_CONVERT_THREAD_STATE_TO_SELF) && defined(__LP64__) 211 if (kret == KERN_SUCCESS) { 212 mach_msg_type_number_t newcount = ARM_THREAD_STATE64_COUNT; 213 arm_thread_state64_t new_gpr; 214 kern_return_t convert_kret = thread_convert_thread_state( 215 m_thread->MachPortNumber(), THREAD_CONVERT_THREAD_STATE_TO_SELF, 216 ARM_THREAD_STATE64, (thread_state_t)&m_state.context.gpr, count, 217 (thread_state_t)&new_gpr, &newcount); 218 DNBLogThreadedIf( 219 LOG_THREAD, 220 "converted register values " 221 "to debugserver's keys, return value %d, old count %d new count %d", 222 convert_kret, count, newcount); 223 if (convert_kret == KERN_SUCCESS) 224 memcpy(&m_state.context.gpr, &new_gpr, count * 4); 225 log_signed_registers(&m_state.context.gpr, 226 "Values after thread_convert_thread_state"); 227 } 228#endif // THREAD_CONVERT_THREAD_STATE_TO_SELF 229 230 if (DNBLogEnabledForAny(LOG_THREAD)) { 231#if defined(DEBUGSERVER_IS_ARM64E) 232 uint64_t log_fp = DNBFixAddress( 233 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_fp)); 234 uint64_t log_lr = DNBFixAddress( 235 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_lr)); 236 uint64_t log_sp = DNBFixAddress( 237 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_sp)); 238 uint64_t log_pc = DNBFixAddress( 239 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc)); 240#else 241 uint64_t log_fp = m_state.context.gpr.__fp; 242 uint64_t log_lr = m_state.context.gpr.__lr; 243 uint64_t log_sp = m_state.context.gpr.__sp; 244 uint64_t log_pc = m_state.context.gpr.__pc; 245#endif 246 uint64_t *x = &m_state.context.gpr.__x[0]; 247 DNBLogThreaded( 248 "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = %u) regs" 249 "\n x0=%16.16llx" 250 "\n x1=%16.16llx" 251 "\n x2=%16.16llx" 252 "\n x3=%16.16llx" 253 "\n x4=%16.16llx" 254 "\n x5=%16.16llx" 255 "\n x6=%16.16llx" 256 "\n x7=%16.16llx" 257 "\n x8=%16.16llx" 258 "\n x9=%16.16llx" 259 "\n x10=%16.16llx" 260 "\n x11=%16.16llx" 261 "\n x12=%16.16llx" 262 "\n x13=%16.16llx" 263 "\n x14=%16.16llx" 264 "\n x15=%16.16llx" 265 "\n x16=%16.16llx" 266 "\n x17=%16.16llx" 267 "\n x18=%16.16llx" 268 "\n x19=%16.16llx" 269 "\n x20=%16.16llx" 270 "\n x21=%16.16llx" 271 "\n x22=%16.16llx" 272 "\n x23=%16.16llx" 273 "\n x24=%16.16llx" 274 "\n x25=%16.16llx" 275 "\n x26=%16.16llx" 276 "\n x27=%16.16llx" 277 "\n x28=%16.16llx" 278 "\n fp=%16.16llx" 279 "\n lr=%16.16llx" 280 "\n sp=%16.16llx" 281 "\n pc=%16.16llx" 282 "\n cpsr=%8.8x", 283 m_thread->MachPortNumber(), e_regSetGPR, e_regSetGPRCount, kret, count, 284 x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[0], x[11], 285 x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21], 286 x[22], x[23], x[24], x[25], x[26], x[27], x[28], 287 log_fp, log_lr, log_sp, log_pc, m_state.context.gpr.__cpsr); 288 } 289 m_state.SetError(set, Read, kret); 290 return kret; 291} 292 293kern_return_t DNBArchMachARM64::GetVFPState(bool force) { 294 int set = e_regSetVFP; 295 // Check if we have valid cached registers 296 if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) 297 return KERN_SUCCESS; 298 299 // Read the registers from our thread 300 mach_msg_type_number_t count = e_regSetVFPCount; 301 kern_return_t kret = 302 ::thread_get_state(m_thread->MachPortNumber(), ARM_NEON_STATE64, 303 (thread_state_t)&m_state.context.vfp, &count); 304 if (DNBLogEnabledForAny(LOG_THREAD)) { 305#if defined(__arm64__) || defined(__aarch64__) 306 DNBLogThreaded( 307 "thread_get_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs" 308 "\n q0 = 0x%16.16llx%16.16llx" 309 "\n q1 = 0x%16.16llx%16.16llx" 310 "\n q2 = 0x%16.16llx%16.16llx" 311 "\n q3 = 0x%16.16llx%16.16llx" 312 "\n q4 = 0x%16.16llx%16.16llx" 313 "\n q5 = 0x%16.16llx%16.16llx" 314 "\n q6 = 0x%16.16llx%16.16llx" 315 "\n q7 = 0x%16.16llx%16.16llx" 316 "\n q8 = 0x%16.16llx%16.16llx" 317 "\n q9 = 0x%16.16llx%16.16llx" 318 "\n q10 = 0x%16.16llx%16.16llx" 319 "\n q11 = 0x%16.16llx%16.16llx" 320 "\n q12 = 0x%16.16llx%16.16llx" 321 "\n q13 = 0x%16.16llx%16.16llx" 322 "\n q14 = 0x%16.16llx%16.16llx" 323 "\n q15 = 0x%16.16llx%16.16llx" 324 "\n q16 = 0x%16.16llx%16.16llx" 325 "\n q17 = 0x%16.16llx%16.16llx" 326 "\n q18 = 0x%16.16llx%16.16llx" 327 "\n q19 = 0x%16.16llx%16.16llx" 328 "\n q20 = 0x%16.16llx%16.16llx" 329 "\n q21 = 0x%16.16llx%16.16llx" 330 "\n q22 = 0x%16.16llx%16.16llx" 331 "\n q23 = 0x%16.16llx%16.16llx" 332 "\n q24 = 0x%16.16llx%16.16llx" 333 "\n q25 = 0x%16.16llx%16.16llx" 334 "\n q26 = 0x%16.16llx%16.16llx" 335 "\n q27 = 0x%16.16llx%16.16llx" 336 "\n q28 = 0x%16.16llx%16.16llx" 337 "\n q29 = 0x%16.16llx%16.16llx" 338 "\n q30 = 0x%16.16llx%16.16llx" 339 "\n q31 = 0x%16.16llx%16.16llx" 340 "\n fpsr = 0x%8.8x" 341 "\n fpcr = 0x%8.8x\n\n", 342 m_thread->MachPortNumber(), e_regSetVFP, e_regSetVFPCount, kret, count, 343 ((uint64_t *)&m_state.context.vfp.__v[0])[0], 344 ((uint64_t *)&m_state.context.vfp.__v[0])[1], 345 ((uint64_t *)&m_state.context.vfp.__v[1])[0], 346 ((uint64_t *)&m_state.context.vfp.__v[1])[1], 347 ((uint64_t *)&m_state.context.vfp.__v[2])[0], 348 ((uint64_t *)&m_state.context.vfp.__v[2])[1], 349 ((uint64_t *)&m_state.context.vfp.__v[3])[0], 350 ((uint64_t *)&m_state.context.vfp.__v[3])[1], 351 ((uint64_t *)&m_state.context.vfp.__v[4])[0], 352 ((uint64_t *)&m_state.context.vfp.__v[4])[1], 353 ((uint64_t *)&m_state.context.vfp.__v[5])[0], 354 ((uint64_t *)&m_state.context.vfp.__v[5])[1], 355 ((uint64_t *)&m_state.context.vfp.__v[6])[0], 356 ((uint64_t *)&m_state.context.vfp.__v[6])[1], 357 ((uint64_t *)&m_state.context.vfp.__v[7])[0], 358 ((uint64_t *)&m_state.context.vfp.__v[7])[1], 359 ((uint64_t *)&m_state.context.vfp.__v[8])[0], 360 ((uint64_t *)&m_state.context.vfp.__v[8])[1], 361 ((uint64_t *)&m_state.context.vfp.__v[9])[0], 362 ((uint64_t *)&m_state.context.vfp.__v[9])[1], 363 ((uint64_t *)&m_state.context.vfp.__v[10])[0], 364 ((uint64_t *)&m_state.context.vfp.__v[10])[1], 365 ((uint64_t *)&m_state.context.vfp.__v[11])[0], 366 ((uint64_t *)&m_state.context.vfp.__v[11])[1], 367 ((uint64_t *)&m_state.context.vfp.__v[12])[0], 368 ((uint64_t *)&m_state.context.vfp.__v[12])[1], 369 ((uint64_t *)&m_state.context.vfp.__v[13])[0], 370 ((uint64_t *)&m_state.context.vfp.__v[13])[1], 371 ((uint64_t *)&m_state.context.vfp.__v[14])[0], 372 ((uint64_t *)&m_state.context.vfp.__v[14])[1], 373 ((uint64_t *)&m_state.context.vfp.__v[15])[0], 374 ((uint64_t *)&m_state.context.vfp.__v[15])[1], 375 ((uint64_t *)&m_state.context.vfp.__v[16])[0], 376 ((uint64_t *)&m_state.context.vfp.__v[16])[1], 377 ((uint64_t *)&m_state.context.vfp.__v[17])[0], 378 ((uint64_t *)&m_state.context.vfp.__v[17])[1], 379 ((uint64_t *)&m_state.context.vfp.__v[18])[0], 380 ((uint64_t *)&m_state.context.vfp.__v[18])[1], 381 ((uint64_t *)&m_state.context.vfp.__v[19])[0], 382 ((uint64_t *)&m_state.context.vfp.__v[19])[1], 383 ((uint64_t *)&m_state.context.vfp.__v[20])[0], 384 ((uint64_t *)&m_state.context.vfp.__v[20])[1], 385 ((uint64_t *)&m_state.context.vfp.__v[21])[0], 386 ((uint64_t *)&m_state.context.vfp.__v[21])[1], 387 ((uint64_t *)&m_state.context.vfp.__v[22])[0], 388 ((uint64_t *)&m_state.context.vfp.__v[22])[1], 389 ((uint64_t *)&m_state.context.vfp.__v[23])[0], 390 ((uint64_t *)&m_state.context.vfp.__v[23])[1], 391 ((uint64_t *)&m_state.context.vfp.__v[24])[0], 392 ((uint64_t *)&m_state.context.vfp.__v[24])[1], 393 ((uint64_t *)&m_state.context.vfp.__v[25])[0], 394 ((uint64_t *)&m_state.context.vfp.__v[25])[1], 395 ((uint64_t *)&m_state.context.vfp.__v[26])[0], 396 ((uint64_t *)&m_state.context.vfp.__v[26])[1], 397 ((uint64_t *)&m_state.context.vfp.__v[27])[0], 398 ((uint64_t *)&m_state.context.vfp.__v[27])[1], 399 ((uint64_t *)&m_state.context.vfp.__v[28])[0], 400 ((uint64_t *)&m_state.context.vfp.__v[28])[1], 401 ((uint64_t *)&m_state.context.vfp.__v[29])[0], 402 ((uint64_t *)&m_state.context.vfp.__v[29])[1], 403 ((uint64_t *)&m_state.context.vfp.__v[30])[0], 404 ((uint64_t *)&m_state.context.vfp.__v[30])[1], 405 ((uint64_t *)&m_state.context.vfp.__v[31])[0], 406 ((uint64_t *)&m_state.context.vfp.__v[31])[1], 407 m_state.context.vfp.__fpsr, m_state.context.vfp.__fpcr); 408#endif 409 } 410 m_state.SetError(set, Read, kret); 411 return kret; 412} 413 414kern_return_t DNBArchMachARM64::GetEXCState(bool force) { 415 int set = e_regSetEXC; 416 // Check if we have valid cached registers 417 if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) 418 return KERN_SUCCESS; 419 420 // Read the registers from our thread 421 mach_msg_type_number_t count = e_regSetEXCCount; 422 kern_return_t kret = 423 ::thread_get_state(m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64, 424 (thread_state_t)&m_state.context.exc, &count); 425 m_state.SetError(set, Read, kret); 426 return kret; 427} 428 429#if 0 430static void DumpDBGState(const arm_debug_state_t &dbg) { 431 uint32_t i = 0; 432 for (i = 0; i < 16; i++) 433 DNBLogThreadedIf(LOG_STEP, "BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } " 434 "WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }", 435 i, i, dbg.__bvr[i], dbg.__bcr[i], i, i, dbg.__wvr[i], 436 dbg.__wcr[i]); 437} 438#endif 439 440kern_return_t DNBArchMachARM64::GetDBGState(bool force) { 441 int set = e_regSetDBG; 442 443 // Check if we have valid cached registers 444 if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) 445 return KERN_SUCCESS; 446 447 // Read the registers from our thread 448 mach_msg_type_number_t count = e_regSetDBGCount; 449 kern_return_t kret = 450 ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE64, 451 (thread_state_t)&m_state.dbg, &count); 452 m_state.SetError(set, Read, kret); 453 454 return kret; 455} 456 457kern_return_t DNBArchMachARM64::GetSVEState(bool force) { 458 int set = e_regSetSVE; 459 // Check if we have valid cached registers 460 if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) 461 return KERN_SUCCESS; 462 463 if (!CPUHasSME()) 464 return KERN_INVALID_ARGUMENT; 465 466 // If the processor is not in Streaming SVE Mode, these thread_get_states 467 // will fail, and we may return uninitialized data in the register context. 468 memset(&m_state.context.sve.z[0], 0, 469 ARM_SVE_Z_STATE_COUNT * sizeof(uint32_t)); 470 memset(&m_state.context.sve.z[16], 0, 471 ARM_SVE_Z_STATE_COUNT * sizeof(uint32_t)); 472 memset(&m_state.context.sve.p[0], 0, 473 ARM_SVE_P_STATE_COUNT * sizeof(uint32_t)); 474 475 // Read the registers from our thread 476 mach_msg_type_number_t count = ARM_SVE_Z_STATE_COUNT; 477 kern_return_t kret = 478 ::thread_get_state(m_thread->MachPortNumber(), ARM_SVE_Z_STATE1, 479 (thread_state_t)&m_state.context.sve.z[0], &count); 480 m_state.SetError(set, Read, kret); 481 DNBLogThreadedIf(LOG_THREAD, "Read SVE registers z0..z15 return value %d", 482 kret); 483 if (kret != KERN_SUCCESS) 484 return kret; 485 486 count = ARM_SVE_Z_STATE_COUNT; 487 kret = thread_get_state(m_thread->MachPortNumber(), ARM_SVE_Z_STATE2, 488 (thread_state_t)&m_state.context.sve.z[16], &count); 489 m_state.SetError(set, Read, kret); 490 DNBLogThreadedIf(LOG_THREAD, "Read SVE registers z16..z31 return value %d", 491 kret); 492 if (kret != KERN_SUCCESS) 493 return kret; 494 495 count = ARM_SVE_P_STATE_COUNT; 496 kret = thread_get_state(m_thread->MachPortNumber(), ARM_SVE_P_STATE, 497 (thread_state_t)&m_state.context.sve.p[0], &count); 498 m_state.SetError(set, Read, kret); 499 DNBLogThreadedIf(LOG_THREAD, "Read SVE registers p0..p15 return value %d", 500 kret); 501 502 return kret; 503} 504 505kern_return_t DNBArchMachARM64::GetSMEState(bool force) { 506 int set = e_regSetSME; 507 // Check if we have valid cached registers 508 if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) 509 return KERN_SUCCESS; 510 511 if (!CPUHasSME()) 512 return KERN_INVALID_ARGUMENT; 513 514 // If the processor is not in Streaming SVE Mode, these thread_get_states 515 // will fail, and we may return uninitialized data in the register context. 516 memset(&m_state.context.sme.svcr, 0, ARM_SME_STATE_COUNT * sizeof(uint32_t)); 517 memset(m_state.context.sme.za.data(), 0, m_state.context.sme.za.size()); 518 if (CPUHasSME2()) 519 memset(&m_state.context.sme.zt0, 0, 520 ARM_SME2_STATE_COUNT * sizeof(uint32_t)); 521 522 // Read the registers from our thread 523 mach_msg_type_number_t count = ARM_SME_STATE_COUNT; 524 kern_return_t kret = 525 ::thread_get_state(m_thread->MachPortNumber(), ARM_SME_STATE, 526 (thread_state_t)&m_state.context.sme.svcr, &count); 527 m_state.SetError(set, Read, kret); 528 DNBLogThreadedIf(LOG_THREAD, "Read ARM_SME_STATE return value %d", kret); 529 if (kret != KERN_SUCCESS) 530 return kret; 531 532 size_t za_size = m_state.context.sme.svl_b * m_state.context.sme.svl_b; 533 const size_t max_chunk_size = 4096; 534 int n_chunks; 535 size_t chunk_size; 536 if (za_size <= max_chunk_size) { 537 n_chunks = 1; 538 chunk_size = za_size; 539 } else { 540 n_chunks = za_size / max_chunk_size; 541 chunk_size = max_chunk_size; 542 } 543 for (int i = 0; i < n_chunks; i++) { 544 count = ARM_SME_ZA_STATE_COUNT; 545 arm_sme_za_state_t za_state; 546 kret = thread_get_state(m_thread->MachPortNumber(), ARM_SME_ZA_STATE1 + i, 547 (thread_state_t)&za_state, &count); 548 m_state.SetError(set, Read, kret); 549 DNBLogThreadedIf(LOG_THREAD, "Read ARM_SME_STATE return value %d", kret); 550 if (kret != KERN_SUCCESS) 551 return kret; 552 memcpy(m_state.context.sme.za.data() + (i * chunk_size), &za_state, 553 chunk_size); 554 } 555 556 if (CPUHasSME2()) { 557 count = ARM_SME2_STATE_COUNT; 558 kret = thread_get_state(m_thread->MachPortNumber(), ARM_SME2_STATE, 559 (thread_state_t)&m_state.context.sme.zt0, &count); 560 m_state.SetError(set, Read, kret); 561 DNBLogThreadedIf(LOG_THREAD, "Read ARM_SME2_STATE return value %d", kret); 562 if (kret != KERN_SUCCESS) 563 return kret; 564 } 565 566 return kret; 567} 568 569kern_return_t DNBArchMachARM64::SetGPRState() { 570 arm_thread_state64_t *state_to_set = &m_state.context.gpr; 571#if defined(THREAD_CONVERT_THREAD_STATE_FROM_SELF) && defined(__LP64__) 572 mach_msg_type_number_t count = ARM_THREAD_STATE64_COUNT; 573 mach_msg_type_number_t new_count = ARM_THREAD_STATE64_COUNT; 574 arm_thread_state64_t new_gpr; 575 memcpy(&new_gpr, &m_state.context.gpr, count * 4); 576 kern_return_t convert_kret = thread_convert_thread_state( 577 m_thread->MachPortNumber(), THREAD_CONVERT_THREAD_STATE_FROM_SELF, 578 ARM_THREAD_STATE64, (thread_state_t)&m_state.context.gpr, count, 579 (thread_state_t)&new_gpr, &new_count); 580 if (convert_kret == KERN_SUCCESS) 581 state_to_set = &new_gpr; 582 DNBLogThreadedIf(LOG_THREAD, 583 "converted register values " 584 "to inferior's keys, return value %d, count %d", 585 convert_kret, new_count); 586#endif // THREAD_CONVERT_THREAD_STATE_TO_SELF 587 588 int set = e_regSetGPR; 589 kern_return_t kret = 590 ::thread_set_state(m_thread->MachPortNumber(), ARM_THREAD_STATE64, 591 (thread_state_t)state_to_set, e_regSetGPRCount); 592 m_state.SetError(set, Write, 593 kret); // Set the current write error for this register set 594 m_state.InvalidateRegisterSetState(set); // Invalidate the current register 595 // state in case registers are read 596 // back differently 597 return kret; // Return the error code 598} 599 600kern_return_t DNBArchMachARM64::SetVFPState() { 601 int set = e_regSetVFP; 602 kern_return_t kret = ::thread_set_state( 603 m_thread->MachPortNumber(), ARM_NEON_STATE64, 604 (thread_state_t)&m_state.context.vfp, e_regSetVFPCount); 605 m_state.SetError(set, Write, 606 kret); // Set the current write error for this register set 607 m_state.InvalidateRegisterSetState(set); // Invalidate the current register 608 // state in case registers are read 609 // back differently 610 return kret; // Return the error code 611} 612 613kern_return_t DNBArchMachARM64::SetSVEState() { 614 if (!CPUHasSME()) 615 return KERN_INVALID_ARGUMENT; 616 617 int set = e_regSetSVE; 618 kern_return_t kret = thread_set_state( 619 m_thread->MachPortNumber(), ARM_SVE_Z_STATE1, 620 (thread_state_t)&m_state.context.sve.z[0], ARM_SVE_Z_STATE_COUNT); 621 m_state.SetError(set, Write, kret); 622 DNBLogThreadedIf(LOG_THREAD, "Write ARM_SVE_Z_STATE1 return value %d", kret); 623 if (kret != KERN_SUCCESS) 624 return kret; 625 626 kret = thread_set_state(m_thread->MachPortNumber(), ARM_SVE_Z_STATE2, 627 (thread_state_t)&m_state.context.sve.z[16], 628 ARM_SVE_Z_STATE_COUNT); 629 m_state.SetError(set, Write, kret); 630 DNBLogThreadedIf(LOG_THREAD, "Write ARM_SVE_Z_STATE2 return value %d", kret); 631 if (kret != KERN_SUCCESS) 632 return kret; 633 634 kret = thread_set_state(m_thread->MachPortNumber(), ARM_SVE_P_STATE, 635 (thread_state_t)&m_state.context.sve.p[0], 636 ARM_SVE_P_STATE_COUNT); 637 m_state.SetError(set, Write, kret); 638 DNBLogThreadedIf(LOG_THREAD, "Write ARM_SVE_P_STATE return value %d", kret); 639 if (kret != KERN_SUCCESS) 640 return kret; 641 642 return kret; 643} 644 645kern_return_t DNBArchMachARM64::SetSMEState() { 646 if (!CPUHasSME()) 647 return KERN_INVALID_ARGUMENT; 648 kern_return_t kret; 649 650 int set = e_regSetSME; 651 size_t za_size = m_state.context.sme.svl_b * m_state.context.sme.svl_b; 652 const size_t max_chunk_size = 4096; 653 int n_chunks; 654 size_t chunk_size; 655 if (za_size <= max_chunk_size) { 656 n_chunks = 1; 657 chunk_size = za_size; 658 } else { 659 n_chunks = za_size / max_chunk_size; 660 chunk_size = max_chunk_size; 661 } 662 for (int i = 0; i < n_chunks; i++) { 663 arm_sme_za_state_t za_state; 664 memcpy(&za_state, m_state.context.sme.za.data() + (i * chunk_size), 665 chunk_size); 666 kret = thread_set_state(m_thread->MachPortNumber(), ARM_SME_ZA_STATE1 + i, 667 (thread_state_t)&za_state, ARM_SME_ZA_STATE_COUNT); 668 m_state.SetError(set, Write, kret); 669 DNBLogThreadedIf(LOG_THREAD, "Write ARM_SME_STATE return value %d", kret); 670 if (kret != KERN_SUCCESS) 671 return kret; 672 } 673 674 if (CPUHasSME2()) { 675 kret = thread_set_state(m_thread->MachPortNumber(), ARM_SME2_STATE, 676 (thread_state_t)&m_state.context.sme.zt0, 677 ARM_SME2_STATE); 678 m_state.SetError(set, Write, kret); 679 DNBLogThreadedIf(LOG_THREAD, "Write ARM_SME2_STATE return value %d", kret); 680 if (kret != KERN_SUCCESS) 681 return kret; 682 } 683 684 return kret; 685} 686 687kern_return_t DNBArchMachARM64::SetEXCState() { 688 int set = e_regSetEXC; 689 kern_return_t kret = ::thread_set_state( 690 m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64, 691 (thread_state_t)&m_state.context.exc, e_regSetEXCCount); 692 m_state.SetError(set, Write, 693 kret); // Set the current write error for this register set 694 m_state.InvalidateRegisterSetState(set); // Invalidate the current register 695 // state in case registers are read 696 // back differently 697 return kret; // Return the error code 698} 699 700kern_return_t DNBArchMachARM64::SetDBGState(bool also_set_on_task) { 701 int set = e_regSetDBG; 702 kern_return_t kret = 703 ::thread_set_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE64, 704 (thread_state_t)&m_state.dbg, e_regSetDBGCount); 705 if (also_set_on_task) { 706 kern_return_t task_kret = task_set_state( 707 m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE64, 708 (thread_state_t)&m_state.dbg, e_regSetDBGCount); 709 if (task_kret != KERN_SUCCESS) 710 DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::SetDBGState failed " 711 "to set debug control register state: " 712 "0x%8.8x.", 713 task_kret); 714 } 715 m_state.SetError(set, Write, 716 kret); // Set the current write error for this register set 717 m_state.InvalidateRegisterSetState(set); // Invalidate the current register 718 // state in case registers are read 719 // back differently 720 721 return kret; // Return the error code 722} 723 724void DNBArchMachARM64::ThreadWillResume() { 725 // Do we need to step this thread? If so, let the mach thread tell us so. 726 if (m_thread->IsStepping()) { 727 EnableHardwareSingleStep(true); 728 } 729 730 // Disable the triggered watchpoint temporarily before we resume. 731 // Plus, we try to enable hardware single step to execute past the instruction 732 // which triggered our watchpoint. 733 if (m_watchpoint_did_occur) { 734 if (m_watchpoint_hw_index >= 0) { 735 kern_return_t kret = GetDBGState(false); 736 if (kret == KERN_SUCCESS && 737 !IsWatchpointEnabled(m_state.dbg, m_watchpoint_hw_index)) { 738 // The watchpoint might have been disabled by the user. We don't need 739 // to do anything at all 740 // to enable hardware single stepping. 741 m_watchpoint_did_occur = false; 742 m_watchpoint_hw_index = -1; 743 return; 744 } 745 746 DisableHardwareWatchpoint(m_watchpoint_hw_index, false); 747 DNBLogThreadedIf(LOG_WATCHPOINTS, 748 "DNBArchMachARM64::ThreadWillResume() " 749 "DisableHardwareWatchpoint(%d) called", 750 m_watchpoint_hw_index); 751 752 // Enable hardware single step to move past the watchpoint-triggering 753 // instruction. 754 m_watchpoint_resume_single_step_enabled = 755 (EnableHardwareSingleStep(true) == KERN_SUCCESS); 756 757 // If we are not able to enable single step to move past the 758 // watchpoint-triggering instruction, 759 // at least we should reset the two watchpoint member variables so that 760 // the next time around 761 // this callback function is invoked, the enclosing logical branch is 762 // skipped. 763 if (!m_watchpoint_resume_single_step_enabled) { 764 // Reset the two watchpoint member variables. 765 m_watchpoint_did_occur = false; 766 m_watchpoint_hw_index = -1; 767 DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::ThreadWillResume()" 768 " failed to enable single step"); 769 } else 770 DNBLogThreadedIf(LOG_WATCHPOINTS, 771 "DNBArchMachARM64::ThreadWillResume() " 772 "succeeded to enable single step"); 773 } 774 } 775} 776 777bool DNBArchMachARM64::NotifyException(MachException::Data &exc) { 778 779 switch (exc.exc_type) { 780 default: 781 break; 782 case EXC_BREAKPOINT: 783 if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG) { 784 // The data break address is passed as exc_data[1]. 785 nub_addr_t addr = exc.exc_data[1]; 786 // Find the hardware index with the side effect of possibly massaging the 787 // addr to return the starting address as seen from the debugger side. 788 uint32_t hw_index = GetHardwareWatchpointHit(addr); 789 790 // One logical watchpoint was split into two watchpoint locations because 791 // it was too big. If the watchpoint exception is indicating the 2nd half 792 // of the two-parter, find the address of the 1st half and report that -- 793 // that's what lldb is going to expect to see. 794 DNBLogThreadedIf(LOG_WATCHPOINTS, 795 "DNBArchMachARM64::NotifyException " 796 "watchpoint %d was hit on address " 797 "0x%llx", 798 hw_index, (uint64_t)addr); 799 const uint32_t num_watchpoints = NumSupportedHardwareWatchpoints(); 800 for (uint32_t i = 0; i < num_watchpoints; i++) { 801 if (LoHi[i] != 0 && LoHi[i] == hw_index && LoHi[i] != i && 802 GetWatchpointAddressByIndex(i) != INVALID_NUB_ADDRESS) { 803 addr = GetWatchpointAddressByIndex(i); 804 DNBLogThreadedIf(LOG_WATCHPOINTS, 805 "DNBArchMachARM64::NotifyException " 806 "It is a linked watchpoint; " 807 "rewritten to index %d addr 0x%llx", 808 LoHi[i], (uint64_t)addr); 809 } 810 } 811 812 if (hw_index != INVALID_NUB_HW_INDEX) { 813 m_watchpoint_did_occur = true; 814 m_watchpoint_hw_index = hw_index; 815 exc.exc_data[1] = addr; 816 // Piggyback the hw_index in the exc.data. 817 exc.exc_data.push_back(hw_index); 818 } 819 820 return true; 821 } 822 break; 823 } 824 return false; 825} 826 827bool DNBArchMachARM64::ThreadDidStop() { 828 bool success = true; 829 830 m_state.InvalidateAllRegisterStates(); 831 832 if (m_watchpoint_resume_single_step_enabled) { 833 // Great! We now disable the hardware single step as well as re-enable the 834 // hardware watchpoint. 835 // See also ThreadWillResume(). 836 if (EnableHardwareSingleStep(false) == KERN_SUCCESS) { 837 if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) { 838 ReenableHardwareWatchpoint(m_watchpoint_hw_index); 839 m_watchpoint_resume_single_step_enabled = false; 840 m_watchpoint_did_occur = false; 841 m_watchpoint_hw_index = -1; 842 } else { 843 DNBLogError("internal error detected: m_watchpoint_resume_step_enabled " 844 "is true but (m_watchpoint_did_occur && " 845 "m_watchpoint_hw_index >= 0) does not hold!"); 846 } 847 } else { 848 DNBLogError("internal error detected: m_watchpoint_resume_step_enabled " 849 "is true but unable to disable single step!"); 850 } 851 } 852 853 // Are we stepping a single instruction? 854 if (GetGPRState(true) == KERN_SUCCESS) { 855 // We are single stepping, was this the primary thread? 856 if (m_thread->IsStepping()) { 857 // This was the primary thread, we need to clear the trace 858 // bit if so. 859 success = EnableHardwareSingleStep(false) == KERN_SUCCESS; 860 } else { 861 // The MachThread will automatically restore the suspend count 862 // in ThreadDidStop(), so we don't need to do anything here if 863 // we weren't the primary thread the last time 864 } 865 } 866 return success; 867} 868 869// Set the single step bit in the processor status register. 870kern_return_t DNBArchMachARM64::EnableHardwareSingleStep(bool enable) { 871 DNBError err; 872 DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable); 873 874 err = GetGPRState(false); 875 876 if (err.Fail()) { 877 err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__); 878 return err.Status(); 879 } 880 881 err = GetDBGState(false); 882 883 if (err.Fail()) { 884 err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__); 885 return err.Status(); 886 } 887 888#if defined(DEBUGSERVER_IS_ARM64E) 889 uint64_t pc = DNBFixAddress( 890 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc)); 891#else 892 uint64_t pc = m_state.context.gpr.__pc; 893#endif 894 895 if (enable) { 896 DNBLogThreadedIf(LOG_STEP, 897 "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx", 898 __FUNCTION__, pc); 899 m_state.dbg.__mdscr_el1 |= SS_ENABLE; 900 } else { 901 DNBLogThreadedIf(LOG_STEP, 902 "%s: Clearing MDSCR_EL1 Single Step bit at pc 0x%llx", 903 __FUNCTION__, pc); 904 m_state.dbg.__mdscr_el1 &= ~(SS_ENABLE); 905 } 906 907 return SetDBGState(false); 908} 909 910// return 1 if bit "BIT" is set in "value" 911static inline uint32_t bit(uint32_t value, uint32_t bit) { 912 return (value >> bit) & 1u; 913} 914 915// return the bitfield "value[msbit:lsbit]". 916static inline uint64_t bits(uint64_t value, uint32_t msbit, uint32_t lsbit) { 917 assert(msbit >= lsbit); 918 uint64_t shift_left = sizeof(value) * 8 - 1 - msbit; 919 value <<= 920 shift_left; // shift anything above the msbit off of the unsigned edge 921 value >>= shift_left + lsbit; // shift it back again down to the lsbit 922 // (including undoing any shift from above) 923 return value; // return our result 924} 925 926uint32_t DNBArchMachARM64::NumSupportedHardwareWatchpoints() { 927 // Set the init value to something that will let us know that we need to 928 // autodetect how many watchpoints are supported dynamically... 929 static uint32_t g_num_supported_hw_watchpoints = UINT_MAX; 930 if (g_num_supported_hw_watchpoints == UINT_MAX) { 931 // Set this to zero in case we can't tell if there are any HW breakpoints 932 g_num_supported_hw_watchpoints = 0; 933 934 size_t len; 935 uint32_t n = 0; 936 len = sizeof(n); 937 if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) { 938 g_num_supported_hw_watchpoints = n; 939 DNBLogThreadedIf(LOG_THREAD, "hw.optional.watchpoint=%u", n); 940 } else { 941// For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in 942// EL0 so it can't 943// access that reg. The kernel should have filled in the sysctls based on it 944// though. 945#if defined(__arm__) 946 uint32_t register_DBGDIDR; 947 948 asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR)); 949 uint32_t numWRPs = bits(register_DBGDIDR, 31, 28); 950 // Zero is reserved for the WRP count, so don't increment it if it is zero 951 if (numWRPs > 0) 952 numWRPs++; 953 g_num_supported_hw_watchpoints = numWRPs; 954 DNBLogThreadedIf(LOG_THREAD, 955 "Number of supported hw watchpoints via asm(): %d", 956 g_num_supported_hw_watchpoints); 957#endif 958 } 959 } 960 return g_num_supported_hw_watchpoints; 961} 962 963uint32_t DNBArchMachARM64::NumSupportedHardwareBreakpoints() { 964 // Set the init value to something that will let us know that we need to 965 // autodetect how many breakpoints are supported dynamically... 966 static uint32_t g_num_supported_hw_breakpoints = UINT_MAX; 967 if (g_num_supported_hw_breakpoints == UINT_MAX) { 968 // Set this to zero in case we can't tell if there are any HW breakpoints 969 g_num_supported_hw_breakpoints = 0; 970 971 size_t len; 972 uint32_t n = 0; 973 len = sizeof(n); 974 if (::sysctlbyname("hw.optional.breakpoint", &n, &len, NULL, 0) == 0) { 975 g_num_supported_hw_breakpoints = n; 976 DNBLogThreadedIf(LOG_THREAD, "hw.optional.breakpoint=%u", n); 977 } else { 978// For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in 979// EL0 so it can't access that reg. The kernel should have filled in the 980// sysctls based on it though. 981#if defined(__arm__) 982 uint32_t register_DBGDIDR; 983 984 asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR)); 985 uint32_t numWRPs = bits(register_DBGDIDR, 31, 28); 986 // Zero is reserved for the WRP count, so don't increment it if it is zero 987 if (numWRPs > 0) 988 numWRPs++; 989 g_num_supported_hw_breakpoints = numWRPs; 990 DNBLogThreadedIf(LOG_THREAD, 991 "Number of supported hw breakpoint via asm(): %d", 992 g_num_supported_hw_breakpoints); 993#endif 994 } 995 } 996 return g_num_supported_hw_breakpoints; 997} 998 999uint32_t DNBArchMachARM64::EnableHardwareBreakpoint(nub_addr_t addr, 1000 nub_size_t size, 1001 bool also_set_on_task) { 1002 DNBLogThreadedIf(LOG_WATCHPOINTS, 1003 "DNBArchMachARM64::EnableHardwareBreakpoint(addr = " 1004 "0x%8.8llx, size = %zu)", 1005 (uint64_t)addr, size); 1006 1007 const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints(); 1008 1009 nub_addr_t aligned_bp_address = addr; 1010 uint32_t control_value = 0; 1011 1012 switch (size) { 1013 case 2: 1014 control_value = (0x3 << 5) | 7; 1015 aligned_bp_address &= ~1; 1016 break; 1017 case 4: 1018 control_value = (0xfu << 5) | 7; 1019 aligned_bp_address &= ~3; 1020 break; 1021 }; 1022 1023 // Read the debug state 1024 kern_return_t kret = GetDBGState(false); 1025 if (kret == KERN_SUCCESS) { 1026 // Check to make sure we have the needed hardware support 1027 uint32_t i = 0; 1028 1029 for (i = 0; i < num_hw_breakpoints; ++i) { 1030 if ((m_state.dbg.__bcr[i] & BCR_ENABLE) == 0) 1031 break; // We found an available hw breakpoint slot (in i) 1032 } 1033 1034 // See if we found an available hw breakpoint slot above 1035 if (i < num_hw_breakpoints) { 1036 m_state.dbg.__bvr[i] = aligned_bp_address; 1037 m_state.dbg.__bcr[i] = control_value; 1038 1039 DNBLogThreadedIf(LOG_WATCHPOINTS, 1040 "DNBArchMachARM64::EnableHardwareBreakpoint() " 1041 "adding breakpoint on address 0x%llx with control " 1042 "register value 0x%x", 1043 (uint64_t)m_state.dbg.__bvr[i], 1044 (uint32_t)m_state.dbg.__bcr[i]); 1045 1046 kret = SetDBGState(also_set_on_task); 1047 1048 DNBLogThreadedIf(LOG_WATCHPOINTS, 1049 "DNBArchMachARM64::" 1050 "EnableHardwareBreakpoint() " 1051 "SetDBGState() => 0x%8.8x.", 1052 kret); 1053 1054 if (kret == KERN_SUCCESS) 1055 return i; 1056 } else { 1057 DNBLogThreadedIf(LOG_WATCHPOINTS, 1058 "DNBArchMachARM64::" 1059 "EnableHardwareBreakpoint(): All " 1060 "hardware resources (%u) are in use.", 1061 num_hw_breakpoints); 1062 } 1063 } 1064 return INVALID_NUB_HW_INDEX; 1065} 1066 1067// This should be `std::bit_ceil(aligned_size)` but 1068// that requires C++20. 1069// Calculates the smallest integral power of two that is not smaller than x. 1070static uint64_t bit_ceil(uint64_t input) { 1071 if (input <= 1 || __builtin_popcount(input) == 1) 1072 return input; 1073 1074 return 1ULL << (64 - __builtin_clzll(input)); 1075} 1076 1077std::vector<DNBArchMachARM64::WatchpointSpec> 1078DNBArchMachARM64::AlignRequestedWatchpoint(nub_addr_t requested_addr, 1079 nub_size_t requested_size) { 1080 1081 // Can't watch zero bytes 1082 if (requested_size == 0) 1083 return {}; 1084 1085 // Smallest size we can watch on AArch64 is 8 bytes 1086 constexpr nub_size_t min_watchpoint_alignment = 8; 1087 nub_size_t aligned_size = std::max(requested_size, min_watchpoint_alignment); 1088 1089 /// Round up \a requested_size to the next power-of-2 size, at least 8 1090 /// bytes 1091 /// requested_size == 8 -> aligned_size == 8 1092 /// requested_size == 9 -> aligned_size == 16 1093 aligned_size = aligned_size = bit_ceil(aligned_size); 1094 1095 nub_addr_t aligned_start = requested_addr & ~(aligned_size - 1); 1096 // Does this power-of-2 memory range, aligned to power-of-2, completely 1097 // encompass the requested watch region. 1098 if (aligned_start + aligned_size >= requested_addr + requested_size) { 1099 WatchpointSpec wp; 1100 wp.aligned_start = aligned_start; 1101 wp.requested_start = requested_addr; 1102 wp.aligned_size = aligned_size; 1103 wp.requested_size = requested_size; 1104 return {{wp}}; 1105 } 1106 1107 // We need to split this into two watchpoints, split on the aligned_size 1108 // boundary and re-evaluate the alignment of each half. 1109 // 1110 // requested_addr 48 requested_size 20 -> aligned_size 32 1111 // aligned_start 32 1112 // split_addr 64 1113 // first_requested_addr 48 1114 // first_requested_size 16 1115 // second_requested_addr 64 1116 // second_requested_size 4 1117 nub_addr_t split_addr = aligned_start + aligned_size; 1118 1119 nub_addr_t first_requested_addr = requested_addr; 1120 nub_size_t first_requested_size = split_addr - requested_addr; 1121 nub_addr_t second_requested_addr = split_addr; 1122 nub_size_t second_requested_size = requested_size - first_requested_size; 1123 1124 std::vector<WatchpointSpec> first_wp = 1125 AlignRequestedWatchpoint(first_requested_addr, first_requested_size); 1126 std::vector<WatchpointSpec> second_wp = 1127 AlignRequestedWatchpoint(second_requested_addr, second_requested_size); 1128 if (first_wp.size() != 1 || second_wp.size() != 1) 1129 return {}; 1130 1131 return {{first_wp[0], second_wp[0]}}; 1132} 1133 1134uint32_t DNBArchMachARM64::EnableHardwareWatchpoint(nub_addr_t addr, 1135 nub_size_t size, bool read, 1136 bool write, 1137 bool also_set_on_task) { 1138 DNBLogThreadedIf(LOG_WATCHPOINTS, 1139 "DNBArchMachARM64::EnableHardwareWatchpoint(addr = " 1140 "0x%8.8llx, size = %zu, read = %u, write = %u)", 1141 (uint64_t)addr, size, read, write); 1142 1143 std::vector<DNBArchMachARM64::WatchpointSpec> wps = 1144 AlignRequestedWatchpoint(addr, size); 1145 DNBLogThreadedIf(LOG_WATCHPOINTS, 1146 "DNBArchMachARM64::EnableHardwareWatchpoint() using %zu " 1147 "hardware watchpoints", 1148 wps.size()); 1149 1150 if (wps.size() == 0) 1151 return INVALID_NUB_HW_INDEX; 1152 1153 // We must watch for either read or write 1154 if (read == false && write == false) 1155 return INVALID_NUB_HW_INDEX; 1156 1157 // Only one hardware watchpoint needed 1158 // to implement the user's request. 1159 if (wps.size() == 1) { 1160 if (wps[0].aligned_size <= 8) 1161 return SetBASWatchpoint(wps[0], read, write, also_set_on_task); 1162 else 1163 return SetMASKWatchpoint(wps[0], read, write, also_set_on_task); 1164 } 1165 1166 // We have multiple WatchpointSpecs 1167 1168 std::vector<uint32_t> wp_slots_used; 1169 for (size_t i = 0; i < wps.size(); i++) { 1170 uint32_t idx = 1171 EnableHardwareWatchpoint(wps[i].requested_start, wps[i].requested_size, 1172 read, write, also_set_on_task); 1173 if (idx != INVALID_NUB_HW_INDEX) 1174 wp_slots_used.push_back(idx); 1175 } 1176 1177 // Did we fail to set all of the WatchpointSpecs needed 1178 // for this user's request? 1179 if (wps.size() != wp_slots_used.size()) { 1180 for (int wp_slot : wp_slots_used) 1181 DisableHardwareWatchpoint(wp_slot, also_set_on_task); 1182 return INVALID_NUB_HW_INDEX; 1183 } 1184 1185 LoHi[wp_slots_used[0]] = wp_slots_used[1]; 1186 return wp_slots_used[0]; 1187} 1188 1189uint32_t DNBArchMachARM64::SetBASWatchpoint(DNBArchMachARM64::WatchpointSpec wp, 1190 bool read, bool write, 1191 bool also_set_on_task) { 1192 const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); 1193 1194 nub_addr_t aligned_dword_addr = wp.aligned_start; 1195 nub_addr_t watching_offset = wp.requested_start - wp.aligned_start; 1196 nub_size_t watching_size = wp.requested_size; 1197 1198 // If user asks to watch 3 bytes at 0x1005, 1199 // aligned_dword_addr 0x1000 1200 // watching_offset 5 1201 // watching_size 3 1202 1203 // Set the Byte Address Selects bits DBGWCRn_EL1 bits [12:5] based on the 1204 // above. 1205 // The bit shift and negation operation will give us 0b11 for 2, 0b1111 for 4, 1206 // etc, up to 0b11111111 for 8. 1207 // then we shift those bits left by the offset into this dword that we are 1208 // interested in. 1209 // e.g. if we are watching bytes 4,5,6,7 in a dword we want a BAS of 1210 // 0b11110000. 1211 uint32_t byte_address_select = ((1 << watching_size) - 1) << watching_offset; 1212 1213 // Read the debug state 1214 kern_return_t kret = GetDBGState(false); 1215 if (kret != KERN_SUCCESS) 1216 return INVALID_NUB_HW_INDEX; 1217 1218 // Check to make sure we have the needed hardware support 1219 uint32_t i = 0; 1220 1221 for (i = 0; i < num_hw_watchpoints; ++i) { 1222 if ((m_state.dbg.__wcr[i] & WCR_ENABLE) == 0) 1223 break; // We found an available hw watchpoint slot 1224 } 1225 if (i == num_hw_watchpoints) { 1226 DNBLogThreadedIf(LOG_WATCHPOINTS, 1227 "DNBArchMachARM64::" 1228 "SetBASWatchpoint(): All " 1229 "hardware resources (%u) are in use.", 1230 num_hw_watchpoints); 1231 return INVALID_NUB_HW_INDEX; 1232 } 1233 1234 DNBLogThreadedIf(LOG_WATCHPOINTS, 1235 "DNBArchMachARM64::" 1236 "SetBASWatchpoint() " 1237 "set hardware register %d to BAS watchpoint " 1238 "aligned start address 0x%llx, watch region start " 1239 "offset %lld, number of bytes %zu", 1240 i, aligned_dword_addr, watching_offset, watching_size); 1241 1242 // Clear any previous LoHi joined-watchpoint that may have been in use 1243 LoHi[i] = 0; 1244 1245 // shift our Byte Address Select bits up to the correct bit range for the 1246 // DBGWCRn_EL1 1247 byte_address_select = byte_address_select << 5; 1248 1249 // Make sure bits 1:0 are clear in our address 1250 m_state.dbg.__wvr[i] = aligned_dword_addr; // DVA (Data Virtual Address) 1251 m_state.dbg.__wcr[i] = byte_address_select | // Which bytes that follow 1252 // the DVA that we will watch 1253 S_USER | // Stop only in user mode 1254 (read ? WCR_LOAD : 0) | // Stop on read access? 1255 (write ? WCR_STORE : 0) | // Stop on write access? 1256 WCR_ENABLE; // Enable this watchpoint; 1257 1258 DNBLogThreadedIf(LOG_WATCHPOINTS, 1259 "DNBArchMachARM64::SetBASWatchpoint() " 1260 "adding watchpoint on address 0x%llx with control " 1261 "register value 0x%x", 1262 (uint64_t)m_state.dbg.__wvr[i], 1263 (uint32_t)m_state.dbg.__wcr[i]); 1264 1265 kret = SetDBGState(also_set_on_task); 1266 // DumpDBGState(m_state.dbg); 1267 1268 DNBLogThreadedIf(LOG_WATCHPOINTS, 1269 "DNBArchMachARM64::" 1270 "SetBASWatchpoint() " 1271 "SetDBGState() => 0x%8.8x.", 1272 kret); 1273 1274 if (kret == KERN_SUCCESS) 1275 return i; 1276 1277 return INVALID_NUB_HW_INDEX; 1278} 1279 1280uint32_t 1281DNBArchMachARM64::SetMASKWatchpoint(DNBArchMachARM64::WatchpointSpec wp, 1282 bool read, bool write, 1283 bool also_set_on_task) { 1284 const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); 1285 1286 // Read the debug state 1287 kern_return_t kret = GetDBGState(false); 1288 if (kret != KERN_SUCCESS) 1289 return INVALID_NUB_HW_INDEX; 1290 1291 // Check to make sure we have the needed hardware support 1292 uint32_t i = 0; 1293 1294 for (i = 0; i < num_hw_watchpoints; ++i) { 1295 if ((m_state.dbg.__wcr[i] & WCR_ENABLE) == 0) 1296 break; // We found an available hw watchpoint slot 1297 } 1298 if (i == num_hw_watchpoints) { 1299 DNBLogThreadedIf(LOG_WATCHPOINTS, 1300 "DNBArchMachARM64::" 1301 "SetMASKWatchpoint(): All " 1302 "hardware resources (%u) are in use.", 1303 num_hw_watchpoints); 1304 return INVALID_NUB_HW_INDEX; 1305 } 1306 1307 DNBLogThreadedIf(LOG_WATCHPOINTS, 1308 "DNBArchMachARM64::" 1309 "SetMASKWatchpoint() " 1310 "set hardware register %d to MASK watchpoint " 1311 "aligned start address 0x%llx, aligned size %zu", 1312 i, wp.aligned_start, wp.aligned_size); 1313 1314 // Clear any previous LoHi joined-watchpoint that may have been in use 1315 LoHi[i] = 0; 1316 1317 // MASK field is the number of low bits that are masked off 1318 // when comparing the address with the DBGWVR<n>_EL1 values. 1319 // If aligned size is 16, that means we ignore low 4 bits, 0b1111. 1320 // popcount(16 - 1) give us the correct value of 4. 1321 // 2GB is max watchable region, which is 31 bits (low bits 0x7fffffff 1322 // masked off) -- a MASK value of 31. 1323 const uint64_t mask = __builtin_popcountl(wp.aligned_size - 1) << 24; 1324 // A '0b11111111' BAS value needed for mask watchpoints plus a 1325 // nonzero mask value. 1326 const uint64_t not_bas_wp = 0xff << 5; 1327 1328 m_state.dbg.__wvr[i] = wp.aligned_start; 1329 m_state.dbg.__wcr[i] = mask | not_bas_wp | S_USER | // Stop only in user mode 1330 (read ? WCR_LOAD : 0) | // Stop on read access? 1331 (write ? WCR_STORE : 0) | // Stop on write access? 1332 WCR_ENABLE; // Enable this watchpoint; 1333 1334 DNBLogThreadedIf(LOG_WATCHPOINTS, 1335 "DNBArchMachARM64::SetMASKWatchpoint() " 1336 "adding watchpoint on address 0x%llx with control " 1337 "register value 0x%llx", 1338 (uint64_t)m_state.dbg.__wvr[i], 1339 (uint64_t)m_state.dbg.__wcr[i]); 1340 1341 kret = SetDBGState(also_set_on_task); 1342 1343 DNBLogThreadedIf(LOG_WATCHPOINTS, 1344 "DNBArchMachARM64::" 1345 "SetMASKWatchpoint() " 1346 "SetDBGState() => 0x%8.8x.", 1347 kret); 1348 1349 if (kret == KERN_SUCCESS) 1350 return i; 1351 1352 return INVALID_NUB_HW_INDEX; 1353} 1354 1355bool DNBArchMachARM64::ReenableHardwareWatchpoint(uint32_t hw_index) { 1356 // If this logical watchpoint # is actually implemented using 1357 // two hardware watchpoint registers, re-enable both of them. 1358 1359 if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) { 1360 return ReenableHardwareWatchpoint_helper(hw_index) && 1361 ReenableHardwareWatchpoint_helper(LoHi[hw_index]); 1362 } else { 1363 return ReenableHardwareWatchpoint_helper(hw_index); 1364 } 1365} 1366 1367bool DNBArchMachARM64::ReenableHardwareWatchpoint_helper(uint32_t hw_index) { 1368 kern_return_t kret = GetDBGState(false); 1369 if (kret != KERN_SUCCESS) 1370 return false; 1371 1372 const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); 1373 if (hw_index >= num_hw_points) 1374 return false; 1375 1376 m_state.dbg.__wvr[hw_index] = m_disabled_watchpoints[hw_index].addr; 1377 m_state.dbg.__wcr[hw_index] = m_disabled_watchpoints[hw_index].control; 1378 1379 DNBLogThreadedIf(LOG_WATCHPOINTS, 1380 "DNBArchMachARM64::" 1381 "ReenableHardwareWatchpoint_helper( %u ) - WVR%u = " 1382 "0x%8.8llx WCR%u = 0x%8.8llx", 1383 hw_index, hw_index, (uint64_t)m_state.dbg.__wvr[hw_index], 1384 hw_index, (uint64_t)m_state.dbg.__wcr[hw_index]); 1385 1386 kret = SetDBGState(false); 1387 1388 return (kret == KERN_SUCCESS); 1389} 1390 1391bool DNBArchMachARM64::DisableHardwareWatchpoint(uint32_t hw_index, 1392 bool also_set_on_task) { 1393 if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) { 1394 return DisableHardwareWatchpoint_helper(hw_index, also_set_on_task) && 1395 DisableHardwareWatchpoint_helper(LoHi[hw_index], also_set_on_task); 1396 } else { 1397 return DisableHardwareWatchpoint_helper(hw_index, also_set_on_task); 1398 } 1399} 1400 1401bool DNBArchMachARM64::DisableHardwareWatchpoint_helper(uint32_t hw_index, 1402 bool also_set_on_task) { 1403 kern_return_t kret = GetDBGState(false); 1404 if (kret != KERN_SUCCESS) 1405 return false; 1406 1407 const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); 1408 if (hw_index >= num_hw_points) 1409 return false; 1410 1411 m_disabled_watchpoints[hw_index].addr = m_state.dbg.__wvr[hw_index]; 1412 m_disabled_watchpoints[hw_index].control = m_state.dbg.__wcr[hw_index]; 1413 1414 m_state.dbg.__wcr[hw_index] &= ~((nub_addr_t)WCR_ENABLE); 1415 DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" 1416 "DisableHardwareWatchpoint( %u ) - WVR%u = " 1417 "0x%8.8llx WCR%u = 0x%8.8llx", 1418 hw_index, hw_index, (uint64_t)m_state.dbg.__wvr[hw_index], 1419 hw_index, (uint64_t)m_state.dbg.__wcr[hw_index]); 1420 1421 kret = SetDBGState(also_set_on_task); 1422 1423 return (kret == KERN_SUCCESS); 1424} 1425 1426bool DNBArchMachARM64::DisableHardwareBreakpoint(uint32_t hw_index, 1427 bool also_set_on_task) { 1428 kern_return_t kret = GetDBGState(false); 1429 if (kret != KERN_SUCCESS) 1430 return false; 1431 1432 const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); 1433 if (hw_index >= num_hw_points) 1434 return false; 1435 1436 m_disabled_breakpoints[hw_index].addr = m_state.dbg.__bvr[hw_index]; 1437 m_disabled_breakpoints[hw_index].control = m_state.dbg.__bcr[hw_index]; 1438 1439 m_state.dbg.__bcr[hw_index] = 0; 1440 DNBLogThreadedIf(LOG_WATCHPOINTS, 1441 "DNBArchMachARM64::" 1442 "DisableHardwareBreakpoint( %u ) - WVR%u = " 1443 "0x%8.8llx BCR%u = 0x%8.8llx", 1444 hw_index, hw_index, (uint64_t)m_state.dbg.__bvr[hw_index], 1445 hw_index, (uint64_t)m_state.dbg.__bcr[hw_index]); 1446 1447 kret = SetDBGState(also_set_on_task); 1448 1449 return (kret == KERN_SUCCESS); 1450} 1451 1452// This is for checking the Byte Address Select bits in the DBRWCRn_EL1 control 1453// register. 1454// Returns -1 if the trailing bit patterns are not one of: 1455// { 0b???????1, 0b??????10, 0b?????100, 0b????1000, 0b???10000, 0b??100000, 1456// 0b?1000000, 0b10000000 }. 1457static inline int32_t LowestBitSet(uint32_t val) { 1458 for (unsigned i = 0; i < 8; ++i) { 1459 if (bit(val, i)) 1460 return i; 1461 } 1462 return -1; 1463} 1464 1465// Iterate through the debug registers; return the index of the first watchpoint 1466// whose address matches. 1467// As a side effect, the starting address as understood by the debugger is 1468// returned which could be 1469// different from 'addr' passed as an in/out argument. 1470uint32_t DNBArchMachARM64::GetHardwareWatchpointHit(nub_addr_t &addr) { 1471 // Read the debug state 1472 kern_return_t kret = GetDBGState(true); 1473 // DumpDBGState(m_state.dbg); 1474 DNBLogThreadedIf( 1475 LOG_WATCHPOINTS, 1476 "DNBArchMachARM64::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", 1477 kret); 1478 DNBLogThreadedIf(LOG_WATCHPOINTS, 1479 "DNBArchMachARM64::GetHardwareWatchpointHit() addr = 0x%llx", 1480 (uint64_t)addr); 1481 1482 if (kret == KERN_SUCCESS) { 1483 DBG &debug_state = m_state.dbg; 1484 uint32_t i, num = NumSupportedHardwareWatchpoints(); 1485 for (i = 0; i < num; ++i) { 1486 nub_addr_t wp_addr = GetWatchAddress(debug_state, i); 1487 1488 DNBLogThreadedIf(LOG_WATCHPOINTS, 1489 "DNBArchImplARM64::" 1490 "GetHardwareWatchpointHit() slot: %u " 1491 "(addr = 0x%llx, WCR = 0x%llx)", 1492 i, wp_addr, debug_state.__wcr[i]); 1493 1494 if (!IsWatchpointEnabled(debug_state, i)) 1495 continue; 1496 1497 // DBGWCR<n>EL1.BAS are the bits of the doubleword that are watched 1498 // with a BAS watchpoint. 1499 uint32_t bas_bits = bits(debug_state.__wcr[i], 12, 5); 1500 // DBGWCR<n>EL1.MASK is the number of bits that are masked off the 1501 // virtual address when comparing to DBGWVR<n>_EL1. 1502 uint32_t mask = bits(debug_state.__wcr[i], 28, 24); 1503 1504 const bool is_bas_watchpoint = mask == 0; 1505 1506 DNBLogThreadedIf( 1507 LOG_WATCHPOINTS, 1508 "DNBArchImplARM64::" 1509 "GetHardwareWatchpointHit() slot: %u %s", 1510 i, is_bas_watchpoint ? "is BAS watchpoint" : "is MASK watchpoint"); 1511 1512 if (is_bas_watchpoint) { 1513 if (bits(wp_addr, 48, 3) != bits(addr, 48, 3)) 1514 continue; 1515 } else { 1516 if (bits(wp_addr, 48, mask) == bits(addr, 48, mask)) { 1517 DNBLogThreadedIf(LOG_WATCHPOINTS, 1518 "DNBArchImplARM64::" 1519 "GetHardwareWatchpointHit() slot: %u matched MASK " 1520 "ignoring %u low bits", 1521 i, mask); 1522 return i; 1523 } 1524 } 1525 1526 if (is_bas_watchpoint) { 1527 // Sanity check the bas_bits 1528 uint32_t lsb = LowestBitSet(bas_bits); 1529 if (lsb < 0) 1530 continue; 1531 1532 uint64_t byte_to_match = bits(addr, 2, 0); 1533 1534 if (bas_bits & (1 << byte_to_match)) { 1535 addr = wp_addr + lsb; 1536 DNBLogThreadedIf(LOG_WATCHPOINTS, 1537 "DNBArchImplARM64::" 1538 "GetHardwareWatchpointHit() slot: %u matched BAS", 1539 i); 1540 return i; 1541 } 1542 } 1543 } 1544 } 1545 return INVALID_NUB_HW_INDEX; 1546} 1547 1548nub_addr_t DNBArchMachARM64::GetWatchpointAddressByIndex(uint32_t hw_index) { 1549 kern_return_t kret = GetDBGState(true); 1550 if (kret != KERN_SUCCESS) 1551 return INVALID_NUB_ADDRESS; 1552 const uint32_t num = NumSupportedHardwareWatchpoints(); 1553 if (hw_index >= num) 1554 return INVALID_NUB_ADDRESS; 1555 if (IsWatchpointEnabled(m_state.dbg, hw_index)) 1556 return GetWatchAddress(m_state.dbg, hw_index); 1557 return INVALID_NUB_ADDRESS; 1558} 1559 1560bool DNBArchMachARM64::IsWatchpointEnabled(const DBG &debug_state, 1561 uint32_t hw_index) { 1562 // Watchpoint Control Registers, bitfield definitions 1563 // ... 1564 // Bits Value Description 1565 // [0] 0 Watchpoint disabled 1566 // 1 Watchpoint enabled. 1567 return (debug_state.__wcr[hw_index] & 1u); 1568} 1569 1570nub_addr_t DNBArchMachARM64::GetWatchAddress(const DBG &debug_state, 1571 uint32_t hw_index) { 1572 // Watchpoint Value Registers, bitfield definitions 1573 // Bits Description 1574 // [31:2] Watchpoint value (word address, i.e., 4-byte aligned) 1575 // [1:0] RAZ/SBZP 1576 return bits(debug_state.__wvr[hw_index], 63, 0); 1577} 1578 1579// Register information definitions for 64 bit ARMv8. 1580enum gpr_regnums { 1581 gpr_x0 = 0, 1582 gpr_x1, 1583 gpr_x2, 1584 gpr_x3, 1585 gpr_x4, 1586 gpr_x5, 1587 gpr_x6, 1588 gpr_x7, 1589 gpr_x8, 1590 gpr_x9, 1591 gpr_x10, 1592 gpr_x11, 1593 gpr_x12, 1594 gpr_x13, 1595 gpr_x14, 1596 gpr_x15, 1597 gpr_x16, 1598 gpr_x17, 1599 gpr_x18, 1600 gpr_x19, 1601 gpr_x20, 1602 gpr_x21, 1603 gpr_x22, 1604 gpr_x23, 1605 gpr_x24, 1606 gpr_x25, 1607 gpr_x26, 1608 gpr_x27, 1609 gpr_x28, 1610 gpr_fp, 1611 gpr_x29 = gpr_fp, 1612 gpr_lr, 1613 gpr_x30 = gpr_lr, 1614 gpr_sp, 1615 gpr_x31 = gpr_sp, 1616 gpr_pc, 1617 gpr_cpsr, 1618 gpr_w0, 1619 gpr_w1, 1620 gpr_w2, 1621 gpr_w3, 1622 gpr_w4, 1623 gpr_w5, 1624 gpr_w6, 1625 gpr_w7, 1626 gpr_w8, 1627 gpr_w9, 1628 gpr_w10, 1629 gpr_w11, 1630 gpr_w12, 1631 gpr_w13, 1632 gpr_w14, 1633 gpr_w15, 1634 gpr_w16, 1635 gpr_w17, 1636 gpr_w18, 1637 gpr_w19, 1638 gpr_w20, 1639 gpr_w21, 1640 gpr_w22, 1641 gpr_w23, 1642 gpr_w24, 1643 gpr_w25, 1644 gpr_w26, 1645 gpr_w27, 1646 gpr_w28 1647 1648}; 1649 1650enum { 1651 vfp_v0 = 0, 1652 vfp_v1, 1653 vfp_v2, 1654 vfp_v3, 1655 vfp_v4, 1656 vfp_v5, 1657 vfp_v6, 1658 vfp_v7, 1659 vfp_v8, 1660 vfp_v9, 1661 vfp_v10, 1662 vfp_v11, 1663 vfp_v12, 1664 vfp_v13, 1665 vfp_v14, 1666 vfp_v15, 1667 vfp_v16, 1668 vfp_v17, 1669 vfp_v18, 1670 vfp_v19, 1671 vfp_v20, 1672 vfp_v21, 1673 vfp_v22, 1674 vfp_v23, 1675 vfp_v24, 1676 vfp_v25, 1677 vfp_v26, 1678 vfp_v27, 1679 vfp_v28, 1680 vfp_v29, 1681 vfp_v30, 1682 vfp_v31, 1683 vfp_fpsr, 1684 vfp_fpcr, 1685 1686 // lower 32 bits of the corresponding vfp_v<n> reg. 1687 vfp_s0, 1688 vfp_s1, 1689 vfp_s2, 1690 vfp_s3, 1691 vfp_s4, 1692 vfp_s5, 1693 vfp_s6, 1694 vfp_s7, 1695 vfp_s8, 1696 vfp_s9, 1697 vfp_s10, 1698 vfp_s11, 1699 vfp_s12, 1700 vfp_s13, 1701 vfp_s14, 1702 vfp_s15, 1703 vfp_s16, 1704 vfp_s17, 1705 vfp_s18, 1706 vfp_s19, 1707 vfp_s20, 1708 vfp_s21, 1709 vfp_s22, 1710 vfp_s23, 1711 vfp_s24, 1712 vfp_s25, 1713 vfp_s26, 1714 vfp_s27, 1715 vfp_s28, 1716 vfp_s29, 1717 vfp_s30, 1718 vfp_s31, 1719 1720 // lower 64 bits of the corresponding vfp_v<n> reg. 1721 vfp_d0, 1722 vfp_d1, 1723 vfp_d2, 1724 vfp_d3, 1725 vfp_d4, 1726 vfp_d5, 1727 vfp_d6, 1728 vfp_d7, 1729 vfp_d8, 1730 vfp_d9, 1731 vfp_d10, 1732 vfp_d11, 1733 vfp_d12, 1734 vfp_d13, 1735 vfp_d14, 1736 vfp_d15, 1737 vfp_d16, 1738 vfp_d17, 1739 vfp_d18, 1740 vfp_d19, 1741 vfp_d20, 1742 vfp_d21, 1743 vfp_d22, 1744 vfp_d23, 1745 vfp_d24, 1746 vfp_d25, 1747 vfp_d26, 1748 vfp_d27, 1749 vfp_d28, 1750 vfp_d29, 1751 vfp_d30, 1752 vfp_d31 1753}; 1754 1755enum { 1756 sve_z0, 1757 sve_z1, 1758 sve_z2, 1759 sve_z3, 1760 sve_z4, 1761 sve_z5, 1762 sve_z6, 1763 sve_z7, 1764 sve_z8, 1765 sve_z9, 1766 sve_z10, 1767 sve_z11, 1768 sve_z12, 1769 sve_z13, 1770 sve_z14, 1771 sve_z15, 1772 sve_z16, 1773 sve_z17, 1774 sve_z18, 1775 sve_z19, 1776 sve_z20, 1777 sve_z21, 1778 sve_z22, 1779 sve_z23, 1780 sve_z24, 1781 sve_z25, 1782 sve_z26, 1783 sve_z27, 1784 sve_z28, 1785 sve_z29, 1786 sve_z30, 1787 sve_z31, 1788 sve_p0, 1789 sve_p1, 1790 sve_p2, 1791 sve_p3, 1792 sve_p4, 1793 sve_p5, 1794 sve_p6, 1795 sve_p7, 1796 sve_p8, 1797 sve_p9, 1798 sve_p10, 1799 sve_p11, 1800 sve_p12, 1801 sve_p13, 1802 sve_p14, 1803 sve_p15 1804}; 1805 1806enum { sme_svcr, sme_tpidr2, sme_svl_b, sme_za, sme_zt0 }; 1807 1808enum { exc_far = 0, exc_esr, exc_exception }; 1809 1810// These numbers from the "DWARF for the ARM 64-bit Architecture (AArch64)" 1811// document. 1812 1813enum { 1814 dwarf_x0 = 0, 1815 dwarf_x1, 1816 dwarf_x2, 1817 dwarf_x3, 1818 dwarf_x4, 1819 dwarf_x5, 1820 dwarf_x6, 1821 dwarf_x7, 1822 dwarf_x8, 1823 dwarf_x9, 1824 dwarf_x10, 1825 dwarf_x11, 1826 dwarf_x12, 1827 dwarf_x13, 1828 dwarf_x14, 1829 dwarf_x15, 1830 dwarf_x16, 1831 dwarf_x17, 1832 dwarf_x18, 1833 dwarf_x19, 1834 dwarf_x20, 1835 dwarf_x21, 1836 dwarf_x22, 1837 dwarf_x23, 1838 dwarf_x24, 1839 dwarf_x25, 1840 dwarf_x26, 1841 dwarf_x27, 1842 dwarf_x28, 1843 dwarf_x29, 1844 dwarf_x30, 1845 dwarf_x31, 1846 dwarf_pc = 32, 1847 dwarf_elr_mode = 33, 1848 dwarf_fp = dwarf_x29, 1849 dwarf_lr = dwarf_x30, 1850 dwarf_sp = dwarf_x31, 1851 // 34-63 reserved 1852 1853 // V0-V31 (128 bit vector registers) 1854 dwarf_v0 = 64, 1855 dwarf_v1, 1856 dwarf_v2, 1857 dwarf_v3, 1858 dwarf_v4, 1859 dwarf_v5, 1860 dwarf_v6, 1861 dwarf_v7, 1862 dwarf_v8, 1863 dwarf_v9, 1864 dwarf_v10, 1865 dwarf_v11, 1866 dwarf_v12, 1867 dwarf_v13, 1868 dwarf_v14, 1869 dwarf_v15, 1870 dwarf_v16, 1871 dwarf_v17, 1872 dwarf_v18, 1873 dwarf_v19, 1874 dwarf_v20, 1875 dwarf_v21, 1876 dwarf_v22, 1877 dwarf_v23, 1878 dwarf_v24, 1879 dwarf_v25, 1880 dwarf_v26, 1881 dwarf_v27, 1882 dwarf_v28, 1883 dwarf_v29, 1884 dwarf_v30, 1885 dwarf_v31 1886 1887 // 96-127 reserved 1888}; 1889 1890enum { 1891 debugserver_gpr_x0 = 0, 1892 debugserver_gpr_x1, 1893 debugserver_gpr_x2, 1894 debugserver_gpr_x3, 1895 debugserver_gpr_x4, 1896 debugserver_gpr_x5, 1897 debugserver_gpr_x6, 1898 debugserver_gpr_x7, 1899 debugserver_gpr_x8, 1900 debugserver_gpr_x9, 1901 debugserver_gpr_x10, 1902 debugserver_gpr_x11, 1903 debugserver_gpr_x12, 1904 debugserver_gpr_x13, 1905 debugserver_gpr_x14, 1906 debugserver_gpr_x15, 1907 debugserver_gpr_x16, 1908 debugserver_gpr_x17, 1909 debugserver_gpr_x18, 1910 debugserver_gpr_x19, 1911 debugserver_gpr_x20, 1912 debugserver_gpr_x21, 1913 debugserver_gpr_x22, 1914 debugserver_gpr_x23, 1915 debugserver_gpr_x24, 1916 debugserver_gpr_x25, 1917 debugserver_gpr_x26, 1918 debugserver_gpr_x27, 1919 debugserver_gpr_x28, 1920 debugserver_gpr_fp, // x29 1921 debugserver_gpr_lr, // x30 1922 debugserver_gpr_sp, // sp aka xsp 1923 debugserver_gpr_pc, 1924 debugserver_gpr_cpsr, 1925 debugserver_vfp_v0, 1926 debugserver_vfp_v1, 1927 debugserver_vfp_v2, 1928 debugserver_vfp_v3, 1929 debugserver_vfp_v4, 1930 debugserver_vfp_v5, 1931 debugserver_vfp_v6, 1932 debugserver_vfp_v7, 1933 debugserver_vfp_v8, 1934 debugserver_vfp_v9, 1935 debugserver_vfp_v10, 1936 debugserver_vfp_v11, 1937 debugserver_vfp_v12, 1938 debugserver_vfp_v13, 1939 debugserver_vfp_v14, 1940 debugserver_vfp_v15, 1941 debugserver_vfp_v16, 1942 debugserver_vfp_v17, 1943 debugserver_vfp_v18, 1944 debugserver_vfp_v19, 1945 debugserver_vfp_v20, 1946 debugserver_vfp_v21, 1947 debugserver_vfp_v22, 1948 debugserver_vfp_v23, 1949 debugserver_vfp_v24, 1950 debugserver_vfp_v25, 1951 debugserver_vfp_v26, 1952 debugserver_vfp_v27, 1953 debugserver_vfp_v28, 1954 debugserver_vfp_v29, 1955 debugserver_vfp_v30, 1956 debugserver_vfp_v31, 1957 debugserver_vfp_fpsr, 1958 debugserver_vfp_fpcr, 1959 debugserver_sve_z0, 1960 debugserver_sve_z1, 1961 debugserver_sve_z2, 1962 debugserver_sve_z3, 1963 debugserver_sve_z4, 1964 debugserver_sve_z5, 1965 debugserver_sve_z6, 1966 debugserver_sve_z7, 1967 debugserver_sve_z8, 1968 debugserver_sve_z9, 1969 debugserver_sve_z10, 1970 debugserver_sve_z11, 1971 debugserver_sve_z12, 1972 debugserver_sve_z13, 1973 debugserver_sve_z14, 1974 debugserver_sve_z15, 1975 debugserver_sve_z16, 1976 debugserver_sve_z17, 1977 debugserver_sve_z18, 1978 debugserver_sve_z19, 1979 debugserver_sve_z20, 1980 debugserver_sve_z21, 1981 debugserver_sve_z22, 1982 debugserver_sve_z23, 1983 debugserver_sve_z24, 1984 debugserver_sve_z25, 1985 debugserver_sve_z26, 1986 debugserver_sve_z27, 1987 debugserver_sve_z28, 1988 debugserver_sve_z29, 1989 debugserver_sve_z30, 1990 debugserver_sve_z31, 1991 debugserver_sve_p0, 1992 debugserver_sve_p1, 1993 debugserver_sve_p2, 1994 debugserver_sve_p3, 1995 debugserver_sve_p4, 1996 debugserver_sve_p5, 1997 debugserver_sve_p6, 1998 debugserver_sve_p7, 1999 debugserver_sve_p8, 2000 debugserver_sve_p9, 2001 debugserver_sve_p10, 2002 debugserver_sve_p11, 2003 debugserver_sve_p12, 2004 debugserver_sve_p13, 2005 debugserver_sve_p14, 2006 debugserver_sve_p15, 2007 debugserver_sme_svcr, 2008 debugserver_sme_tpidr2, 2009 debugserver_sme_svl_b, 2010 debugserver_sme_za, 2011 debugserver_sme_zt0 2012}; 2013 2014const char *g_contained_x0[]{"x0", NULL}; 2015const char *g_contained_x1[]{"x1", NULL}; 2016const char *g_contained_x2[]{"x2", NULL}; 2017const char *g_contained_x3[]{"x3", NULL}; 2018const char *g_contained_x4[]{"x4", NULL}; 2019const char *g_contained_x5[]{"x5", NULL}; 2020const char *g_contained_x6[]{"x6", NULL}; 2021const char *g_contained_x7[]{"x7", NULL}; 2022const char *g_contained_x8[]{"x8", NULL}; 2023const char *g_contained_x9[]{"x9", NULL}; 2024const char *g_contained_x10[]{"x10", NULL}; 2025const char *g_contained_x11[]{"x11", NULL}; 2026const char *g_contained_x12[]{"x12", NULL}; 2027const char *g_contained_x13[]{"x13", NULL}; 2028const char *g_contained_x14[]{"x14", NULL}; 2029const char *g_contained_x15[]{"x15", NULL}; 2030const char *g_contained_x16[]{"x16", NULL}; 2031const char *g_contained_x17[]{"x17", NULL}; 2032const char *g_contained_x18[]{"x18", NULL}; 2033const char *g_contained_x19[]{"x19", NULL}; 2034const char *g_contained_x20[]{"x20", NULL}; 2035const char *g_contained_x21[]{"x21", NULL}; 2036const char *g_contained_x22[]{"x22", NULL}; 2037const char *g_contained_x23[]{"x23", NULL}; 2038const char *g_contained_x24[]{"x24", NULL}; 2039const char *g_contained_x25[]{"x25", NULL}; 2040const char *g_contained_x26[]{"x26", NULL}; 2041const char *g_contained_x27[]{"x27", NULL}; 2042const char *g_contained_x28[]{"x28", NULL}; 2043 2044const char *g_invalidate_x0[]{"x0", "w0", NULL}; 2045const char *g_invalidate_x1[]{"x1", "w1", NULL}; 2046const char *g_invalidate_x2[]{"x2", "w2", NULL}; 2047const char *g_invalidate_x3[]{"x3", "w3", NULL}; 2048const char *g_invalidate_x4[]{"x4", "w4", NULL}; 2049const char *g_invalidate_x5[]{"x5", "w5", NULL}; 2050const char *g_invalidate_x6[]{"x6", "w6", NULL}; 2051const char *g_invalidate_x7[]{"x7", "w7", NULL}; 2052const char *g_invalidate_x8[]{"x8", "w8", NULL}; 2053const char *g_invalidate_x9[]{"x9", "w9", NULL}; 2054const char *g_invalidate_x10[]{"x10", "w10", NULL}; 2055const char *g_invalidate_x11[]{"x11", "w11", NULL}; 2056const char *g_invalidate_x12[]{"x12", "w12", NULL}; 2057const char *g_invalidate_x13[]{"x13", "w13", NULL}; 2058const char *g_invalidate_x14[]{"x14", "w14", NULL}; 2059const char *g_invalidate_x15[]{"x15", "w15", NULL}; 2060const char *g_invalidate_x16[]{"x16", "w16", NULL}; 2061const char *g_invalidate_x17[]{"x17", "w17", NULL}; 2062const char *g_invalidate_x18[]{"x18", "w18", NULL}; 2063const char *g_invalidate_x19[]{"x19", "w19", NULL}; 2064const char *g_invalidate_x20[]{"x20", "w20", NULL}; 2065const char *g_invalidate_x21[]{"x21", "w21", NULL}; 2066const char *g_invalidate_x22[]{"x22", "w22", NULL}; 2067const char *g_invalidate_x23[]{"x23", "w23", NULL}; 2068const char *g_invalidate_x24[]{"x24", "w24", NULL}; 2069const char *g_invalidate_x25[]{"x25", "w25", NULL}; 2070const char *g_invalidate_x26[]{"x26", "w26", NULL}; 2071const char *g_invalidate_x27[]{"x27", "w27", NULL}; 2072const char *g_invalidate_x28[]{"x28", "w28", NULL}; 2073 2074#define GPR_OFFSET_IDX(idx) (offsetof(DNBArchMachARM64::GPR, __x[idx])) 2075 2076#define GPR_OFFSET_NAME(reg) (offsetof(DNBArchMachARM64::GPR, __##reg)) 2077 2078// These macros will auto define the register name, alt name, register size, 2079// register offset, encoding, format and native register. This ensures that 2080// the register state structures are defined correctly and have the correct 2081// sizes and offsets. 2082#define DEFINE_GPR_IDX(idx, reg, alt, gen) \ 2083 { \ 2084 e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_IDX(idx), \ 2085 dwarf_##reg, dwarf_##reg, gen, debugserver_gpr_##reg, NULL, \ 2086 g_invalidate_x##idx \ 2087 } 2088#define DEFINE_GPR_NAME(reg, alt, gen) \ 2089 { \ 2090 e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_NAME(reg), \ 2091 dwarf_##reg, dwarf_##reg, gen, debugserver_gpr_##reg, NULL, NULL \ 2092 } 2093#define DEFINE_PSEUDO_GPR_IDX(idx, reg) \ 2094 { \ 2095 e_regSetGPR, gpr_##reg, #reg, NULL, Uint, Hex, 4, 0, INVALID_NUB_REGNUM, \ 2096 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ 2097 g_contained_x##idx, g_invalidate_x##idx \ 2098 } 2099 2100//_STRUCT_ARM_THREAD_STATE64 2101//{ 2102// uint64_t x[29]; /* General purpose registers x0-x28 */ 2103// uint64_t fp; /* Frame pointer x29 */ 2104// uint64_t lr; /* Link register x30 */ 2105// uint64_t sp; /* Stack pointer x31 */ 2106// uint64_t pc; /* Program counter */ 2107// uint32_t cpsr; /* Current program status register */ 2108//}; 2109 2110// General purpose registers 2111const DNBRegisterInfo DNBArchMachARM64::g_gpr_registers[] = { 2112 DEFINE_GPR_IDX(0, x0, "arg1", GENERIC_REGNUM_ARG1), 2113 DEFINE_GPR_IDX(1, x1, "arg2", GENERIC_REGNUM_ARG2), 2114 DEFINE_GPR_IDX(2, x2, "arg3", GENERIC_REGNUM_ARG3), 2115 DEFINE_GPR_IDX(3, x3, "arg4", GENERIC_REGNUM_ARG4), 2116 DEFINE_GPR_IDX(4, x4, "arg5", GENERIC_REGNUM_ARG5), 2117 DEFINE_GPR_IDX(5, x5, "arg6", GENERIC_REGNUM_ARG6), 2118 DEFINE_GPR_IDX(6, x6, "arg7", GENERIC_REGNUM_ARG7), 2119 DEFINE_GPR_IDX(7, x7, "arg8", GENERIC_REGNUM_ARG8), 2120 DEFINE_GPR_IDX(8, x8, NULL, INVALID_NUB_REGNUM), 2121 DEFINE_GPR_IDX(9, x9, NULL, INVALID_NUB_REGNUM), 2122 DEFINE_GPR_IDX(10, x10, NULL, INVALID_NUB_REGNUM), 2123 DEFINE_GPR_IDX(11, x11, NULL, INVALID_NUB_REGNUM), 2124 DEFINE_GPR_IDX(12, x12, NULL, INVALID_NUB_REGNUM), 2125 DEFINE_GPR_IDX(13, x13, NULL, INVALID_NUB_REGNUM), 2126 DEFINE_GPR_IDX(14, x14, NULL, INVALID_NUB_REGNUM), 2127 DEFINE_GPR_IDX(15, x15, NULL, INVALID_NUB_REGNUM), 2128 DEFINE_GPR_IDX(16, x16, NULL, INVALID_NUB_REGNUM), 2129 DEFINE_GPR_IDX(17, x17, NULL, INVALID_NUB_REGNUM), 2130 DEFINE_GPR_IDX(18, x18, NULL, INVALID_NUB_REGNUM), 2131 DEFINE_GPR_IDX(19, x19, NULL, INVALID_NUB_REGNUM), 2132 DEFINE_GPR_IDX(20, x20, NULL, INVALID_NUB_REGNUM), 2133 DEFINE_GPR_IDX(21, x21, NULL, INVALID_NUB_REGNUM), 2134 DEFINE_GPR_IDX(22, x22, NULL, INVALID_NUB_REGNUM), 2135 DEFINE_GPR_IDX(23, x23, NULL, INVALID_NUB_REGNUM), 2136 DEFINE_GPR_IDX(24, x24, NULL, INVALID_NUB_REGNUM), 2137 DEFINE_GPR_IDX(25, x25, NULL, INVALID_NUB_REGNUM), 2138 DEFINE_GPR_IDX(26, x26, NULL, INVALID_NUB_REGNUM), 2139 DEFINE_GPR_IDX(27, x27, NULL, INVALID_NUB_REGNUM), 2140 DEFINE_GPR_IDX(28, x28, NULL, INVALID_NUB_REGNUM), 2141 // For the G/g packet we want to show where the offset into the regctx 2142 // is for fp/lr/sp/pc, but we cannot directly access them on arm64e 2143 // devices (and therefore can't offsetof() them)) - add the offset based 2144 // on the last accessible register by hand for advertising the location 2145 // in the regctx to lldb. We'll go through the accessor functions when 2146 // we read/write them here. 2147 { 2148 e_regSetGPR, gpr_fp, "fp", "x29", Uint, Hex, 8, GPR_OFFSET_IDX(28) + 8, 2149 dwarf_fp, dwarf_fp, GENERIC_REGNUM_FP, debugserver_gpr_fp, NULL, NULL 2150 }, 2151 { 2152 e_regSetGPR, gpr_lr, "lr", "x30", Uint, Hex, 8, GPR_OFFSET_IDX(28) + 16, 2153 dwarf_lr, dwarf_lr, GENERIC_REGNUM_RA, debugserver_gpr_lr, NULL, NULL 2154 }, 2155 { 2156 e_regSetGPR, gpr_sp, "sp", "xsp", Uint, Hex, 8, GPR_OFFSET_IDX(28) + 24, 2157 dwarf_sp, dwarf_sp, GENERIC_REGNUM_SP, debugserver_gpr_sp, NULL, NULL 2158 }, 2159 { 2160 e_regSetGPR, gpr_pc, "pc", NULL, Uint, Hex, 8, GPR_OFFSET_IDX(28) + 32, 2161 dwarf_pc, dwarf_pc, GENERIC_REGNUM_PC, debugserver_gpr_pc, NULL, NULL 2162 }, 2163 2164 // in armv7 we specify that writing to the CPSR should invalidate r8-12, sp, 2165 // lr. 2166 // this should be specified for arm64 too even though debugserver is only 2167 // used for 2168 // userland debugging. 2169 {e_regSetGPR, gpr_cpsr, "cpsr", "flags", Uint, Hex, 4, 2170 GPR_OFFSET_NAME(cpsr), dwarf_elr_mode, dwarf_elr_mode, GENERIC_REGNUM_FLAGS, 2171 debugserver_gpr_cpsr, NULL, NULL}, 2172 2173 DEFINE_PSEUDO_GPR_IDX(0, w0), 2174 DEFINE_PSEUDO_GPR_IDX(1, w1), 2175 DEFINE_PSEUDO_GPR_IDX(2, w2), 2176 DEFINE_PSEUDO_GPR_IDX(3, w3), 2177 DEFINE_PSEUDO_GPR_IDX(4, w4), 2178 DEFINE_PSEUDO_GPR_IDX(5, w5), 2179 DEFINE_PSEUDO_GPR_IDX(6, w6), 2180 DEFINE_PSEUDO_GPR_IDX(7, w7), 2181 DEFINE_PSEUDO_GPR_IDX(8, w8), 2182 DEFINE_PSEUDO_GPR_IDX(9, w9), 2183 DEFINE_PSEUDO_GPR_IDX(10, w10), 2184 DEFINE_PSEUDO_GPR_IDX(11, w11), 2185 DEFINE_PSEUDO_GPR_IDX(12, w12), 2186 DEFINE_PSEUDO_GPR_IDX(13, w13), 2187 DEFINE_PSEUDO_GPR_IDX(14, w14), 2188 DEFINE_PSEUDO_GPR_IDX(15, w15), 2189 DEFINE_PSEUDO_GPR_IDX(16, w16), 2190 DEFINE_PSEUDO_GPR_IDX(17, w17), 2191 DEFINE_PSEUDO_GPR_IDX(18, w18), 2192 DEFINE_PSEUDO_GPR_IDX(19, w19), 2193 DEFINE_PSEUDO_GPR_IDX(20, w20), 2194 DEFINE_PSEUDO_GPR_IDX(21, w21), 2195 DEFINE_PSEUDO_GPR_IDX(22, w22), 2196 DEFINE_PSEUDO_GPR_IDX(23, w23), 2197 DEFINE_PSEUDO_GPR_IDX(24, w24), 2198 DEFINE_PSEUDO_GPR_IDX(25, w25), 2199 DEFINE_PSEUDO_GPR_IDX(26, w26), 2200 DEFINE_PSEUDO_GPR_IDX(27, w27), 2201 DEFINE_PSEUDO_GPR_IDX(28, w28)}; 2202 2203const char *g_contained_v0[]{"v0", NULL}; 2204const char *g_contained_v1[]{"v1", NULL}; 2205const char *g_contained_v2[]{"v2", NULL}; 2206const char *g_contained_v3[]{"v3", NULL}; 2207const char *g_contained_v4[]{"v4", NULL}; 2208const char *g_contained_v5[]{"v5", NULL}; 2209const char *g_contained_v6[]{"v6", NULL}; 2210const char *g_contained_v7[]{"v7", NULL}; 2211const char *g_contained_v8[]{"v8", NULL}; 2212const char *g_contained_v9[]{"v9", NULL}; 2213const char *g_contained_v10[]{"v10", NULL}; 2214const char *g_contained_v11[]{"v11", NULL}; 2215const char *g_contained_v12[]{"v12", NULL}; 2216const char *g_contained_v13[]{"v13", NULL}; 2217const char *g_contained_v14[]{"v14", NULL}; 2218const char *g_contained_v15[]{"v15", NULL}; 2219const char *g_contained_v16[]{"v16", NULL}; 2220const char *g_contained_v17[]{"v17", NULL}; 2221const char *g_contained_v18[]{"v18", NULL}; 2222const char *g_contained_v19[]{"v19", NULL}; 2223const char *g_contained_v20[]{"v20", NULL}; 2224const char *g_contained_v21[]{"v21", NULL}; 2225const char *g_contained_v22[]{"v22", NULL}; 2226const char *g_contained_v23[]{"v23", NULL}; 2227const char *g_contained_v24[]{"v24", NULL}; 2228const char *g_contained_v25[]{"v25", NULL}; 2229const char *g_contained_v26[]{"v26", NULL}; 2230const char *g_contained_v27[]{"v27", NULL}; 2231const char *g_contained_v28[]{"v28", NULL}; 2232const char *g_contained_v29[]{"v29", NULL}; 2233const char *g_contained_v30[]{"v30", NULL}; 2234const char *g_contained_v31[]{"v31", NULL}; 2235 2236const char *g_invalidate_v[32][4]{ 2237 {"v0", "d0", "s0", NULL}, {"v1", "d1", "s1", NULL}, 2238 {"v2", "d2", "s2", NULL}, {"v3", "d3", "s3", NULL}, 2239 {"v4", "d4", "s4", NULL}, {"v5", "d5", "s5", NULL}, 2240 {"v6", "d6", "s6", NULL}, {"v7", "d7", "s7", NULL}, 2241 {"v8", "d8", "s8", NULL}, {"v9", "d9", "s9", NULL}, 2242 {"v10", "d10", "s10", NULL}, {"v11", "d11", "s11", NULL}, 2243 {"v12", "d12", "s12", NULL}, {"v13", "d13", "s13", NULL}, 2244 {"v14", "d14", "s14", NULL}, {"v15", "d15", "s15", NULL}, 2245 {"v16", "d16", "s16", NULL}, {"v17", "d17", "s17", NULL}, 2246 {"v18", "d18", "s18", NULL}, {"v19", "d19", "s19", NULL}, 2247 {"v20", "d20", "s20", NULL}, {"v21", "d21", "s21", NULL}, 2248 {"v22", "d22", "s22", NULL}, {"v23", "d23", "s23", NULL}, 2249 {"v24", "d24", "s24", NULL}, {"v25", "d25", "s25", NULL}, 2250 {"v26", "d26", "s26", NULL}, {"v27", "d27", "s27", NULL}, 2251 {"v28", "d28", "s28", NULL}, {"v29", "d29", "s29", NULL}, 2252 {"v30", "d30", "s30", NULL}, {"v31", "d31", "s31", NULL}}; 2253 2254const char *g_invalidate_z[32][5]{ 2255 {"z0", "v0", "d0", "s0", NULL}, {"z1", "v1", "d1", "s1", NULL}, 2256 {"z2", "v2", "d2", "s2", NULL}, {"z3", "v3", "d3", "s3", NULL}, 2257 {"z4", "v4", "d4", "s4", NULL}, {"z5", "v5", "d5", "s5", NULL}, 2258 {"z6", "v6", "d6", "s6", NULL}, {"z7", "v7", "d7", "s7", NULL}, 2259 {"z8", "v8", "d8", "s8", NULL}, {"z9", "v9", "d9", "s9", NULL}, 2260 {"z10", "v10", "d10", "s10", NULL}, {"z11", "v11", "d11", "s11", NULL}, 2261 {"z12", "v12", "d12", "s12", NULL}, {"z13", "v13", "d13", "s13", NULL}, 2262 {"z14", "v14", "d14", "s14", NULL}, {"z15", "v15", "d15", "s15", NULL}, 2263 {"z16", "v16", "d16", "s16", NULL}, {"z17", "v17", "d17", "s17", NULL}, 2264 {"z18", "v18", "d18", "s18", NULL}, {"z19", "v19", "d19", "s19", NULL}, 2265 {"z20", "v20", "d20", "s20", NULL}, {"z21", "v21", "d21", "s21", NULL}, 2266 {"z22", "v22", "d22", "s22", NULL}, {"z23", "v23", "d23", "s23", NULL}, 2267 {"z24", "v24", "d24", "s24", NULL}, {"z25", "v25", "d25", "s25", NULL}, 2268 {"z26", "v26", "d26", "s26", NULL}, {"z27", "v27", "d27", "s27", NULL}, 2269 {"z28", "v28", "d28", "s28", NULL}, {"z29", "v29", "d29", "s29", NULL}, 2270 {"z30", "v30", "d30", "s30", NULL}, {"z31", "v31", "d31", "s31", NULL}}; 2271 2272const char *g_contained_z0[]{"z0", NULL}; 2273const char *g_contained_z1[]{"z1", NULL}; 2274const char *g_contained_z2[]{"z2", NULL}; 2275const char *g_contained_z3[]{"z3", NULL}; 2276const char *g_contained_z4[]{"z4", NULL}; 2277const char *g_contained_z5[]{"z5", NULL}; 2278const char *g_contained_z6[]{"z6", NULL}; 2279const char *g_contained_z7[]{"z7", NULL}; 2280const char *g_contained_z8[]{"z8", NULL}; 2281const char *g_contained_z9[]{"z9", NULL}; 2282const char *g_contained_z10[]{"z10", NULL}; 2283const char *g_contained_z11[]{"z11", NULL}; 2284const char *g_contained_z12[]{"z12", NULL}; 2285const char *g_contained_z13[]{"z13", NULL}; 2286const char *g_contained_z14[]{"z14", NULL}; 2287const char *g_contained_z15[]{"z15", NULL}; 2288const char *g_contained_z16[]{"z16", NULL}; 2289const char *g_contained_z17[]{"z17", NULL}; 2290const char *g_contained_z18[]{"z18", NULL}; 2291const char *g_contained_z19[]{"z19", NULL}; 2292const char *g_contained_z20[]{"z20", NULL}; 2293const char *g_contained_z21[]{"z21", NULL}; 2294const char *g_contained_z22[]{"z22", NULL}; 2295const char *g_contained_z23[]{"z23", NULL}; 2296const char *g_contained_z24[]{"z24", NULL}; 2297const char *g_contained_z25[]{"z25", NULL}; 2298const char *g_contained_z26[]{"z26", NULL}; 2299const char *g_contained_z27[]{"z27", NULL}; 2300const char *g_contained_z28[]{"z28", NULL}; 2301const char *g_contained_z29[]{"z29", NULL}; 2302const char *g_contained_z30[]{"z30", NULL}; 2303const char *g_contained_z31[]{"z31", NULL}; 2304 2305#if defined(__arm64__) || defined(__aarch64__) 2306#define VFP_V_OFFSET_IDX(idx) \ 2307 (offsetof(DNBArchMachARM64::FPU, __v) + (idx * 16) + \ 2308 offsetof(DNBArchMachARM64::Context, vfp)) 2309#else 2310#define VFP_V_OFFSET_IDX(idx) \ 2311 (offsetof(DNBArchMachARM64::FPU, opaque) + (idx * 16) + \ 2312 offsetof(DNBArchMachARM64::Context, vfp)) 2313#endif 2314#define EXC_OFFSET(reg) \ 2315 (offsetof(DNBArchMachARM64::EXC, reg) + \ 2316 offsetof(DNBArchMachARM64::Context, exc)) 2317#define SVE_OFFSET_Z_IDX(idx) \ 2318 (offsetof(DNBArchMachARM64::SVE, z[idx]) + \ 2319 offsetof(DNBArchMachARM64::Context, sve)) 2320#define SVE_OFFSET_P_IDX(idx) \ 2321 (offsetof(DNBArchMachARM64::SVE, p[idx]) + \ 2322 offsetof(DNBArchMachARM64::Context, sve)) 2323#define SME_OFFSET(reg) \ 2324 (offsetof(DNBArchMachARM64::SME, reg) + \ 2325 offsetof(DNBArchMachARM64::Context, sme)) 2326 2327//_STRUCT_ARM_EXCEPTION_STATE64 2328//{ 2329// uint64_t far; /* Virtual Fault Address */ 2330// uint32_t esr; /* Exception syndrome */ 2331// uint32_t exception; /* number of arm exception taken */ 2332//}; 2333 2334// Exception registers 2335const DNBRegisterInfo DNBArchMachARM64::g_exc_registers[] = { 2336 {e_regSetEXC, exc_far, "far", NULL, Uint, Hex, 8, EXC_OFFSET(__far), 2337 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2338 INVALID_NUB_REGNUM, NULL, NULL}, 2339 {e_regSetEXC, exc_esr, "esr", NULL, Uint, Hex, 4, EXC_OFFSET(__esr), 2340 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2341 INVALID_NUB_REGNUM, NULL, NULL}, 2342 {e_regSetEXC, exc_exception, "exception", NULL, Uint, Hex, 4, 2343 EXC_OFFSET(__exception), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2344 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}}; 2345 2346// Number of registers in each register set 2347const size_t DNBArchMachARM64::k_num_gpr_registers = 2348 sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo); 2349const size_t DNBArchMachARM64::k_num_exc_registers = 2350 sizeof(g_exc_registers) / sizeof(DNBRegisterInfo); 2351 2352static std::vector<DNBRegisterInfo> g_sve_registers; 2353static void initialize_sve_registers() { 2354 static const char *g_z_regnames[32] = { 2355 "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", 2356 "z8", "z9", "z10", "z11", "z12", "z13", "z14", "z15", 2357 "z16", "z17", "z18", "z19", "z20", "z21", "z22", "z23", 2358 "z24", "z25", "z26", "z27", "z28", "z29", "z30", "z31"}; 2359 static const char *g_p_regnames[16] = { 2360 "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7", 2361 "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15"}; 2362 2363 if (DNBArchMachARM64::CPUHasSME()) { 2364 uint32_t svl_bytes = DNBArchMachARM64::GetSMEMaxSVL(); 2365 for (uint32_t i = 0; i < 32; i++) { 2366 g_sve_registers.push_back( 2367 {DNBArchMachARM64::e_regSetSVE, (uint32_t)sve_z0 + i, g_z_regnames[i], 2368 NULL, Vector, VectorOfUInt8, svl_bytes, 2369 static_cast<uint32_t>(SVE_OFFSET_Z_IDX(i)), INVALID_NUB_REGNUM, 2370 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2371 (uint32_t)debugserver_sve_z0 + i, NULL, g_invalidate_z[i]}); 2372 } 2373 for (uint32_t i = 0; i < 16; i++) { 2374 g_sve_registers.push_back( 2375 {DNBArchMachARM64::e_regSetSVE, (uint32_t)sve_p0 + i, g_p_regnames[i], 2376 NULL, Vector, VectorOfUInt8, svl_bytes / 8, 2377 (uint32_t)SVE_OFFSET_P_IDX(i), INVALID_NUB_REGNUM, 2378 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2379 (uint32_t)debugserver_sve_p0 + i, NULL, NULL}); 2380 } 2381 } 2382} 2383 2384static std::vector<DNBRegisterInfo> g_vfp_registers; 2385static void initialize_vfp_registers() { 2386 static const char *g_v_regnames[32] = { 2387 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", 2388 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", 2389 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", 2390 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"}; 2391 static const char *g_q_regnames[32] = { 2392 "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 2393 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", 2394 "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23", 2395 "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31"}; 2396 2397 static const char *g_d_regnames[32] = { 2398 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", 2399 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", 2400 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", 2401 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"}; 2402 2403 static const char *g_s_regnames[32] = { 2404 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 2405 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", 2406 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", 2407 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"}; 2408 2409 for (uint32_t i = 0; i < 32; i++) 2410 if (DNBArchMachARM64::CPUHasSME()) 2411 g_vfp_registers.push_back( 2412 {DNBArchMachARM64::e_regSetVFP, (uint32_t)vfp_v0 + i, g_v_regnames[i], 2413 g_q_regnames[i], Vector, VectorOfUInt8, 16, 2414 static_cast<uint32_t>(VFP_V_OFFSET_IDX(i)), INVALID_NUB_REGNUM, 2415 (uint32_t)dwarf_v0 + i, INVALID_NUB_REGNUM, 2416 (uint32_t)debugserver_vfp_v0 + i, NULL, g_invalidate_z[i]}); 2417 else 2418 g_vfp_registers.push_back( 2419 {DNBArchMachARM64::e_regSetVFP, (uint32_t)vfp_v0 + i, g_v_regnames[i], 2420 g_q_regnames[i], Vector, VectorOfUInt8, 16, 2421 static_cast<uint32_t>(VFP_V_OFFSET_IDX(i)), INVALID_NUB_REGNUM, 2422 (uint32_t)dwarf_v0 + i, INVALID_NUB_REGNUM, 2423 (uint32_t)debugserver_vfp_v0 + i, NULL, g_invalidate_v[i]}); 2424 2425 g_vfp_registers.push_back( 2426 {DNBArchMachARM64::e_regSetVFP, vfp_fpsr, "fpsr", NULL, Uint, Hex, 4, 2427 VFP_V_OFFSET_IDX(32) + 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2428 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}); 2429 g_vfp_registers.push_back( 2430 {DNBArchMachARM64::e_regSetVFP, vfp_fpcr, "fpcr", NULL, Uint, Hex, 4, 2431 VFP_V_OFFSET_IDX(32) + 4, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2432 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}); 2433 2434 for (uint32_t i = 0; i < 32; i++) 2435 if (DNBArchMachARM64::CPUHasSME()) 2436 g_vfp_registers.push_back( 2437 {DNBArchMachARM64::e_regSetVFP, (uint32_t)vfp_d0 + i, g_d_regnames[i], 2438 NULL, IEEE754, Float, 8, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2439 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, g_invalidate_z[i]}); 2440 else 2441 g_vfp_registers.push_back( 2442 {DNBArchMachARM64::e_regSetVFP, (uint32_t)vfp_d0 + i, g_d_regnames[i], 2443 NULL, IEEE754, Float, 8, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2444 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, g_invalidate_v[i]}); 2445 2446 for (uint32_t i = 0; i < 32; i++) 2447 if (DNBArchMachARM64::CPUHasSME()) 2448 g_vfp_registers.push_back( 2449 {DNBArchMachARM64::e_regSetVFP, (uint32_t)vfp_s0 + i, g_s_regnames[i], 2450 NULL, IEEE754, Float, 4, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2451 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, g_invalidate_z[i]}); 2452 else 2453 g_vfp_registers.push_back( 2454 {DNBArchMachARM64::e_regSetVFP, (uint32_t)vfp_s0 + i, g_s_regnames[i], 2455 NULL, IEEE754, Float, 4, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2456 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, g_invalidate_v[i]}); 2457} 2458 2459static std::once_flag g_vfp_once; 2460DNBRegisterInfo * 2461DNBArchMachARM64::get_vfp_registerinfo(size_t &num_vfp_registers) { 2462 std::call_once(g_vfp_once, []() { initialize_vfp_registers(); }); 2463 num_vfp_registers = g_vfp_registers.size(); 2464 if (num_vfp_registers > 0) 2465 return g_vfp_registers.data(); 2466 else 2467 return nullptr; 2468} 2469 2470static std::once_flag g_sve_once; 2471DNBRegisterInfo * 2472DNBArchMachARM64::get_sve_registerinfo(size_t &num_sve_registers) { 2473 std::call_once(g_sve_once, []() { initialize_sve_registers(); }); 2474 num_sve_registers = g_sve_registers.size(); 2475 if (num_sve_registers > 0) 2476 return g_sve_registers.data(); 2477 else 2478 return nullptr; 2479} 2480 2481static std::vector<DNBRegisterInfo> g_sme_registers; 2482static void initialize_sme_registers() { 2483 if (DNBArchMachARM64::CPUHasSME()) { 2484 uint32_t svl_bytes = DNBArchMachARM64::GetSMEMaxSVL(); 2485 g_sme_registers.push_back( 2486 {DNBArchMachARM64::e_regSetSME, sme_svcr, "svcr", NULL, Uint, Hex, 8, 2487 SME_OFFSET(svcr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2488 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}); 2489 g_sme_registers.push_back( 2490 {DNBArchMachARM64::e_regSetSME, sme_tpidr2, "tpidr2", NULL, Uint, Hex, 2491 8, SME_OFFSET(tpidr2), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2492 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}); 2493 g_sme_registers.push_back( 2494 {DNBArchMachARM64::e_regSetSME, sme_svl_b, "svl", NULL, Uint, Hex, 2, 2495 SME_OFFSET(svl_b), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2496 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}); 2497 uint32_t za_max_size = svl_bytes * svl_bytes; 2498 g_sme_registers.push_back({DNBArchMachARM64::e_regSetSME, sme_za, "za", 2499 NULL, Vector, VectorOfUInt8, za_max_size, 2500 SME_OFFSET(za), INVALID_NUB_REGNUM, 2501 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2502 INVALID_NUB_REGNUM, NULL, NULL}); 2503 } 2504 if (DNBArchMachARM64::CPUHasSME2()) { 2505 g_sme_registers.push_back({DNBArchMachARM64::e_regSetSME, sme_zt0, "zt0", 2506 NULL, Vector, VectorOfUInt8, 64, SME_OFFSET(zt0), 2507 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, 2508 INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, 2509 NULL}); 2510 } 2511} 2512 2513static std::once_flag g_sme_once; 2514DNBRegisterInfo * 2515DNBArchMachARM64::get_sme_registerinfo(size_t &num_sme_registers) { 2516 std::call_once(g_sme_once, []() { initialize_sme_registers(); }); 2517 num_sme_registers = g_sme_registers.size(); 2518 if (num_sme_registers > 0) 2519 return g_sme_registers.data(); 2520 else 2521 return nullptr; 2522} 2523 2524static std::vector<DNBRegisterSetInfo> g_reg_sets; 2525void DNBArchMachARM64::initialize_reg_sets() { 2526 nub_size_t num_all_registers = DNBArchMachARM64::k_num_gpr_registers + 2527 DNBArchMachARM64::k_num_exc_registers; 2528 size_t num_vfp_registers = 0; 2529 DNBRegisterInfo *vfp_reginfos = 2530 DNBArchMachARM64::get_vfp_registerinfo(num_vfp_registers); 2531 size_t num_sve_registers = 0; 2532 DNBRegisterInfo *sve_reginfos = 2533 DNBArchMachARM64::get_sve_registerinfo(num_sve_registers); 2534 size_t num_sme_registers = 0; 2535 DNBRegisterInfo *sme_reginfos = 2536 DNBArchMachARM64::get_sme_registerinfo(num_sme_registers); 2537 num_all_registers += 2538 num_vfp_registers + num_sve_registers + num_sme_registers; 2539 g_reg_sets.push_back({"ARM64 Registers", NULL, num_all_registers}); 2540 g_reg_sets.push_back({"General Purpose Registers", 2541 DNBArchMachARM64::g_gpr_registers, 2542 DNBArchMachARM64::k_num_gpr_registers}); 2543 g_reg_sets.push_back( 2544 {"Floating Point Registers", vfp_reginfos, num_vfp_registers}); 2545 g_reg_sets.push_back({"Exception State Registers", 2546 DNBArchMachARM64::g_exc_registers, 2547 DNBArchMachARM64::k_num_exc_registers}); 2548 if (DNBArchMachARM64::CPUHasSME()) { 2549 g_reg_sets.push_back({"Scalable Vector Extension Registers", sve_reginfos, 2550 num_sve_registers}); 2551 g_reg_sets.push_back({"Scalable Matrix Extension Registers", sme_reginfos, 2552 num_sme_registers}); 2553 } 2554} 2555 2556static std::once_flag g_initialize_register_set_info; 2557const DNBRegisterSetInfo * 2558DNBArchMachARM64::GetRegisterSetInfo(nub_size_t *num_reg_sets) { 2559 std::call_once(g_initialize_register_set_info, 2560 []() { initialize_reg_sets(); }); 2561 *num_reg_sets = g_reg_sets.size(); 2562 return g_reg_sets.data(); 2563} 2564 2565bool DNBArchMachARM64::FixGenericRegisterNumber(uint32_t &set, uint32_t &reg) { 2566 if (set == REGISTER_SET_GENERIC) { 2567 switch (reg) { 2568 case GENERIC_REGNUM_PC: // Program Counter 2569 set = e_regSetGPR; 2570 reg = gpr_pc; 2571 break; 2572 2573 case GENERIC_REGNUM_SP: // Stack Pointer 2574 set = e_regSetGPR; 2575 reg = gpr_sp; 2576 break; 2577 2578 case GENERIC_REGNUM_FP: // Frame Pointer 2579 set = e_regSetGPR; 2580 reg = gpr_fp; 2581 break; 2582 2583 case GENERIC_REGNUM_RA: // Return Address 2584 set = e_regSetGPR; 2585 reg = gpr_lr; 2586 break; 2587 2588 case GENERIC_REGNUM_FLAGS: // Processor flags register 2589 set = e_regSetGPR; 2590 reg = gpr_cpsr; 2591 break; 2592 2593 case GENERIC_REGNUM_ARG1: 2594 case GENERIC_REGNUM_ARG2: 2595 case GENERIC_REGNUM_ARG3: 2596 case GENERIC_REGNUM_ARG4: 2597 case GENERIC_REGNUM_ARG5: 2598 case GENERIC_REGNUM_ARG6: 2599 set = e_regSetGPR; 2600 reg = gpr_x0 + reg - GENERIC_REGNUM_ARG1; 2601 break; 2602 2603 default: 2604 return false; 2605 } 2606 } 2607 return true; 2608} 2609bool DNBArchMachARM64::GetRegisterValue(uint32_t set, uint32_t reg, 2610 DNBRegisterValue *value) { 2611 if (!FixGenericRegisterNumber(set, reg)) 2612 return false; 2613 2614 if (GetRegisterState(set, false) != KERN_SUCCESS) 2615 return false; 2616 2617 const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); 2618 if (regInfo) { 2619 uint16_t max_svl_bytes = GetSMEMaxSVL(); 2620 value->info = *regInfo; 2621 switch (set) { 2622 case e_regSetGPR: 2623 if (reg <= gpr_pc) { 2624 switch (reg) { 2625#if defined(DEBUGSERVER_IS_ARM64E) 2626 case gpr_pc: 2627 value->value.uint64 = DNBFixAddress( 2628 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc)); 2629 break; 2630 case gpr_lr: 2631 value->value.uint64 = arm_thread_state64_get_lr(m_state.context.gpr); 2632 break; 2633 case gpr_sp: 2634 value->value.uint64 = DNBFixAddress( 2635 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_sp)); 2636 break; 2637 case gpr_fp: 2638 value->value.uint64 = DNBFixAddress( 2639 reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_fp)); 2640 break; 2641#else 2642 case gpr_pc: 2643 value->value.uint64 = DNBFixAddress(m_state.context.gpr.__pc); 2644 break; 2645 case gpr_lr: 2646 value->value.uint64 = DNBFixAddress(m_state.context.gpr.__lr); 2647 break; 2648 case gpr_sp: 2649 value->value.uint64 = DNBFixAddress(m_state.context.gpr.__sp); 2650 break; 2651 case gpr_fp: 2652 value->value.uint64 = DNBFixAddress(m_state.context.gpr.__fp); 2653 break; 2654#endif 2655 default: 2656 value->value.uint64 = m_state.context.gpr.__x[reg]; 2657 } 2658 return true; 2659 } else if (reg == gpr_cpsr) { 2660 value->value.uint32 = m_state.context.gpr.__cpsr; 2661 return true; 2662 } 2663 break; 2664 2665 case e_regSetVFP: 2666 2667 if (reg >= vfp_v0 && reg <= vfp_v31) { 2668#if defined(__arm64__) || defined(__aarch64__) 2669 memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_v0], 2670 16); 2671#else 2672 memcpy(&value->value.v_uint8, 2673 ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16), 2674 16); 2675#endif 2676 return true; 2677 } else if (reg == vfp_fpsr) { 2678#if defined(__arm64__) || defined(__aarch64__) 2679 memcpy(&value->value.uint32, &m_state.context.vfp.__fpsr, 4); 2680#else 2681 memcpy(&value->value.uint32, 2682 ((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 0, 4); 2683#endif 2684 return true; 2685 } else if (reg == vfp_fpcr) { 2686#if defined(__arm64__) || defined(__aarch64__) 2687 memcpy(&value->value.uint32, &m_state.context.vfp.__fpcr, 4); 2688#else 2689 memcpy(&value->value.uint32, 2690 ((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 4, 4); 2691#endif 2692 return true; 2693 } else if (reg >= vfp_s0 && reg <= vfp_s31) { 2694#if defined(__arm64__) || defined(__aarch64__) 2695 memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_s0], 2696 4); 2697#else 2698 memcpy(&value->value.v_uint8, 2699 ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16), 2700 4); 2701#endif 2702 return true; 2703 } else if (reg >= vfp_d0 && reg <= vfp_d31) { 2704#if defined(__arm64__) || defined(__aarch64__) 2705 memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_d0], 2706 8); 2707#else 2708 memcpy(&value->value.v_uint8, 2709 ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16), 2710 8); 2711#endif 2712 return true; 2713 } 2714 break; 2715 2716 case e_regSetSVE: 2717 if (GetRegisterState(e_regSetSVE, false) != KERN_SUCCESS) 2718 return false; 2719 2720 if (reg >= sve_z0 && reg <= sve_z31) { 2721 memset(&value->value.v_uint8, 0, max_svl_bytes); 2722 memcpy(&value->value.v_uint8, &m_state.context.sve.z[reg - sve_z0], 2723 max_svl_bytes); 2724 return true; 2725 } else if (reg >= sve_p0 && reg <= sve_p15) { 2726 memset(&value->value.v_uint8, 0, max_svl_bytes / 8); 2727 memcpy(&value->value.v_uint8, &m_state.context.sve.p[reg - sve_p0], 2728 max_svl_bytes / 8); 2729 return true; 2730 } 2731 break; 2732 2733 case e_regSetSME: 2734 if (GetRegisterState(e_regSetSME, false) != KERN_SUCCESS) 2735 return false; 2736 2737 if (reg == sme_svcr) { 2738 value->value.uint64 = m_state.context.sme.svcr; 2739 return true; 2740 } else if (reg == sme_tpidr2) { 2741 value->value.uint64 = m_state.context.sme.tpidr2; 2742 return true; 2743 } else if (reg == sme_svl_b) { 2744 value->value.uint64 = m_state.context.sme.svl_b; 2745 return true; 2746 } else if (reg == sme_za) { 2747 memcpy(&value->value.v_uint8, m_state.context.sme.za.data(), 2748 max_svl_bytes * max_svl_bytes); 2749 return true; 2750 } else if (reg == sme_zt0) { 2751 memcpy(&value->value.v_uint8, &m_state.context.sme.zt0, 64); 2752 return true; 2753 } 2754 break; 2755 2756 case e_regSetEXC: 2757 if (reg == exc_far) { 2758 value->value.uint64 = m_state.context.exc.__far; 2759 return true; 2760 } else if (reg == exc_esr) { 2761 value->value.uint32 = m_state.context.exc.__esr; 2762 return true; 2763 } else if (reg == exc_exception) { 2764 value->value.uint32 = m_state.context.exc.__exception; 2765 return true; 2766 } 2767 break; 2768 } 2769 } 2770 return false; 2771} 2772 2773bool DNBArchMachARM64::SetRegisterValue(uint32_t set, uint32_t reg, 2774 const DNBRegisterValue *value) { 2775 if (!FixGenericRegisterNumber(set, reg)) 2776 return false; 2777 2778 if (GetRegisterState(set, false) != KERN_SUCCESS) 2779 return false; 2780 2781 bool success = false; 2782 const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); 2783 if (regInfo) { 2784 switch (set) { 2785 case e_regSetGPR: 2786 if (reg <= gpr_pc) { 2787#if defined(__LP64__) 2788 uint64_t signed_value = value->value.uint64; 2789#if __has_feature(ptrauth_calls) 2790 // The incoming value could be garbage. Strip it to avoid 2791 // trapping when it gets resigned in the thread state. 2792 signed_value = (uint64_t) ptrauth_strip((void*) signed_value, ptrauth_key_function_pointer); 2793 signed_value = (uint64_t) ptrauth_sign_unauthenticated((void*) signed_value, ptrauth_key_function_pointer, 0); 2794#endif 2795 if (reg == gpr_pc) 2796 arm_thread_state64_set_pc_fptr (m_state.context.gpr, (void*) signed_value); 2797 else if (reg == gpr_lr) 2798 arm_thread_state64_set_lr_fptr (m_state.context.gpr, (void*) signed_value); 2799 else if (reg == gpr_sp) 2800 arm_thread_state64_set_sp (m_state.context.gpr, value->value.uint64); 2801 else if (reg == gpr_fp) 2802 arm_thread_state64_set_fp (m_state.context.gpr, value->value.uint64); 2803 else 2804 m_state.context.gpr.__x[reg] = value->value.uint64; 2805#else 2806 m_state.context.gpr.__x[reg] = value->value.uint64; 2807#endif 2808 success = true; 2809 } else if (reg == gpr_cpsr) { 2810 m_state.context.gpr.__cpsr = value->value.uint32; 2811 success = true; 2812 } 2813 break; 2814 2815 case e_regSetVFP: 2816 if (reg >= vfp_v0 && reg <= vfp_v31) { 2817#if defined(__arm64__) || defined(__aarch64__) 2818 memcpy(&m_state.context.vfp.__v[reg - vfp_v0], &value->value.v_uint8, 2819 16); 2820#else 2821 memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16), 2822 &value->value.v_uint8, 16); 2823#endif 2824 success = true; 2825 } else if (reg == vfp_fpsr) { 2826#if defined(__arm64__) || defined(__aarch64__) 2827 memcpy(&m_state.context.vfp.__fpsr, &value->value.uint32, 4); 2828#else 2829 memcpy(((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 0, 2830 &value->value.uint32, 4); 2831#endif 2832 success = true; 2833 } else if (reg == vfp_fpcr) { 2834#if defined(__arm64__) || defined(__aarch64__) 2835 memcpy(&m_state.context.vfp.__fpcr, &value->value.uint32, 4); 2836#else 2837 memcpy(((uint8_t *)m_state.context.vfp.opaque) + (32 * 16) + 4, 2838 &value->value.uint32, 4); 2839#endif 2840 success = true; 2841 } else if (reg >= vfp_s0 && reg <= vfp_s31) { 2842#if defined(__arm64__) || defined(__aarch64__) 2843 memcpy(&m_state.context.vfp.__v[reg - vfp_s0], &value->value.v_uint8, 2844 4); 2845#else 2846 memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16), 2847 &value->value.v_uint8, 4); 2848#endif 2849 success = true; 2850 } else if (reg >= vfp_d0 && reg <= vfp_d31) { 2851#if defined(__arm64__) || defined(__aarch64__) 2852 memcpy(&m_state.context.vfp.__v[reg - vfp_d0], &value->value.v_uint8, 2853 8); 2854#else 2855 memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16), 2856 &value->value.v_uint8, 8); 2857#endif 2858 success = true; 2859 } 2860 break; 2861 2862 case e_regSetSVE: 2863 if (reg >= sve_z0 && reg <= sve_z31) { 2864 uint16_t max_svl_bytes = GetSMEMaxSVL(); 2865 memcpy(&m_state.context.sve.z[reg - sve_z0], &value->value.v_uint8, 2866 max_svl_bytes); 2867 success = true; 2868 } 2869 if (reg >= sve_p0 && reg <= sve_p15) { 2870 uint16_t max_svl_bytes = GetSMEMaxSVL(); 2871 memcpy(&m_state.context.sve.p[reg - sve_p0], &value->value.v_uint8, 2872 max_svl_bytes / 8); 2873 success = true; 2874 } 2875 break; 2876 2877 case e_regSetSME: 2878 // Cannot change ARM_SME_STATE registers with thread_set_state 2879 if (reg == sme_svcr || reg == sme_tpidr2 || reg == sme_svl_b) 2880 return false; 2881 if (reg == sme_za) { 2882 uint16_t max_svl_bytes = GetSMEMaxSVL(); 2883 memcpy(m_state.context.sme.za.data(), &value->value.v_uint8, 2884 max_svl_bytes * max_svl_bytes); 2885 success = true; 2886 } 2887 if (reg == sme_zt0) { 2888 memcpy(&m_state.context.sme.zt0, &value->value.v_uint8, 64); 2889 success = true; 2890 } 2891 break; 2892 2893 case e_regSetEXC: 2894 if (reg == exc_far) { 2895 m_state.context.exc.__far = value->value.uint64; 2896 success = true; 2897 } else if (reg == exc_esr) { 2898 m_state.context.exc.__esr = value->value.uint32; 2899 success = true; 2900 } else if (reg == exc_exception) { 2901 m_state.context.exc.__exception = value->value.uint32; 2902 success = true; 2903 } 2904 break; 2905 } 2906 } 2907 if (success) 2908 return SetRegisterState(set) == KERN_SUCCESS; 2909 return false; 2910} 2911 2912kern_return_t DNBArchMachARM64::GetRegisterState(int set, bool force) { 2913 switch (set) { 2914 case e_regSetALL: { 2915 kern_return_t retval = GetGPRState(force) | GetVFPState(force) | 2916 GetEXCState(force) | GetDBGState(force); 2917 // If the processor is not in Streaming SVE Mode currently, these 2918 // two will fail to read. Don't return that as an error, it will 2919 // be the most common case. 2920 if (CPUHasSME()) { 2921 GetSVEState(force); 2922 GetSMEState(force); 2923 } 2924 return retval; 2925 } 2926 case e_regSetGPR: 2927 return GetGPRState(force); 2928 case e_regSetVFP: 2929 return GetVFPState(force); 2930 case e_regSetSVE: 2931 return GetSVEState(force); 2932 case e_regSetSME: 2933 return GetSMEState(force); 2934 case e_regSetEXC: 2935 return GetEXCState(force); 2936 case e_regSetDBG: 2937 return GetDBGState(force); 2938 default: 2939 break; 2940 } 2941 return KERN_INVALID_ARGUMENT; 2942} 2943 2944kern_return_t DNBArchMachARM64::SetRegisterState(int set) { 2945 // Make sure we have a valid context to set. 2946 kern_return_t err = GetRegisterState(set, false); 2947 if (err != KERN_SUCCESS) 2948 return err; 2949 2950 switch (set) { 2951 case e_regSetALL: { 2952 kern_return_t ret = 2953 SetGPRState() | SetVFPState() | SetEXCState() | SetDBGState(false); 2954 if (CPUHasSME()) { 2955 SetSVEState(); 2956 SetSMEState(); 2957 } 2958 return ret; 2959 } 2960 case e_regSetGPR: 2961 return SetGPRState(); 2962 case e_regSetVFP: 2963 return SetVFPState(); 2964 case e_regSetSVE: 2965 return SetSVEState(); 2966 case e_regSetSME: 2967 return SetSMEState(); 2968 case e_regSetEXC: 2969 return SetEXCState(); 2970 case e_regSetDBG: 2971 return SetDBGState(false); 2972 default: 2973 break; 2974 } 2975 return KERN_INVALID_ARGUMENT; 2976} 2977 2978bool DNBArchMachARM64::RegisterSetStateIsValid(int set) const { 2979 return m_state.RegsAreValid(set); 2980} 2981 2982nub_size_t DNBArchMachARM64::GetRegisterContext(void *buf, nub_size_t buf_len) { 2983 nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) + 2984 sizeof(m_state.context.exc); 2985 const bool cpu_has_sme = CPUHasSME(); 2986 if (cpu_has_sme) { 2987 size += sizeof(m_state.context.sve); 2988 // ZA register is in a std::vector<uint8_t> so we need to add 2989 // the sizes of the SME manually. 2990 size += ARM_SME_STATE_COUNT * sizeof(uint32_t); 2991 size += m_state.context.sme.za.size(); 2992 size += ARM_SME2_STATE_COUNT * sizeof(uint32_t); 2993 } 2994 2995 if (buf && buf_len) { 2996 if (size > buf_len) 2997 size = buf_len; 2998 2999 bool force = false; 3000 if (GetGPRState(force) | GetVFPState(force) | GetEXCState(force)) 3001 return 0; 3002 // Don't error out if SME/SVE fail to read. These can only be read 3003 // when the process is in Streaming SVE Mode, so the failure to read 3004 // them will be common. 3005 if (cpu_has_sme) { 3006 GetSVEState(force); 3007 GetSMEState(force); 3008 } 3009 3010 // Copy each struct individually to avoid any padding that might be between 3011 // the structs in m_state.context 3012 uint8_t *p = (uint8_t *)buf; 3013 ::memcpy(p, &m_state.context.gpr, sizeof(m_state.context.gpr)); 3014 p += sizeof(m_state.context.gpr); 3015 ::memcpy(p, &m_state.context.vfp, sizeof(m_state.context.vfp)); 3016 p += sizeof(m_state.context.vfp); 3017 if (cpu_has_sme) { 3018 ::memcpy(p, &m_state.context.sve, sizeof(m_state.context.sve)); 3019 p += sizeof(m_state.context.sve); 3020 3021 memcpy(p, &m_state.context.sme.svcr, 3022 ARM_SME_STATE_COUNT * sizeof(uint32_t)); 3023 p += ARM_SME_STATE_COUNT * sizeof(uint32_t); 3024 memcpy(p, m_state.context.sme.za.data(), m_state.context.sme.za.size()); 3025 p += m_state.context.sme.za.size(); 3026 if (CPUHasSME2()) { 3027 memcpy(p, &m_state.context.sme.zt0, 3028 ARM_SME2_STATE_COUNT * sizeof(uint32_t)); 3029 p += ARM_SME2_STATE_COUNT * sizeof(uint32_t); 3030 } 3031 } 3032 ::memcpy(p, &m_state.context.exc, sizeof(m_state.context.exc)); 3033 p += sizeof(m_state.context.exc); 3034 3035 size_t bytes_written = p - (uint8_t *)buf; 3036 UNUSED_IF_ASSERT_DISABLED(bytes_written); 3037 assert(bytes_written == size); 3038 } 3039 DNBLogThreadedIf( 3040 LOG_THREAD, 3041 "DNBArchMachARM64::GetRegisterContext (buf = %p, len = %zu) => %zu", buf, 3042 buf_len, size); 3043 // Return the size of the register context even if NULL was passed in 3044 return size; 3045} 3046 3047nub_size_t DNBArchMachARM64::SetRegisterContext(const void *buf, 3048 nub_size_t buf_len) { 3049 nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) + 3050 sizeof(m_state.context.exc); 3051 if (CPUHasSME()) { 3052 // m_state.context.za is three status registers, then a std::vector<uint8_t> 3053 // for ZA, then zt0, so the size of the data is not statically knowable. 3054 nub_size_t sme_size = ARM_SME_STATE_COUNT * sizeof(uint32_t); 3055 sme_size += m_state.context.sme.za.size(); 3056 sme_size += ARM_SME2_STATE_COUNT * sizeof(uint32_t); 3057 3058 size += sizeof(m_state.context.sve) + sme_size; 3059 } 3060 3061 if (buf == NULL || buf_len == 0) 3062 size = 0; 3063 3064 if (size) { 3065 if (size > buf_len) 3066 size = buf_len; 3067 3068 // Copy each struct individually to avoid any padding that might be between 3069 // the structs in m_state.context 3070 uint8_t *p = const_cast<uint8_t*>(reinterpret_cast<const uint8_t *>(buf)); 3071 ::memcpy(&m_state.context.gpr, p, sizeof(m_state.context.gpr)); 3072 p += sizeof(m_state.context.gpr); 3073 ::memcpy(&m_state.context.vfp, p, sizeof(m_state.context.vfp)); 3074 p += sizeof(m_state.context.vfp); 3075 if (CPUHasSME()) { 3076 memcpy(&m_state.context.sve, p, sizeof(m_state.context.sve)); 3077 p += sizeof(m_state.context.sve); 3078 memcpy(&m_state.context.sme.svcr, p, 3079 ARM_SME_STATE_COUNT * sizeof(uint32_t)); 3080 p += ARM_SME_STATE_COUNT * sizeof(uint32_t); 3081 memcpy(m_state.context.sme.za.data(), p, m_state.context.sme.za.size()); 3082 p += m_state.context.sme.za.size(); 3083 if (CPUHasSME2()) { 3084 memcpy(&m_state.context.sme.zt0, p, 3085 ARM_SME2_STATE_COUNT * sizeof(uint32_t)); 3086 p += ARM_SME2_STATE_COUNT * sizeof(uint32_t); 3087 } 3088 } 3089 ::memcpy(&m_state.context.exc, p, sizeof(m_state.context.exc)); 3090 p += sizeof(m_state.context.exc); 3091 3092 size_t bytes_written = p - reinterpret_cast<const uint8_t *>(buf); 3093 UNUSED_IF_ASSERT_DISABLED(bytes_written); 3094 assert(bytes_written == size); 3095 SetGPRState(); 3096 SetVFPState(); 3097 if (CPUHasSME()) { 3098 SetSVEState(); 3099 SetSMEState(); 3100 } 3101 SetEXCState(); 3102 } 3103 DNBLogThreadedIf( 3104 LOG_THREAD, 3105 "DNBArchMachARM64::SetRegisterContext (buf = %p, len = %zu) => %zu", buf, 3106 buf_len, size); 3107 return size; 3108} 3109 3110uint32_t DNBArchMachARM64::SaveRegisterState() { 3111 kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); 3112 DNBLogThreadedIf( 3113 LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u " 3114 "(SetGPRState() for stop_count = %u)", 3115 m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); 3116 3117 // Always re-read the registers because above we call thread_abort_safely(); 3118 bool force = true; 3119 3120 if ((kret = GetGPRState(force)) != KERN_SUCCESS) { 3121 DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () " 3122 "error: GPR regs failed to read: %u ", 3123 kret); 3124 } else if ((kret = GetVFPState(force)) != KERN_SUCCESS) { 3125 DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () " 3126 "error: %s regs failed to read: %u", 3127 "VFP", kret); 3128 } else { 3129 if (CPUHasSME()) { 3130 // These can fail when processor is not in streaming SVE mode, 3131 // and that failure should be ignored. 3132 GetSVEState(force); 3133 GetSMEState(force); 3134 } 3135 const uint32_t save_id = GetNextRegisterStateSaveID(); 3136 m_saved_register_states[save_id] = m_state.context; 3137 return save_id; 3138 } 3139 return UINT32_MAX; 3140} 3141 3142bool DNBArchMachARM64::RestoreRegisterState(uint32_t save_id) { 3143 SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); 3144 if (pos != m_saved_register_states.end()) { 3145 m_state.context.gpr = pos->second.gpr; 3146 m_state.context.vfp = pos->second.vfp; 3147 kern_return_t kret; 3148 bool success = true; 3149 if ((kret = SetGPRState()) != KERN_SUCCESS) { 3150 DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState " 3151 "(save_id = %u) error: GPR regs failed to " 3152 "write: %u", 3153 save_id, kret); 3154 success = false; 3155 } else if ((kret = SetVFPState()) != KERN_SUCCESS) { 3156 DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState " 3157 "(save_id = %u) error: %s regs failed to " 3158 "write: %u", 3159 save_id, "VFP", kret); 3160 success = false; 3161 } 3162 if (CPUHasSME()) { 3163 // These can fail when processor is not in streaming SVE mode, 3164 // and that failure should be ignored. 3165 SetSVEState(); 3166 SetSMEState(); 3167 } 3168 m_saved_register_states.erase(pos); 3169 return success; 3170 } 3171 return false; 3172} 3173 3174#endif // #if defined (ARM_THREAD_STATE64_COUNT) 3175#endif // #if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)