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