1 //===-- NativeRegisterContextOpenBSD_arm64.cpp ---------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #if defined(__arm64__) || defined(__aarch64__) 11 12 #include <elf.h> 13 #include <err.h> 14 #include <stdint.h> 15 #include <stdlib.h> 16 17 #include "NativeRegisterContextOpenBSD_arm64.h" 18 19 #include "lldb/Host/HostInfo.h" 20 #include "lldb/Utility/DataBufferHeap.h" 21 #include "lldb/Utility/Log.h" 22 #include "lldb/Utility/RegisterValue.h" 23 #include "lldb/Utility/Status.h" 24 #include "llvm/ADT/APInt.h" 25 26 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" 27 28 // clang-format off 29 #include <sys/types.h> 30 #include <sys/sysctl.h> 31 #include <sys/time.h> 32 #include <machine/cpu.h> 33 // clang-format on 34 35 using namespace lldb_private; 36 using namespace lldb_private::process_openbsd; 37 38 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) 39 40 // ARM64 general purpose registers. 41 static const uint32_t g_gpr_regnums_arm64[] = { 42 gpr_x0_arm64, gpr_x1_arm64, gpr_x2_arm64, gpr_x3_arm64, 43 gpr_x4_arm64, gpr_x5_arm64, gpr_x6_arm64, gpr_x7_arm64, 44 gpr_x8_arm64, gpr_x9_arm64, gpr_x10_arm64, gpr_x11_arm64, 45 gpr_x12_arm64, gpr_x13_arm64, gpr_x14_arm64, gpr_x15_arm64, 46 gpr_x16_arm64, gpr_x17_arm64, gpr_x18_arm64, gpr_x19_arm64, 47 gpr_x20_arm64, gpr_x21_arm64, gpr_x22_arm64, gpr_x23_arm64, 48 gpr_x24_arm64, gpr_x25_arm64, gpr_x26_arm64, gpr_x27_arm64, 49 gpr_x28_arm64, gpr_fp_arm64, gpr_lr_arm64, gpr_sp_arm64, 50 gpr_pc_arm64, gpr_cpsr_arm64, gpr_w0_arm64, gpr_w1_arm64, 51 gpr_w2_arm64, gpr_w3_arm64, gpr_w4_arm64, gpr_w5_arm64, 52 gpr_w6_arm64, gpr_w7_arm64, gpr_w8_arm64, gpr_w9_arm64, 53 gpr_w10_arm64, gpr_w11_arm64, gpr_w12_arm64, gpr_w13_arm64, 54 gpr_w14_arm64, gpr_w15_arm64, gpr_w16_arm64, gpr_w17_arm64, 55 gpr_w18_arm64, gpr_w19_arm64, gpr_w20_arm64, gpr_w21_arm64, 56 gpr_w22_arm64, gpr_w23_arm64, gpr_w24_arm64, gpr_w25_arm64, 57 gpr_w26_arm64, gpr_w27_arm64, gpr_w28_arm64, 58 LLDB_INVALID_REGNUM // register sets need to end with this flag 59 }; 60 static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 61 1) == k_num_gpr_registers_arm64, 62 "g_gpr_regnums_arm64 has wrong number of register infos"); 63 64 // ARM64 floating point registers. 65 static const uint32_t g_fpu_regnums_arm64[] = { 66 fpu_v0_arm64, fpu_v1_arm64, fpu_v2_arm64, fpu_v3_arm64, 67 fpu_v4_arm64, fpu_v5_arm64, fpu_v6_arm64, fpu_v7_arm64, 68 fpu_v8_arm64, fpu_v9_arm64, fpu_v10_arm64, fpu_v11_arm64, 69 fpu_v12_arm64, fpu_v13_arm64, fpu_v14_arm64, fpu_v15_arm64, 70 fpu_v16_arm64, fpu_v17_arm64, fpu_v18_arm64, fpu_v19_arm64, 71 fpu_v20_arm64, fpu_v21_arm64, fpu_v22_arm64, fpu_v23_arm64, 72 fpu_v24_arm64, fpu_v25_arm64, fpu_v26_arm64, fpu_v27_arm64, 73 fpu_v28_arm64, fpu_v29_arm64, fpu_v30_arm64, fpu_v31_arm64, 74 75 fpu_s0_arm64, fpu_s1_arm64, fpu_s2_arm64, fpu_s3_arm64, 76 fpu_s4_arm64, fpu_s5_arm64, fpu_s6_arm64, fpu_s7_arm64, 77 fpu_s8_arm64, fpu_s9_arm64, fpu_s10_arm64, fpu_s11_arm64, 78 fpu_s12_arm64, fpu_s13_arm64, fpu_s14_arm64, fpu_s15_arm64, 79 fpu_s16_arm64, fpu_s17_arm64, fpu_s18_arm64, fpu_s19_arm64, 80 fpu_s20_arm64, fpu_s21_arm64, fpu_s22_arm64, fpu_s23_arm64, 81 fpu_s24_arm64, fpu_s25_arm64, fpu_s26_arm64, fpu_s27_arm64, 82 fpu_s28_arm64, fpu_s29_arm64, fpu_s30_arm64, fpu_s31_arm64, 83 84 fpu_d0_arm64, fpu_d1_arm64, fpu_d2_arm64, fpu_d3_arm64, 85 fpu_d4_arm64, fpu_d5_arm64, fpu_d6_arm64, fpu_d7_arm64, 86 fpu_d8_arm64, fpu_d9_arm64, fpu_d10_arm64, fpu_d11_arm64, 87 fpu_d12_arm64, fpu_d13_arm64, fpu_d14_arm64, fpu_d15_arm64, 88 fpu_d16_arm64, fpu_d17_arm64, fpu_d18_arm64, fpu_d19_arm64, 89 fpu_d20_arm64, fpu_d21_arm64, fpu_d22_arm64, fpu_d23_arm64, 90 fpu_d24_arm64, fpu_d25_arm64, fpu_d26_arm64, fpu_d27_arm64, 91 fpu_d28_arm64, fpu_d29_arm64, fpu_d30_arm64, fpu_d31_arm64, 92 fpu_fpsr_arm64, fpu_fpcr_arm64, 93 LLDB_INVALID_REGNUM // register sets need to end with this flag 94 }; 95 static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 96 1) == k_num_fpr_registers_arm64, 97 "g_fpu_regnums_arm64 has wrong number of register infos"); 98 99 namespace { 100 // Number of register sets provided by this context. 101 enum { k_num_register_sets = 2 }; 102 } 103 104 // Register sets for ARM64. 105 static const RegisterSet g_reg_sets_arm64[k_num_register_sets] = { 106 {"General Purpose Registers", "gpr", k_num_gpr_registers_arm64, 107 g_gpr_regnums_arm64}, 108 {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64, 109 g_fpu_regnums_arm64}}; 110 111 std::unique_ptr<NativeRegisterContextOpenBSD> 112 NativeRegisterContextOpenBSD::CreateHostNativeRegisterContextOpenBSD( 113 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 114 return std::make_unique<NativeRegisterContextOpenBSD_arm64>(target_arch, native_thread); 115 } 116 117 // ---------------------------------------------------------------------------- 118 // NativeRegisterContextOpenBSD_arm64 members. 119 // ---------------------------------------------------------------------------- 120 121 static RegisterInfoInterface * 122 CreateRegisterInfoInterface(const ArchSpec &target_arch) { 123 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 124 "Register setting path assumes this is a 64-bit host"); 125 return new RegisterInfoPOSIX_arm64(target_arch, 0); 126 } 127 128 static llvm::APInt uint128ToAPInt(__uint128_t in) { 129 uint64_t *pair = (uint64_t *)∈ 130 llvm::APInt out(128, 2, pair); 131 return out; 132 } 133 134 static __uint128_t APIntTouint128(llvm::APInt in) { 135 assert(in.getBitWidth() == 128); 136 __uint128_t out = 0; 137 const uint64_t *data = in.getRawData(); 138 ::memcpy((uint64_t *)&out, data, sizeof(__uint128_t)); 139 return out; 140 } 141 142 NativeRegisterContextOpenBSD_arm64::NativeRegisterContextOpenBSD_arm64( 143 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 144 : NativeRegisterContextOpenBSD(native_thread, 145 CreateRegisterInfoInterface(target_arch)), 146 m_gpr(), m_fpr() {} 147 148 uint32_t NativeRegisterContextOpenBSD_arm64::GetUserRegisterCount() const { 149 uint32_t count = 0; 150 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 151 count += g_reg_sets_arm64[set_index].num_registers; 152 return count; 153 } 154 155 uint32_t NativeRegisterContextOpenBSD_arm64::GetRegisterSetCount() const { 156 return k_num_register_sets; 157 } 158 159 const RegisterSet * 160 NativeRegisterContextOpenBSD_arm64::GetRegisterSet(uint32_t set_index) const { 161 if (set_index < k_num_register_sets) 162 return &g_reg_sets_arm64[set_index]; 163 164 return nullptr; 165 } 166 167 Status 168 NativeRegisterContextOpenBSD_arm64::ReadRegister(const RegisterInfo *reg_info, 169 RegisterValue ®_value) { 170 Status error; 171 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 172 173 if (!reg_info) { 174 error.SetErrorString("reg_info NULL"); 175 return error; 176 } 177 178 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 179 if (reg == LLDB_INVALID_REGNUM) { 180 // This is likely an internal register for lldb use only and should not be 181 // directly queried. 182 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 183 "register, cannot read directly", 184 reg_info->name); 185 return error; 186 } 187 188 int set = GetSetForNativeRegNum(reg); 189 if (set == -1) { 190 // This is likely an internal register for lldb use only and should not be 191 // directly queried. 192 error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 193 reg_info->name); 194 return error; 195 } 196 197 if (ReadRegisterSet(set) != 0) { 198 // This is likely an internal register for lldb use only and should not be 199 // directly queried. 200 error.SetErrorStringWithFormat( 201 "reading register set for register \"%s\" failed", reg_info->name); 202 return error; 203 } 204 205 switch (reg) { 206 case gpr_x0_arm64: 207 case gpr_x1_arm64: 208 case gpr_x2_arm64: 209 case gpr_x3_arm64: 210 case gpr_x4_arm64: 211 case gpr_x5_arm64: 212 case gpr_x6_arm64: 213 case gpr_x7_arm64: 214 case gpr_x8_arm64: 215 case gpr_x9_arm64: 216 case gpr_x10_arm64: 217 case gpr_x11_arm64: 218 case gpr_x12_arm64: 219 case gpr_x13_arm64: 220 case gpr_x14_arm64: 221 case gpr_x15_arm64: 222 case gpr_x16_arm64: 223 case gpr_x17_arm64: 224 case gpr_x18_arm64: 225 case gpr_x19_arm64: 226 case gpr_x20_arm64: 227 case gpr_x21_arm64: 228 case gpr_x22_arm64: 229 case gpr_x23_arm64: 230 case gpr_x24_arm64: 231 case gpr_x25_arm64: 232 case gpr_x26_arm64: 233 case gpr_x27_arm64: 234 case gpr_x28_arm64: 235 reg_value = (uint64_t)m_gpr.r_reg[reg - gpr_x0_arm64]; 236 break; 237 case gpr_fp_arm64: 238 reg_value = (uint64_t)m_gpr.r_reg[29]; 239 break; 240 case gpr_lr_arm64: 241 reg_value = (uint64_t)m_gpr.r_lr; 242 break; 243 case gpr_sp_arm64: 244 reg_value = (uint64_t)m_gpr.r_sp; 245 break; 246 case gpr_pc_arm64: 247 reg_value = (uint64_t)m_gpr.r_pc; 248 break; 249 case gpr_cpsr_arm64: 250 reg_value = (uint64_t)m_gpr.r_spsr; 251 break; 252 case fpu_v0_arm64: 253 case fpu_v1_arm64: 254 case fpu_v2_arm64: 255 case fpu_v3_arm64: 256 case fpu_v4_arm64: 257 case fpu_v5_arm64: 258 case fpu_v6_arm64: 259 case fpu_v7_arm64: 260 case fpu_v8_arm64: 261 case fpu_v9_arm64: 262 case fpu_v10_arm64: 263 case fpu_v11_arm64: 264 case fpu_v12_arm64: 265 case fpu_v13_arm64: 266 case fpu_v14_arm64: 267 case fpu_v15_arm64: 268 case fpu_v16_arm64: 269 case fpu_v17_arm64: 270 case fpu_v18_arm64: 271 case fpu_v19_arm64: 272 case fpu_v20_arm64: 273 case fpu_v21_arm64: 274 case fpu_v22_arm64: 275 case fpu_v23_arm64: 276 case fpu_v24_arm64: 277 case fpu_v25_arm64: 278 case fpu_v26_arm64: 279 case fpu_v27_arm64: 280 case fpu_v28_arm64: 281 case fpu_v29_arm64: 282 case fpu_v30_arm64: 283 case fpu_v31_arm64: 284 reg_value = uint128ToAPInt(m_fpr.fp_reg[reg - fpu_v0_arm64]); 285 break; 286 case fpu_fpsr_arm64: 287 reg_value = (uint32_t)m_fpr.fp_sr; 288 break; 289 case fpu_fpcr_arm64: 290 reg_value = (uint32_t)m_fpr.fp_cr; 291 break; 292 default: 293 log->Printf("Requested read to unhandled reg: %u", reg); 294 break; 295 } 296 297 if (reg_value.GetByteSize() > reg_info->byte_size) { 298 reg_value.SetType(reg_info); 299 } 300 301 return error; 302 } 303 304 Status NativeRegisterContextOpenBSD_arm64::WriteRegister( 305 const RegisterInfo *reg_info, const RegisterValue ®_value) { 306 307 Status error; 308 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 309 310 if (!reg_info) { 311 error.SetErrorString("reg_info NULL"); 312 return error; 313 } 314 315 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 316 if (reg == LLDB_INVALID_REGNUM) { 317 // This is likely an internal register for lldb use only and should not be 318 // directly queried. 319 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 320 "register, cannot read directly", 321 reg_info->name); 322 return error; 323 } 324 325 int set = GetSetForNativeRegNum(reg); 326 if (set == -1) { 327 // This is likely an internal register for lldb use only and should not be 328 // directly queried. 329 error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 330 reg_info->name); 331 return error; 332 } 333 334 if (ReadRegisterSet(set) != 0) { 335 // This is likely an internal register for lldb use only and should not be 336 // directly queried. 337 error.SetErrorStringWithFormat( 338 "reading register set for register \"%s\" failed", reg_info->name); 339 return error; 340 } 341 342 switch (reg) { 343 case gpr_x0_arm64: 344 case gpr_x1_arm64: 345 case gpr_x2_arm64: 346 case gpr_x3_arm64: 347 case gpr_x4_arm64: 348 case gpr_x5_arm64: 349 case gpr_x6_arm64: 350 case gpr_x7_arm64: 351 case gpr_x8_arm64: 352 case gpr_x9_arm64: 353 case gpr_x10_arm64: 354 case gpr_x11_arm64: 355 case gpr_x12_arm64: 356 case gpr_x13_arm64: 357 case gpr_x14_arm64: 358 case gpr_x15_arm64: 359 case gpr_x16_arm64: 360 case gpr_x17_arm64: 361 case gpr_x18_arm64: 362 case gpr_x19_arm64: 363 case gpr_x20_arm64: 364 case gpr_x21_arm64: 365 case gpr_x22_arm64: 366 case gpr_x23_arm64: 367 case gpr_x24_arm64: 368 case gpr_x25_arm64: 369 case gpr_x26_arm64: 370 case gpr_x27_arm64: 371 case gpr_x28_arm64: 372 m_gpr.r_reg[reg - gpr_x0_arm64] = reg_value.GetAsUInt64(); 373 break; 374 case gpr_fp_arm64: 375 m_gpr.r_reg[29] = reg_value.GetAsUInt64(); 376 break; 377 case gpr_lr_arm64: 378 m_gpr.r_lr = reg_value.GetAsUInt64(); 379 break; 380 case gpr_sp_arm64: 381 m_gpr.r_sp = reg_value.GetAsUInt64(); 382 break; 383 case gpr_pc_arm64: 384 m_gpr.r_pc = reg_value.GetAsUInt64(); 385 break; 386 case gpr_cpsr_arm64: 387 m_gpr.r_spsr = reg_value.GetAsUInt64(); 388 break; 389 case fpu_v0_arm64: 390 case fpu_v1_arm64: 391 case fpu_v2_arm64: 392 case fpu_v3_arm64: 393 case fpu_v4_arm64: 394 case fpu_v5_arm64: 395 case fpu_v6_arm64: 396 case fpu_v7_arm64: 397 case fpu_v8_arm64: 398 case fpu_v9_arm64: 399 case fpu_v10_arm64: 400 case fpu_v11_arm64: 401 case fpu_v12_arm64: 402 case fpu_v13_arm64: 403 case fpu_v14_arm64: 404 case fpu_v15_arm64: 405 case fpu_v16_arm64: 406 case fpu_v17_arm64: 407 case fpu_v18_arm64: 408 case fpu_v19_arm64: 409 case fpu_v20_arm64: 410 case fpu_v21_arm64: 411 case fpu_v22_arm64: 412 case fpu_v23_arm64: 413 case fpu_v24_arm64: 414 case fpu_v25_arm64: 415 case fpu_v26_arm64: 416 case fpu_v27_arm64: 417 case fpu_v28_arm64: 418 case fpu_v29_arm64: 419 case fpu_v30_arm64: 420 case fpu_v31_arm64: 421 m_fpr.fp_reg[reg - fpu_v0_arm64] = 422 APIntTouint128(reg_value.GetAsUInt128(llvm::APInt(128, 0, false))); 423 break; 424 case fpu_fpsr_arm64: 425 m_fpr.fp_sr = reg_value.GetAsUInt32(); 426 break; 427 case fpu_fpcr_arm64: 428 m_fpr.fp_cr = reg_value.GetAsUInt32(); 429 break; 430 default: 431 log->Printf("Requested write of unhandled reg: %u", reg); 432 break; 433 } 434 435 if (WriteRegisterSet(set) != 0) 436 error.SetErrorStringWithFormat("failed to write register set"); 437 438 return error; 439 } 440 441 Status NativeRegisterContextOpenBSD_arm64::ReadAllRegisterValues( 442 lldb::DataBufferSP &data_sp) { 443 Status error; 444 445 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 446 if (!data_sp) { 447 error.SetErrorStringWithFormat( 448 "failed to allocate DataBufferHeap instance of size %zu", 449 REG_CONTEXT_SIZE); 450 return error; 451 } 452 453 error = ReadGPR(); 454 if (error.Fail()) 455 return error; 456 457 error = ReadFPR(); 458 if (error.Fail()) 459 return error; 460 461 uint8_t *dst = data_sp->GetBytes(); 462 if (dst == nullptr) { 463 error.SetErrorStringWithFormat("DataBufferHeap instance of size %zu" 464 " returned a null pointer", 465 REG_CONTEXT_SIZE); 466 return error; 467 } 468 469 ::memcpy(dst, &m_gpr, GetGPRSize()); 470 dst += GetGPRSize(); 471 472 ::memcpy(dst, &m_fpr, GetFPRSize()); 473 dst += GetFPRSize(); 474 475 return error; 476 } 477 478 Status NativeRegisterContextOpenBSD_arm64::WriteAllRegisterValues( 479 const lldb::DataBufferSP &data_sp) { 480 Status error; 481 482 if (!data_sp) { 483 error.SetErrorStringWithFormat( 484 "NativeRegisterContextOpenBSD_arm64::%s invalid data_sp provided", 485 __FUNCTION__); 486 return error; 487 } 488 489 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 490 error.SetErrorStringWithFormat( 491 "NativeRegisterContextOpenBSD_arm64::%s data_sp contained mismatched " 492 "data size, expected %zu, actual %llu", 493 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 494 return error; 495 } 496 497 uint8_t *src = data_sp->GetBytes(); 498 if (src == nullptr) { 499 error.SetErrorStringWithFormat("NativeRegisterContextOpenBSD_arm64::%s " 500 "DataBuffer::GetBytes() returned a null " 501 "pointer", 502 __FUNCTION__); 503 return error; 504 } 505 // TODO ? 506 // Do we need to make a custom RegisterInfoOpenBSD_arm64 507 // because the RegisterInfoPOSIX_arm64 doesn't quite match 508 // our machine/reg.h? 509 ::memcpy(&m_gpr, src, GetGPRSize()); 510 error = WriteGPR(); 511 if (error.Fail()) 512 return error; 513 src += GetGPRSize(); 514 515 ::memcpy(&m_fpr, src, GetFPRSize()); 516 error = WriteFPR(); 517 if (error.Fail()) 518 return error; 519 src += GetFPRSize(); 520 521 return error; 522 } 523 524 int NativeRegisterContextOpenBSD_arm64::GetSetForNativeRegNum( 525 int reg_num) const { 526 if (reg_num >= k_first_gpr_arm64 && reg_num <= k_last_gpr_arm64) 527 return GPRegSet; 528 else if (reg_num >= k_first_fpr_arm64 && reg_num <= k_last_fpr_arm64) 529 return FPRegSet; 530 else 531 return -1; 532 } 533 534 int NativeRegisterContextOpenBSD_arm64::ReadRegisterSet(uint32_t set) { 535 switch (set) { 536 case GPRegSet: 537 ReadGPR(); 538 return 0; 539 case FPRegSet: 540 ReadFPR(); 541 return 0; 542 default: 543 break; 544 } 545 return -1; 546 } 547 548 int NativeRegisterContextOpenBSD_arm64::WriteRegisterSet(uint32_t set) { 549 switch (set) { 550 case GPRegSet: 551 WriteGPR(); 552 return 0; 553 case FPRegSet: 554 WriteFPR(); 555 return 0; 556 default: 557 break; 558 } 559 return -1; 560 } 561 #endif 562