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