| 1 | //===-- RegisterContextDarwin_arm64.cpp -----------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "RegisterContextDarwin_arm64.h" |
| 10 | #include "RegisterContextDarwinConstants.h" |
| 11 | |
| 12 | #include "lldb/Target/Process.h" |
| 13 | #include "lldb/Target/Thread.h" |
| 14 | #include "lldb/Utility/DataBufferHeap.h" |
| 15 | #include "lldb/Utility/DataExtractor.h" |
| 16 | #include "lldb/Utility/Endian.h" |
| 17 | #include "lldb/Utility/Log.h" |
| 18 | #include "lldb/Utility/RegisterValue.h" |
| 19 | #include "lldb/Utility/Scalar.h" |
| 20 | #include "llvm/ADT/STLExtras.h" |
| 21 | #include "llvm/Support/Compiler.h" |
| 22 | |
| 23 | #include "Plugins/Process/Utility/InstructionUtils.h" |
| 24 | |
| 25 | #include <memory> |
| 26 | |
| 27 | #if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) |
| 28 | #include <sys/types.h> |
| 29 | #include <sys/sysctl.h> |
| 30 | #endif |
| 31 | |
| 32 | #include "Utility/ARM64_DWARF_Registers.h" |
| 33 | |
| 34 | using namespace lldb; |
| 35 | using namespace lldb_private; |
| 36 | |
| 37 | #define GPR_OFFSET(idx) ((idx)*8) |
| 38 | #define GPR_OFFSET_NAME(reg) \ |
| 39 | (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::GPR, reg)) |
| 40 | |
| 41 | #define FPU_OFFSET(idx) ((idx)*16 + sizeof(RegisterContextDarwin_arm64::GPR)) |
| 42 | #define FPU_OFFSET_NAME(reg) \ |
| 43 | (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::FPU, reg)) |
| 44 | |
| 45 | #define EXC_OFFSET_NAME(reg) \ |
| 46 | (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::EXC, reg) + \ |
| 47 | sizeof(RegisterContextDarwin_arm64::GPR) + \ |
| 48 | sizeof(RegisterContextDarwin_arm64::FPU)) |
| 49 | #define DBG_OFFSET_NAME(reg) \ |
| 50 | (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::DBG, reg) + \ |
| 51 | sizeof(RegisterContextDarwin_arm64::GPR) + \ |
| 52 | sizeof(RegisterContextDarwin_arm64::FPU) + \ |
| 53 | sizeof(RegisterContextDarwin_arm64::EXC)) |
| 54 | |
| 55 | #define DEFINE_DBG(reg, i) \ |
| 56 | #reg, NULL, \ |
| 57 | sizeof(((RegisterContextDarwin_arm64::DBG *) NULL)->reg[i]), \ |
| 58 | DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, \ |
| 59 | {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ |
| 60 | LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ |
| 61 | LLDB_INVALID_REGNUM }, \ |
| 62 | NULL, NULL, NULL |
| 63 | #define REG_CONTEXT_SIZE \ |
| 64 | (sizeof(RegisterContextDarwin_arm64::GPR) + \ |
| 65 | sizeof(RegisterContextDarwin_arm64::FPU) + \ |
| 66 | sizeof(RegisterContextDarwin_arm64::EXC)) |
| 67 | |
| 68 | // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. |
| 69 | #define DECLARE_REGISTER_INFOS_ARM64_STRUCT |
| 70 | #include "RegisterInfos_arm64.h" |
| 71 | #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT |
| 72 | |
| 73 | // General purpose registers |
| 74 | static uint32_t g_gpr_regnums[] = { |
| 75 | gpr_x0, gpr_x1, gpr_x2, gpr_x3, gpr_x4, gpr_x5, gpr_x6, |
| 76 | gpr_x7, gpr_x8, gpr_x9, gpr_x10, gpr_x11, gpr_x12, gpr_x13, |
| 77 | gpr_x14, gpr_x15, gpr_x16, gpr_x17, gpr_x18, gpr_x19, gpr_x20, |
| 78 | gpr_x21, gpr_x22, gpr_x23, gpr_x24, gpr_x25, gpr_x26, gpr_x27, |
| 79 | gpr_x28, gpr_fp, gpr_lr, gpr_sp, gpr_pc, gpr_cpsr}; |
| 80 | |
| 81 | // Floating point registers |
| 82 | static uint32_t g_fpu_regnums[] = { |
| 83 | fpu_v0, fpu_v1, fpu_v2, fpu_v3, fpu_v4, fpu_v5, fpu_v6, |
| 84 | fpu_v7, fpu_v8, fpu_v9, fpu_v10, fpu_v11, fpu_v12, fpu_v13, |
| 85 | fpu_v14, fpu_v15, fpu_v16, fpu_v17, fpu_v18, fpu_v19, fpu_v20, |
| 86 | fpu_v21, fpu_v22, fpu_v23, fpu_v24, fpu_v25, fpu_v26, fpu_v27, |
| 87 | fpu_v28, fpu_v29, fpu_v30, fpu_v31, fpu_fpsr, fpu_fpcr}; |
| 88 | |
| 89 | // Exception registers |
| 90 | |
| 91 | static uint32_t g_exc_regnums[] = {exc_far, exc_esr, exc_exception}; |
| 92 | |
| 93 | static size_t k_num_register_infos = std::size(g_register_infos_arm64_le); |
| 94 | |
| 95 | RegisterContextDarwin_arm64::RegisterContextDarwin_arm64( |
| 96 | Thread &thread, uint32_t concrete_frame_idx) |
| 97 | : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc(), dbg() { |
| 98 | uint32_t i; |
| 99 | for (i = 0; i < kNumErrors; i++) { |
| 100 | gpr_errs[i] = -1; |
| 101 | fpu_errs[i] = -1; |
| 102 | exc_errs[i] = -1; |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64() = default; |
| 107 | |
| 108 | void RegisterContextDarwin_arm64::InvalidateAllRegisters() { |
| 109 | InvalidateAllRegisterStates(); |
| 110 | } |
| 111 | |
| 112 | size_t RegisterContextDarwin_arm64::GetRegisterCount() { |
| 113 | assert(k_num_register_infos == k_num_registers); |
| 114 | return k_num_registers; |
| 115 | } |
| 116 | |
| 117 | const RegisterInfo * |
| 118 | RegisterContextDarwin_arm64::GetRegisterInfoAtIndex(size_t reg) { |
| 119 | assert(k_num_register_infos == k_num_registers); |
| 120 | if (reg < k_num_registers) |
| 121 | return &g_register_infos_arm64_le[reg]; |
| 122 | return nullptr; |
| 123 | } |
| 124 | |
| 125 | size_t RegisterContextDarwin_arm64::GetRegisterInfosCount() { |
| 126 | return k_num_register_infos; |
| 127 | } |
| 128 | |
| 129 | const RegisterInfo *RegisterContextDarwin_arm64::GetRegisterInfos() { |
| 130 | return g_register_infos_arm64_le; |
| 131 | } |
| 132 | |
| 133 | // Number of registers in each register set |
| 134 | const size_t k_num_gpr_registers = std::size(g_gpr_regnums); |
| 135 | const size_t k_num_fpu_registers = std::size(g_fpu_regnums); |
| 136 | const size_t k_num_exc_registers = std::size(g_exc_regnums); |
| 137 | |
| 138 | // Register set definitions. The first definitions at register set index of |
| 139 | // zero is for all registers, followed by other registers sets. The register |
| 140 | // information for the all register set need not be filled in. |
| 141 | static const RegisterSet g_reg_sets[] = { |
| 142 | { |
| 143 | .name: "General Purpose Registers" , .short_name: "gpr" , .num_registers: k_num_gpr_registers, .registers: g_gpr_regnums, |
| 144 | }, |
| 145 | {.name: "Floating Point Registers" , .short_name: "fpu" , .num_registers: k_num_fpu_registers, .registers: g_fpu_regnums}, |
| 146 | {.name: "Exception State Registers" , .short_name: "exc" , .num_registers: k_num_exc_registers, .registers: g_exc_regnums}}; |
| 147 | |
| 148 | const size_t k_num_regsets = std::size(g_reg_sets); |
| 149 | |
| 150 | size_t RegisterContextDarwin_arm64::GetRegisterSetCount() { |
| 151 | return k_num_regsets; |
| 152 | } |
| 153 | |
| 154 | const RegisterSet *RegisterContextDarwin_arm64::GetRegisterSet(size_t reg_set) { |
| 155 | if (reg_set < k_num_regsets) |
| 156 | return &g_reg_sets[reg_set]; |
| 157 | return nullptr; |
| 158 | } |
| 159 | |
| 160 | // Register information definitions for arm64 |
| 161 | int RegisterContextDarwin_arm64::GetSetForNativeRegNum(int reg) { |
| 162 | if (reg < fpu_v0) |
| 163 | return GPRRegSet; |
| 164 | else if (reg < exc_far) |
| 165 | return FPURegSet; |
| 166 | else if (reg < k_num_registers) |
| 167 | return EXCRegSet; |
| 168 | return -1; |
| 169 | } |
| 170 | |
| 171 | int RegisterContextDarwin_arm64::ReadGPR(bool force) { |
| 172 | int set = GPRRegSet; |
| 173 | if (force || !RegisterSetIsCached(set)) { |
| 174 | SetError(flavor: set, err_idx: Read, err: DoReadGPR(tid: GetThreadID(), flavor: set, gpr)); |
| 175 | } |
| 176 | return GetError(flavor: GPRRegSet, err_idx: Read); |
| 177 | } |
| 178 | |
| 179 | int RegisterContextDarwin_arm64::ReadFPU(bool force) { |
| 180 | int set = FPURegSet; |
| 181 | if (force || !RegisterSetIsCached(set)) { |
| 182 | SetError(flavor: set, err_idx: Read, err: DoReadFPU(tid: GetThreadID(), flavor: set, fpu)); |
| 183 | } |
| 184 | return GetError(flavor: FPURegSet, err_idx: Read); |
| 185 | } |
| 186 | |
| 187 | int RegisterContextDarwin_arm64::ReadEXC(bool force) { |
| 188 | int set = EXCRegSet; |
| 189 | if (force || !RegisterSetIsCached(set)) { |
| 190 | SetError(flavor: set, err_idx: Read, err: DoReadEXC(tid: GetThreadID(), flavor: set, exc)); |
| 191 | } |
| 192 | return GetError(flavor: EXCRegSet, err_idx: Read); |
| 193 | } |
| 194 | |
| 195 | int RegisterContextDarwin_arm64::ReadDBG(bool force) { |
| 196 | int set = DBGRegSet; |
| 197 | if (force || !RegisterSetIsCached(set)) { |
| 198 | SetError(flavor: set, err_idx: Read, err: DoReadDBG(tid: GetThreadID(), flavor: set, dbg)); |
| 199 | } |
| 200 | return GetError(flavor: DBGRegSet, err_idx: Read); |
| 201 | } |
| 202 | |
| 203 | int RegisterContextDarwin_arm64::WriteGPR() { |
| 204 | int set = GPRRegSet; |
| 205 | if (!RegisterSetIsCached(set)) { |
| 206 | SetError(flavor: set, err_idx: Write, err: -1); |
| 207 | return KERN_INVALID_ARGUMENT; |
| 208 | } |
| 209 | SetError(flavor: set, err_idx: Write, err: DoWriteGPR(tid: GetThreadID(), flavor: set, gpr)); |
| 210 | SetError(flavor: set, err_idx: Read, err: -1); |
| 211 | return GetError(flavor: GPRRegSet, err_idx: Write); |
| 212 | } |
| 213 | |
| 214 | int RegisterContextDarwin_arm64::WriteFPU() { |
| 215 | int set = FPURegSet; |
| 216 | if (!RegisterSetIsCached(set)) { |
| 217 | SetError(flavor: set, err_idx: Write, err: -1); |
| 218 | return KERN_INVALID_ARGUMENT; |
| 219 | } |
| 220 | SetError(flavor: set, err_idx: Write, err: DoWriteFPU(tid: GetThreadID(), flavor: set, fpu)); |
| 221 | SetError(flavor: set, err_idx: Read, err: -1); |
| 222 | return GetError(flavor: FPURegSet, err_idx: Write); |
| 223 | } |
| 224 | |
| 225 | int RegisterContextDarwin_arm64::WriteEXC() { |
| 226 | int set = EXCRegSet; |
| 227 | if (!RegisterSetIsCached(set)) { |
| 228 | SetError(flavor: set, err_idx: Write, err: -1); |
| 229 | return KERN_INVALID_ARGUMENT; |
| 230 | } |
| 231 | SetError(flavor: set, err_idx: Write, err: DoWriteEXC(tid: GetThreadID(), flavor: set, exc)); |
| 232 | SetError(flavor: set, err_idx: Read, err: -1); |
| 233 | return GetError(flavor: EXCRegSet, err_idx: Write); |
| 234 | } |
| 235 | |
| 236 | int RegisterContextDarwin_arm64::WriteDBG() { |
| 237 | int set = DBGRegSet; |
| 238 | if (!RegisterSetIsCached(set)) { |
| 239 | SetError(flavor: set, err_idx: Write, err: -1); |
| 240 | return KERN_INVALID_ARGUMENT; |
| 241 | } |
| 242 | SetError(flavor: set, err_idx: Write, err: DoWriteDBG(tid: GetThreadID(), flavor: set, dbg)); |
| 243 | SetError(flavor: set, err_idx: Read, err: -1); |
| 244 | return GetError(flavor: DBGRegSet, err_idx: Write); |
| 245 | } |
| 246 | |
| 247 | int RegisterContextDarwin_arm64::ReadRegisterSet(uint32_t set, bool force) { |
| 248 | switch (set) { |
| 249 | case GPRRegSet: |
| 250 | return ReadGPR(force); |
| 251 | case FPURegSet: |
| 252 | return ReadFPU(force); |
| 253 | case EXCRegSet: |
| 254 | return ReadEXC(force); |
| 255 | case DBGRegSet: |
| 256 | return ReadDBG(force); |
| 257 | default: |
| 258 | break; |
| 259 | } |
| 260 | return KERN_INVALID_ARGUMENT; |
| 261 | } |
| 262 | |
| 263 | int RegisterContextDarwin_arm64::WriteRegisterSet(uint32_t set) { |
| 264 | // Make sure we have a valid context to set. |
| 265 | if (RegisterSetIsCached(set)) { |
| 266 | switch (set) { |
| 267 | case GPRRegSet: |
| 268 | return WriteGPR(); |
| 269 | case FPURegSet: |
| 270 | return WriteFPU(); |
| 271 | case EXCRegSet: |
| 272 | return WriteEXC(); |
| 273 | case DBGRegSet: |
| 274 | return WriteDBG(); |
| 275 | default: |
| 276 | break; |
| 277 | } |
| 278 | } |
| 279 | return KERN_INVALID_ARGUMENT; |
| 280 | } |
| 281 | |
| 282 | void RegisterContextDarwin_arm64::LogDBGRegisters(Log *log, const DBG &dbg) { |
| 283 | if (log) { |
| 284 | for (uint32_t i = 0; i < 16; i++) |
| 285 | LLDB_LOGF(log, |
| 286 | "BVR%-2u/BCR%-2u = { 0x%8.8" PRIu64 ", 0x%8.8" PRIu64 |
| 287 | " } WVR%-2u/WCR%-2u " |
| 288 | "= { 0x%8.8" PRIu64 ", 0x%8.8" PRIu64 " }" , |
| 289 | i, i, dbg.bvr[i], dbg.bcr[i], i, i, dbg.wvr[i], dbg.wcr[i]); |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | bool RegisterContextDarwin_arm64::ReadRegister(const RegisterInfo *reg_info, |
| 294 | RegisterValue &value) { |
| 295 | const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; |
| 296 | int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum(reg); |
| 297 | |
| 298 | if (set == -1) |
| 299 | return false; |
| 300 | |
| 301 | if (ReadRegisterSet(set, force: false) != KERN_SUCCESS) |
| 302 | return false; |
| 303 | |
| 304 | switch (reg) { |
| 305 | case gpr_x0: |
| 306 | case gpr_x1: |
| 307 | case gpr_x2: |
| 308 | case gpr_x3: |
| 309 | case gpr_x4: |
| 310 | case gpr_x5: |
| 311 | case gpr_x6: |
| 312 | case gpr_x7: |
| 313 | case gpr_x8: |
| 314 | case gpr_x9: |
| 315 | case gpr_x10: |
| 316 | case gpr_x11: |
| 317 | case gpr_x12: |
| 318 | case gpr_x13: |
| 319 | case gpr_x14: |
| 320 | case gpr_x15: |
| 321 | case gpr_x16: |
| 322 | case gpr_x17: |
| 323 | case gpr_x18: |
| 324 | case gpr_x19: |
| 325 | case gpr_x20: |
| 326 | case gpr_x21: |
| 327 | case gpr_x22: |
| 328 | case gpr_x23: |
| 329 | case gpr_x24: |
| 330 | case gpr_x25: |
| 331 | case gpr_x26: |
| 332 | case gpr_x27: |
| 333 | case gpr_x28: |
| 334 | value.SetUInt64(uint: gpr.x[reg - gpr_x0]); |
| 335 | break; |
| 336 | case gpr_fp: |
| 337 | value.SetUInt64(uint: gpr.fp); |
| 338 | break; |
| 339 | case gpr_sp: |
| 340 | value.SetUInt64(uint: gpr.sp); |
| 341 | break; |
| 342 | case gpr_lr: |
| 343 | value.SetUInt64(uint: gpr.lr); |
| 344 | break; |
| 345 | case gpr_pc: |
| 346 | value.SetUInt64(uint: gpr.pc); |
| 347 | break; |
| 348 | case gpr_cpsr: |
| 349 | value.SetUInt64(uint: gpr.cpsr); |
| 350 | break; |
| 351 | |
| 352 | case gpr_w0: |
| 353 | case gpr_w1: |
| 354 | case gpr_w2: |
| 355 | case gpr_w3: |
| 356 | case gpr_w4: |
| 357 | case gpr_w5: |
| 358 | case gpr_w6: |
| 359 | case gpr_w7: |
| 360 | case gpr_w8: |
| 361 | case gpr_w9: |
| 362 | case gpr_w10: |
| 363 | case gpr_w11: |
| 364 | case gpr_w12: |
| 365 | case gpr_w13: |
| 366 | case gpr_w14: |
| 367 | case gpr_w15: |
| 368 | case gpr_w16: |
| 369 | case gpr_w17: |
| 370 | case gpr_w18: |
| 371 | case gpr_w19: |
| 372 | case gpr_w20: |
| 373 | case gpr_w21: |
| 374 | case gpr_w22: |
| 375 | case gpr_w23: |
| 376 | case gpr_w24: |
| 377 | case gpr_w25: |
| 378 | case gpr_w26: |
| 379 | case gpr_w27: |
| 380 | case gpr_w28: { |
| 381 | ProcessSP process_sp(m_thread.GetProcess()); |
| 382 | if (process_sp.get()) { |
| 383 | DataExtractor regdata(&gpr.x[reg - gpr_w0], 8, process_sp->GetByteOrder(), |
| 384 | process_sp->GetAddressByteSize()); |
| 385 | offset_t offset = 0; |
| 386 | uint64_t retval = regdata.GetMaxU64(offset_ptr: &offset, byte_size: 8); |
| 387 | uint32_t retval_lower32 = static_cast<uint32_t>(retval & 0xffffffff); |
| 388 | value.SetUInt32(uint: retval_lower32); |
| 389 | } |
| 390 | } break; |
| 391 | |
| 392 | case fpu_v0: |
| 393 | case fpu_v1: |
| 394 | case fpu_v2: |
| 395 | case fpu_v3: |
| 396 | case fpu_v4: |
| 397 | case fpu_v5: |
| 398 | case fpu_v6: |
| 399 | case fpu_v7: |
| 400 | case fpu_v8: |
| 401 | case fpu_v9: |
| 402 | case fpu_v10: |
| 403 | case fpu_v11: |
| 404 | case fpu_v12: |
| 405 | case fpu_v13: |
| 406 | case fpu_v14: |
| 407 | case fpu_v15: |
| 408 | case fpu_v16: |
| 409 | case fpu_v17: |
| 410 | case fpu_v18: |
| 411 | case fpu_v19: |
| 412 | case fpu_v20: |
| 413 | case fpu_v21: |
| 414 | case fpu_v22: |
| 415 | case fpu_v23: |
| 416 | case fpu_v24: |
| 417 | case fpu_v25: |
| 418 | case fpu_v26: |
| 419 | case fpu_v27: |
| 420 | case fpu_v28: |
| 421 | case fpu_v29: |
| 422 | case fpu_v30: |
| 423 | case fpu_v31: |
| 424 | value.SetBytes(bytes: fpu.v[reg - fpu_v0].bytes, length: reg_info->byte_size, |
| 425 | byte_order: endian::InlHostByteOrder()); |
| 426 | break; |
| 427 | |
| 428 | case fpu_s0: |
| 429 | case fpu_s1: |
| 430 | case fpu_s2: |
| 431 | case fpu_s3: |
| 432 | case fpu_s4: |
| 433 | case fpu_s5: |
| 434 | case fpu_s6: |
| 435 | case fpu_s7: |
| 436 | case fpu_s8: |
| 437 | case fpu_s9: |
| 438 | case fpu_s10: |
| 439 | case fpu_s11: |
| 440 | case fpu_s12: |
| 441 | case fpu_s13: |
| 442 | case fpu_s14: |
| 443 | case fpu_s15: |
| 444 | case fpu_s16: |
| 445 | case fpu_s17: |
| 446 | case fpu_s18: |
| 447 | case fpu_s19: |
| 448 | case fpu_s20: |
| 449 | case fpu_s21: |
| 450 | case fpu_s22: |
| 451 | case fpu_s23: |
| 452 | case fpu_s24: |
| 453 | case fpu_s25: |
| 454 | case fpu_s26: |
| 455 | case fpu_s27: |
| 456 | case fpu_s28: |
| 457 | case fpu_s29: |
| 458 | case fpu_s30: |
| 459 | case fpu_s31: { |
| 460 | ProcessSP process_sp(m_thread.GetProcess()); |
| 461 | if (process_sp.get()) { |
| 462 | DataExtractor regdata(&fpu.v[reg - fpu_s0], 4, process_sp->GetByteOrder(), |
| 463 | process_sp->GetAddressByteSize()); |
| 464 | offset_t offset = 0; |
| 465 | value.SetFloat(regdata.GetFloat(offset_ptr: &offset)); |
| 466 | } |
| 467 | } break; |
| 468 | |
| 469 | case fpu_d0: |
| 470 | case fpu_d1: |
| 471 | case fpu_d2: |
| 472 | case fpu_d3: |
| 473 | case fpu_d4: |
| 474 | case fpu_d5: |
| 475 | case fpu_d6: |
| 476 | case fpu_d7: |
| 477 | case fpu_d8: |
| 478 | case fpu_d9: |
| 479 | case fpu_d10: |
| 480 | case fpu_d11: |
| 481 | case fpu_d12: |
| 482 | case fpu_d13: |
| 483 | case fpu_d14: |
| 484 | case fpu_d15: |
| 485 | case fpu_d16: |
| 486 | case fpu_d17: |
| 487 | case fpu_d18: |
| 488 | case fpu_d19: |
| 489 | case fpu_d20: |
| 490 | case fpu_d21: |
| 491 | case fpu_d22: |
| 492 | case fpu_d23: |
| 493 | case fpu_d24: |
| 494 | case fpu_d25: |
| 495 | case fpu_d26: |
| 496 | case fpu_d27: |
| 497 | case fpu_d28: |
| 498 | case fpu_d29: |
| 499 | case fpu_d30: |
| 500 | case fpu_d31: { |
| 501 | ProcessSP process_sp(m_thread.GetProcess()); |
| 502 | if (process_sp.get()) { |
| 503 | DataExtractor regdata(&fpu.v[reg - fpu_d0], 8, process_sp->GetByteOrder(), |
| 504 | process_sp->GetAddressByteSize()); |
| 505 | offset_t offset = 0; |
| 506 | value.SetDouble(regdata.GetDouble(offset_ptr: &offset)); |
| 507 | } |
| 508 | } break; |
| 509 | |
| 510 | case fpu_fpsr: |
| 511 | value.SetUInt32(uint: fpu.fpsr); |
| 512 | break; |
| 513 | |
| 514 | case fpu_fpcr: |
| 515 | value.SetUInt32(uint: fpu.fpcr); |
| 516 | break; |
| 517 | |
| 518 | case exc_exception: |
| 519 | value.SetUInt32(uint: exc.exception); |
| 520 | break; |
| 521 | case exc_esr: |
| 522 | value.SetUInt32(uint: exc.esr); |
| 523 | break; |
| 524 | case exc_far: |
| 525 | value.SetUInt64(uint: exc.far); |
| 526 | break; |
| 527 | |
| 528 | default: |
| 529 | value.SetValueToInvalid(); |
| 530 | return false; |
| 531 | } |
| 532 | return true; |
| 533 | } |
| 534 | |
| 535 | bool RegisterContextDarwin_arm64::WriteRegister(const RegisterInfo *reg_info, |
| 536 | const RegisterValue &value) { |
| 537 | const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; |
| 538 | int set = GetSetForNativeRegNum(reg); |
| 539 | |
| 540 | if (set == -1) |
| 541 | return false; |
| 542 | |
| 543 | if (ReadRegisterSet(set, force: false) != KERN_SUCCESS) |
| 544 | return false; |
| 545 | |
| 546 | switch (reg) { |
| 547 | case gpr_x0: |
| 548 | case gpr_x1: |
| 549 | case gpr_x2: |
| 550 | case gpr_x3: |
| 551 | case gpr_x4: |
| 552 | case gpr_x5: |
| 553 | case gpr_x6: |
| 554 | case gpr_x7: |
| 555 | case gpr_x8: |
| 556 | case gpr_x9: |
| 557 | case gpr_x10: |
| 558 | case gpr_x11: |
| 559 | case gpr_x12: |
| 560 | case gpr_x13: |
| 561 | case gpr_x14: |
| 562 | case gpr_x15: |
| 563 | case gpr_x16: |
| 564 | case gpr_x17: |
| 565 | case gpr_x18: |
| 566 | case gpr_x19: |
| 567 | case gpr_x20: |
| 568 | case gpr_x21: |
| 569 | case gpr_x22: |
| 570 | case gpr_x23: |
| 571 | case gpr_x24: |
| 572 | case gpr_x25: |
| 573 | case gpr_x26: |
| 574 | case gpr_x27: |
| 575 | case gpr_x28: |
| 576 | case gpr_fp: |
| 577 | case gpr_sp: |
| 578 | case gpr_lr: |
| 579 | case gpr_pc: |
| 580 | case gpr_cpsr: |
| 581 | gpr.x[reg - gpr_x0] = value.GetAsUInt64(); |
| 582 | break; |
| 583 | |
| 584 | case fpu_v0: |
| 585 | case fpu_v1: |
| 586 | case fpu_v2: |
| 587 | case fpu_v3: |
| 588 | case fpu_v4: |
| 589 | case fpu_v5: |
| 590 | case fpu_v6: |
| 591 | case fpu_v7: |
| 592 | case fpu_v8: |
| 593 | case fpu_v9: |
| 594 | case fpu_v10: |
| 595 | case fpu_v11: |
| 596 | case fpu_v12: |
| 597 | case fpu_v13: |
| 598 | case fpu_v14: |
| 599 | case fpu_v15: |
| 600 | case fpu_v16: |
| 601 | case fpu_v17: |
| 602 | case fpu_v18: |
| 603 | case fpu_v19: |
| 604 | case fpu_v20: |
| 605 | case fpu_v21: |
| 606 | case fpu_v22: |
| 607 | case fpu_v23: |
| 608 | case fpu_v24: |
| 609 | case fpu_v25: |
| 610 | case fpu_v26: |
| 611 | case fpu_v27: |
| 612 | case fpu_v28: |
| 613 | case fpu_v29: |
| 614 | case fpu_v30: |
| 615 | case fpu_v31: |
| 616 | ::memcpy(dest: fpu.v[reg - fpu_v0].bytes, src: value.GetBytes(), |
| 617 | n: value.GetByteSize()); |
| 618 | break; |
| 619 | |
| 620 | case fpu_fpsr: |
| 621 | fpu.fpsr = value.GetAsUInt32(); |
| 622 | break; |
| 623 | |
| 624 | case fpu_fpcr: |
| 625 | fpu.fpcr = value.GetAsUInt32(); |
| 626 | break; |
| 627 | |
| 628 | case exc_exception: |
| 629 | exc.exception = value.GetAsUInt32(); |
| 630 | break; |
| 631 | case exc_esr: |
| 632 | exc.esr = value.GetAsUInt32(); |
| 633 | break; |
| 634 | case exc_far: |
| 635 | exc.far = value.GetAsUInt64(); |
| 636 | break; |
| 637 | |
| 638 | default: |
| 639 | return false; |
| 640 | } |
| 641 | return WriteRegisterSet(set) == KERN_SUCCESS; |
| 642 | } |
| 643 | |
| 644 | bool RegisterContextDarwin_arm64::ReadAllRegisterValues( |
| 645 | lldb::WritableDataBufferSP &data_sp) { |
| 646 | data_sp = std::make_shared<DataBufferHeap>(REG_CONTEXT_SIZE, args: 0); |
| 647 | if (ReadGPR(force: false) == KERN_SUCCESS && ReadFPU(force: false) == KERN_SUCCESS && |
| 648 | ReadEXC(force: false) == KERN_SUCCESS) { |
| 649 | uint8_t *dst = data_sp->GetBytes(); |
| 650 | ::memcpy(dest: dst, src: &gpr, n: sizeof(gpr)); |
| 651 | dst += sizeof(gpr); |
| 652 | |
| 653 | ::memcpy(dest: dst, src: &fpu, n: sizeof(fpu)); |
| 654 | dst += sizeof(gpr); |
| 655 | |
| 656 | ::memcpy(dest: dst, src: &exc, n: sizeof(exc)); |
| 657 | return true; |
| 658 | } |
| 659 | return false; |
| 660 | } |
| 661 | |
| 662 | bool RegisterContextDarwin_arm64::WriteAllRegisterValues( |
| 663 | const lldb::DataBufferSP &data_sp) { |
| 664 | if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { |
| 665 | const uint8_t *src = data_sp->GetBytes(); |
| 666 | ::memcpy(dest: &gpr, src: src, n: sizeof(gpr)); |
| 667 | src += sizeof(gpr); |
| 668 | |
| 669 | ::memcpy(dest: &fpu, src: src, n: sizeof(fpu)); |
| 670 | src += sizeof(gpr); |
| 671 | |
| 672 | ::memcpy(dest: &exc, src: src, n: sizeof(exc)); |
| 673 | uint32_t success_count = 0; |
| 674 | if (WriteGPR() == KERN_SUCCESS) |
| 675 | ++success_count; |
| 676 | if (WriteFPU() == KERN_SUCCESS) |
| 677 | ++success_count; |
| 678 | if (WriteEXC() == KERN_SUCCESS) |
| 679 | ++success_count; |
| 680 | return success_count == 3; |
| 681 | } |
| 682 | return false; |
| 683 | } |
| 684 | |
| 685 | uint32_t RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber( |
| 686 | RegisterKind kind, uint32_t reg) { |
| 687 | if (kind == eRegisterKindGeneric) { |
| 688 | switch (reg) { |
| 689 | case LLDB_REGNUM_GENERIC_PC: |
| 690 | return gpr_pc; |
| 691 | case LLDB_REGNUM_GENERIC_SP: |
| 692 | return gpr_sp; |
| 693 | case LLDB_REGNUM_GENERIC_FP: |
| 694 | return gpr_fp; |
| 695 | case LLDB_REGNUM_GENERIC_RA: |
| 696 | return gpr_lr; |
| 697 | case LLDB_REGNUM_GENERIC_FLAGS: |
| 698 | return gpr_cpsr; |
| 699 | default: |
| 700 | break; |
| 701 | } |
| 702 | } else if (kind == eRegisterKindDWARF) { |
| 703 | switch (reg) { |
| 704 | case arm64_dwarf::x0: |
| 705 | return gpr_x0; |
| 706 | case arm64_dwarf::x1: |
| 707 | return gpr_x1; |
| 708 | case arm64_dwarf::x2: |
| 709 | return gpr_x2; |
| 710 | case arm64_dwarf::x3: |
| 711 | return gpr_x3; |
| 712 | case arm64_dwarf::x4: |
| 713 | return gpr_x4; |
| 714 | case arm64_dwarf::x5: |
| 715 | return gpr_x5; |
| 716 | case arm64_dwarf::x6: |
| 717 | return gpr_x6; |
| 718 | case arm64_dwarf::x7: |
| 719 | return gpr_x7; |
| 720 | case arm64_dwarf::x8: |
| 721 | return gpr_x8; |
| 722 | case arm64_dwarf::x9: |
| 723 | return gpr_x9; |
| 724 | case arm64_dwarf::x10: |
| 725 | return gpr_x10; |
| 726 | case arm64_dwarf::x11: |
| 727 | return gpr_x11; |
| 728 | case arm64_dwarf::x12: |
| 729 | return gpr_x12; |
| 730 | case arm64_dwarf::x13: |
| 731 | return gpr_x13; |
| 732 | case arm64_dwarf::x14: |
| 733 | return gpr_x14; |
| 734 | case arm64_dwarf::x15: |
| 735 | return gpr_x15; |
| 736 | case arm64_dwarf::x16: |
| 737 | return gpr_x16; |
| 738 | case arm64_dwarf::x17: |
| 739 | return gpr_x17; |
| 740 | case arm64_dwarf::x18: |
| 741 | return gpr_x18; |
| 742 | case arm64_dwarf::x19: |
| 743 | return gpr_x19; |
| 744 | case arm64_dwarf::x20: |
| 745 | return gpr_x20; |
| 746 | case arm64_dwarf::x21: |
| 747 | return gpr_x21; |
| 748 | case arm64_dwarf::x22: |
| 749 | return gpr_x22; |
| 750 | case arm64_dwarf::x23: |
| 751 | return gpr_x23; |
| 752 | case arm64_dwarf::x24: |
| 753 | return gpr_x24; |
| 754 | case arm64_dwarf::x25: |
| 755 | return gpr_x25; |
| 756 | case arm64_dwarf::x26: |
| 757 | return gpr_x26; |
| 758 | case arm64_dwarf::x27: |
| 759 | return gpr_x27; |
| 760 | case arm64_dwarf::x28: |
| 761 | return gpr_x28; |
| 762 | |
| 763 | case arm64_dwarf::fp: |
| 764 | return gpr_fp; |
| 765 | case arm64_dwarf::sp: |
| 766 | return gpr_sp; |
| 767 | case arm64_dwarf::lr: |
| 768 | return gpr_lr; |
| 769 | case arm64_dwarf::pc: |
| 770 | return gpr_pc; |
| 771 | case arm64_dwarf::cpsr: |
| 772 | return gpr_cpsr; |
| 773 | |
| 774 | case arm64_dwarf::v0: |
| 775 | return fpu_v0; |
| 776 | case arm64_dwarf::v1: |
| 777 | return fpu_v1; |
| 778 | case arm64_dwarf::v2: |
| 779 | return fpu_v2; |
| 780 | case arm64_dwarf::v3: |
| 781 | return fpu_v3; |
| 782 | case arm64_dwarf::v4: |
| 783 | return fpu_v4; |
| 784 | case arm64_dwarf::v5: |
| 785 | return fpu_v5; |
| 786 | case arm64_dwarf::v6: |
| 787 | return fpu_v6; |
| 788 | case arm64_dwarf::v7: |
| 789 | return fpu_v7; |
| 790 | case arm64_dwarf::v8: |
| 791 | return fpu_v8; |
| 792 | case arm64_dwarf::v9: |
| 793 | return fpu_v9; |
| 794 | case arm64_dwarf::v10: |
| 795 | return fpu_v10; |
| 796 | case arm64_dwarf::v11: |
| 797 | return fpu_v11; |
| 798 | case arm64_dwarf::v12: |
| 799 | return fpu_v12; |
| 800 | case arm64_dwarf::v13: |
| 801 | return fpu_v13; |
| 802 | case arm64_dwarf::v14: |
| 803 | return fpu_v14; |
| 804 | case arm64_dwarf::v15: |
| 805 | return fpu_v15; |
| 806 | case arm64_dwarf::v16: |
| 807 | return fpu_v16; |
| 808 | case arm64_dwarf::v17: |
| 809 | return fpu_v17; |
| 810 | case arm64_dwarf::v18: |
| 811 | return fpu_v18; |
| 812 | case arm64_dwarf::v19: |
| 813 | return fpu_v19; |
| 814 | case arm64_dwarf::v20: |
| 815 | return fpu_v20; |
| 816 | case arm64_dwarf::v21: |
| 817 | return fpu_v21; |
| 818 | case arm64_dwarf::v22: |
| 819 | return fpu_v22; |
| 820 | case arm64_dwarf::v23: |
| 821 | return fpu_v23; |
| 822 | case arm64_dwarf::v24: |
| 823 | return fpu_v24; |
| 824 | case arm64_dwarf::v25: |
| 825 | return fpu_v25; |
| 826 | case arm64_dwarf::v26: |
| 827 | return fpu_v26; |
| 828 | case arm64_dwarf::v27: |
| 829 | return fpu_v27; |
| 830 | case arm64_dwarf::v28: |
| 831 | return fpu_v28; |
| 832 | case arm64_dwarf::v29: |
| 833 | return fpu_v29; |
| 834 | case arm64_dwarf::v30: |
| 835 | return fpu_v30; |
| 836 | case arm64_dwarf::v31: |
| 837 | return fpu_v31; |
| 838 | |
| 839 | default: |
| 840 | break; |
| 841 | } |
| 842 | } else if (kind == eRegisterKindEHFrame) { |
| 843 | switch (reg) { |
| 844 | case arm64_ehframe::x0: |
| 845 | return gpr_x0; |
| 846 | case arm64_ehframe::x1: |
| 847 | return gpr_x1; |
| 848 | case arm64_ehframe::x2: |
| 849 | return gpr_x2; |
| 850 | case arm64_ehframe::x3: |
| 851 | return gpr_x3; |
| 852 | case arm64_ehframe::x4: |
| 853 | return gpr_x4; |
| 854 | case arm64_ehframe::x5: |
| 855 | return gpr_x5; |
| 856 | case arm64_ehframe::x6: |
| 857 | return gpr_x6; |
| 858 | case arm64_ehframe::x7: |
| 859 | return gpr_x7; |
| 860 | case arm64_ehframe::x8: |
| 861 | return gpr_x8; |
| 862 | case arm64_ehframe::x9: |
| 863 | return gpr_x9; |
| 864 | case arm64_ehframe::x10: |
| 865 | return gpr_x10; |
| 866 | case arm64_ehframe::x11: |
| 867 | return gpr_x11; |
| 868 | case arm64_ehframe::x12: |
| 869 | return gpr_x12; |
| 870 | case arm64_ehframe::x13: |
| 871 | return gpr_x13; |
| 872 | case arm64_ehframe::x14: |
| 873 | return gpr_x14; |
| 874 | case arm64_ehframe::x15: |
| 875 | return gpr_x15; |
| 876 | case arm64_ehframe::x16: |
| 877 | return gpr_x16; |
| 878 | case arm64_ehframe::x17: |
| 879 | return gpr_x17; |
| 880 | case arm64_ehframe::x18: |
| 881 | return gpr_x18; |
| 882 | case arm64_ehframe::x19: |
| 883 | return gpr_x19; |
| 884 | case arm64_ehframe::x20: |
| 885 | return gpr_x20; |
| 886 | case arm64_ehframe::x21: |
| 887 | return gpr_x21; |
| 888 | case arm64_ehframe::x22: |
| 889 | return gpr_x22; |
| 890 | case arm64_ehframe::x23: |
| 891 | return gpr_x23; |
| 892 | case arm64_ehframe::x24: |
| 893 | return gpr_x24; |
| 894 | case arm64_ehframe::x25: |
| 895 | return gpr_x25; |
| 896 | case arm64_ehframe::x26: |
| 897 | return gpr_x26; |
| 898 | case arm64_ehframe::x27: |
| 899 | return gpr_x27; |
| 900 | case arm64_ehframe::x28: |
| 901 | return gpr_x28; |
| 902 | case arm64_ehframe::fp: |
| 903 | return gpr_fp; |
| 904 | case arm64_ehframe::sp: |
| 905 | return gpr_sp; |
| 906 | case arm64_ehframe::lr: |
| 907 | return gpr_lr; |
| 908 | case arm64_ehframe::pc: |
| 909 | return gpr_pc; |
| 910 | case arm64_ehframe::cpsr: |
| 911 | return gpr_cpsr; |
| 912 | } |
| 913 | } else if (kind == eRegisterKindLLDB) { |
| 914 | return reg; |
| 915 | } |
| 916 | return LLDB_INVALID_REGNUM; |
| 917 | } |
| 918 | |
| 919 | uint32_t RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints() { |
| 920 | #if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) |
| 921 | // autodetect how many watchpoints are supported dynamically... |
| 922 | static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; |
| 923 | if (g_num_supported_hw_watchpoints == UINT32_MAX) { |
| 924 | size_t len; |
| 925 | uint32_t n = 0; |
| 926 | len = sizeof(n); |
| 927 | if (::sysctlbyname("hw.optional.watchpoint" , &n, &len, NULL, 0) == 0) { |
| 928 | g_num_supported_hw_watchpoints = n; |
| 929 | } |
| 930 | } |
| 931 | return g_num_supported_hw_watchpoints; |
| 932 | #else |
| 933 | // TODO: figure out remote case here! |
| 934 | return 2; |
| 935 | #endif |
| 936 | } |
| 937 | |
| 938 | uint32_t RegisterContextDarwin_arm64::SetHardwareWatchpoint(lldb::addr_t addr, |
| 939 | size_t size, |
| 940 | bool read, |
| 941 | bool write) { |
| 942 | // if (log) log->Printf |
| 943 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, |
| 944 | // size = %u, read = %u, write = %u)", addr, size, read, write); |
| 945 | |
| 946 | const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); |
| 947 | |
| 948 | // Can't watch zero bytes |
| 949 | if (size == 0) |
| 950 | return LLDB_INVALID_INDEX32; |
| 951 | |
| 952 | // We must watch for either read or write |
| 953 | if (!read && !write) |
| 954 | return LLDB_INVALID_INDEX32; |
| 955 | |
| 956 | // Can't watch more than 4 bytes per WVR/WCR pair |
| 957 | if (size > 4) |
| 958 | return LLDB_INVALID_INDEX32; |
| 959 | |
| 960 | // We can only watch up to four bytes that follow a 4 byte aligned address |
| 961 | // per watchpoint register pair. Since we have at most so we can only watch |
| 962 | // until the next 4 byte boundary and we need to make sure we can properly |
| 963 | // encode this. |
| 964 | uint32_t addr_word_offset = addr % 4; |
| 965 | // if (log) log->Printf |
| 966 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - |
| 967 | // addr_word_offset = 0x%8.8x", addr_word_offset); |
| 968 | |
| 969 | uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; |
| 970 | // if (log) log->Printf |
| 971 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = |
| 972 | // 0x%8.8x", byte_mask); |
| 973 | if (byte_mask > 0xfu) |
| 974 | return LLDB_INVALID_INDEX32; |
| 975 | |
| 976 | // Read the debug state |
| 977 | int kret = ReadDBG(force: false); |
| 978 | |
| 979 | if (kret == KERN_SUCCESS) { |
| 980 | // Check to make sure we have the needed hardware support |
| 981 | uint32_t i = 0; |
| 982 | |
| 983 | for (i = 0; i < num_hw_watchpoints; ++i) { |
| 984 | if ((dbg.wcr[i] & WCR_ENABLE) == 0) |
| 985 | break; // We found an available hw breakpoint slot (in i) |
| 986 | } |
| 987 | |
| 988 | // See if we found an available hw breakpoint slot above |
| 989 | if (i < num_hw_watchpoints) { |
| 990 | // Make the byte_mask into a valid Byte Address Select mask |
| 991 | uint32_t byte_address_select = byte_mask << 5; |
| 992 | // Make sure bits 1:0 are clear in our address |
| 993 | dbg.wvr[i] = addr & ~((lldb::addr_t)3); |
| 994 | dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA |
| 995 | // that we will watch |
| 996 | S_USER | // Stop only in user mode |
| 997 | (read ? WCR_LOAD : 0) | // Stop on read access? |
| 998 | (write ? WCR_STORE : 0) | // Stop on write access? |
| 999 | WCR_ENABLE; // Enable this watchpoint; |
| 1000 | |
| 1001 | kret = WriteDBG(); |
| 1002 | // if (log) log->Printf |
| 1003 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() |
| 1004 | // WriteDBG() => 0x%8.8x.", kret); |
| 1005 | |
| 1006 | if (kret == KERN_SUCCESS) |
| 1007 | return i; |
| 1008 | } else { |
| 1009 | // if (log) log->Printf |
| 1010 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): |
| 1011 | // All hardware resources (%u) are in use.", |
| 1012 | // num_hw_watchpoints); |
| 1013 | } |
| 1014 | } |
| 1015 | return LLDB_INVALID_INDEX32; |
| 1016 | } |
| 1017 | |
| 1018 | bool RegisterContextDarwin_arm64::ClearHardwareWatchpoint(uint32_t hw_index) { |
| 1019 | int kret = ReadDBG(force: false); |
| 1020 | |
| 1021 | const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); |
| 1022 | if (kret == KERN_SUCCESS) { |
| 1023 | if (hw_index < num_hw_points) { |
| 1024 | dbg.wcr[hw_index] = 0; |
| 1025 | // if (log) log->Printf |
| 1026 | // ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) |
| 1027 | // - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", |
| 1028 | // hw_index, |
| 1029 | // hw_index, |
| 1030 | // dbg.wvr[hw_index], |
| 1031 | // hw_index, |
| 1032 | // dbg.wcr[hw_index]); |
| 1033 | |
| 1034 | kret = WriteDBG(); |
| 1035 | |
| 1036 | if (kret == KERN_SUCCESS) |
| 1037 | return true; |
| 1038 | } |
| 1039 | } |
| 1040 | return false; |
| 1041 | } |
| 1042 | |