1 //===-- NativeRegisterContextNetBSD_x86_64.cpp ---------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #if defined(__x86_64__) 10 11 #include "NativeRegisterContextNetBSD_x86_64.h" 12 13 #include "lldb/Host/HostInfo.h" 14 #include "lldb/Utility/DataBufferHeap.h" 15 #include "lldb/Utility/Log.h" 16 #include "lldb/Utility/RegisterValue.h" 17 #include "lldb/Utility/Status.h" 18 19 #include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h" 20 21 // clang-format off 22 #include <sys/types.h> 23 #include <sys/sysctl.h> 24 #include <x86/cpu.h> 25 #include <elf.h> 26 #include <err.h> 27 #include <stdint.h> 28 #include <stdlib.h> 29 // clang-format on 30 31 using namespace lldb_private; 32 using namespace lldb_private::process_netbsd; 33 34 // Private namespace. 35 36 namespace { 37 // x86 64-bit general purpose registers. 38 static const uint32_t g_gpr_regnums_x86_64[] = { 39 lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, 40 lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64, 41 lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64, 42 lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64, 43 lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64, 44 lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64, 45 lldb_eax_x86_64, lldb_ebx_x86_64, lldb_ecx_x86_64, lldb_edx_x86_64, 46 lldb_edi_x86_64, lldb_esi_x86_64, lldb_ebp_x86_64, lldb_esp_x86_64, 47 lldb_r8d_x86_64, // Low 32 bits or r8 48 lldb_r9d_x86_64, // Low 32 bits or r9 49 lldb_r10d_x86_64, // Low 32 bits or r10 50 lldb_r11d_x86_64, // Low 32 bits or r11 51 lldb_r12d_x86_64, // Low 32 bits or r12 52 lldb_r13d_x86_64, // Low 32 bits or r13 53 lldb_r14d_x86_64, // Low 32 bits or r14 54 lldb_r15d_x86_64, // Low 32 bits or r15 55 lldb_ax_x86_64, lldb_bx_x86_64, lldb_cx_x86_64, lldb_dx_x86_64, 56 lldb_di_x86_64, lldb_si_x86_64, lldb_bp_x86_64, lldb_sp_x86_64, 57 lldb_r8w_x86_64, // Low 16 bits or r8 58 lldb_r9w_x86_64, // Low 16 bits or r9 59 lldb_r10w_x86_64, // Low 16 bits or r10 60 lldb_r11w_x86_64, // Low 16 bits or r11 61 lldb_r12w_x86_64, // Low 16 bits or r12 62 lldb_r13w_x86_64, // Low 16 bits or r13 63 lldb_r14w_x86_64, // Low 16 bits or r14 64 lldb_r15w_x86_64, // Low 16 bits or r15 65 lldb_ah_x86_64, lldb_bh_x86_64, lldb_ch_x86_64, lldb_dh_x86_64, 66 lldb_al_x86_64, lldb_bl_x86_64, lldb_cl_x86_64, lldb_dl_x86_64, 67 lldb_dil_x86_64, lldb_sil_x86_64, lldb_bpl_x86_64, lldb_spl_x86_64, 68 lldb_r8l_x86_64, // Low 8 bits or r8 69 lldb_r9l_x86_64, // Low 8 bits or r9 70 lldb_r10l_x86_64, // Low 8 bits or r10 71 lldb_r11l_x86_64, // Low 8 bits or r11 72 lldb_r12l_x86_64, // Low 8 bits or r12 73 lldb_r13l_x86_64, // Low 8 bits or r13 74 lldb_r14l_x86_64, // Low 8 bits or r14 75 lldb_r15l_x86_64, // Low 8 bits or r15 76 LLDB_INVALID_REGNUM // register sets need to end with this flag 77 }; 78 static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 79 1 == 80 k_num_gpr_registers_x86_64, 81 "g_gpr_regnums_x86_64 has wrong number of register infos"); 82 83 // Number of register sets provided by this context. 84 enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 }; 85 86 // Register sets for x86 64-bit. 87 static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { 88 {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, 89 g_gpr_regnums_x86_64}, 90 }; 91 92 #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize()) 93 94 const int fpu_present = []() -> int { 95 int mib[2]; 96 int error; 97 size_t len; 98 int val; 99 100 len = sizeof(val); 101 mib[0] = CTL_MACHDEP; 102 mib[1] = CPU_FPU_PRESENT; 103 104 error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0); 105 if (error) 106 errx(EXIT_FAILURE, "sysctl"); 107 108 return val; 109 }(); 110 111 const int osfxsr = []() -> int { 112 int mib[2]; 113 int error; 114 size_t len; 115 int val; 116 117 len = sizeof(val); 118 mib[0] = CTL_MACHDEP; 119 mib[1] = CPU_OSFXSR; 120 121 error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0); 122 if (error) 123 errx(EXIT_FAILURE, "sysctl"); 124 125 return val; 126 }(); 127 128 const int fpu_save = []() -> int { 129 int mib[2]; 130 int error; 131 size_t len; 132 int val; 133 134 len = sizeof(val); 135 mib[0] = CTL_MACHDEP; 136 mib[1] = CPU_FPU_SAVE; 137 138 error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0); 139 if (error) 140 errx(EXIT_FAILURE, "sysctl"); 141 142 return val; 143 }(); 144 145 } // namespace 146 147 NativeRegisterContextNetBSD * 148 NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD( 149 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 150 return new NativeRegisterContextNetBSD_x86_64(target_arch, native_thread); 151 } 152 153 // NativeRegisterContextNetBSD_x86_64 members. 154 155 static RegisterInfoInterface * 156 CreateRegisterInfoInterface(const ArchSpec &target_arch) { 157 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 158 "Register setting path assumes this is a 64-bit host"); 159 // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 160 // register context. 161 return new RegisterContextNetBSD_x86_64(target_arch); 162 } 163 164 NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64( 165 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 166 : NativeRegisterContextNetBSD(native_thread, 167 CreateRegisterInfoInterface(target_arch)), 168 m_gpr_x86_64(), m_fpr_x86_64(), m_dbr_x86_64() {} 169 170 // CONSIDER after local and llgs debugging are merged, register set support can 171 // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual. 172 uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const { 173 uint32_t sets = 0; 174 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { 175 if (GetSetForNativeRegNum(set_index) != -1) 176 ++sets; 177 } 178 179 return sets; 180 } 181 182 const RegisterSet * 183 NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const { 184 switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { 185 case llvm::Triple::x86_64: 186 return &g_reg_sets_x86_64[set_index]; 187 default: 188 assert(false && "Unhandled target architecture."); 189 return nullptr; 190 } 191 192 return nullptr; 193 } 194 195 int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum( 196 int reg_num) const { 197 if (reg_num <= k_last_gpr_x86_64) 198 return GPRegSet; 199 else if (reg_num <= k_last_fpr_x86_64) 200 return (fpu_present == 1 && osfxsr == 1 && fpu_save >= 1) ? FPRegSet : -1; 201 else if (reg_num <= k_last_avx_x86_64) 202 return -1; // AVX 203 else if (reg_num <= k_last_mpxr_x86_64) 204 return -1; // MPXR 205 else if (reg_num <= k_last_mpxc_x86_64) 206 return -1; // MPXC 207 else if (reg_num <= lldb_dr7_x86_64) 208 return DBRegSet; // DBR 209 else 210 return -1; 211 } 212 213 int NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) { 214 switch (set) { 215 case GPRegSet: 216 ReadGPR(); 217 return 0; 218 case FPRegSet: 219 ReadFPR(); 220 return 0; 221 case DBRegSet: 222 ReadDBR(); 223 return 0; 224 default: 225 break; 226 } 227 return -1; 228 } 229 int NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) { 230 switch (set) { 231 case GPRegSet: 232 WriteGPR(); 233 return 0; 234 case FPRegSet: 235 WriteFPR(); 236 return 0; 237 case DBRegSet: 238 WriteDBR(); 239 return 0; 240 default: 241 break; 242 } 243 return -1; 244 } 245 246 Status 247 NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, 248 RegisterValue ®_value) { 249 Status error; 250 251 if (!reg_info) { 252 error.SetErrorString("reg_info NULL"); 253 return error; 254 } 255 256 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 257 if (reg == LLDB_INVALID_REGNUM) { 258 // This is likely an internal register for lldb use only and should not be 259 // directly queried. 260 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 261 "register, cannot read directly", 262 reg_info->name); 263 return error; 264 } 265 266 int set = GetSetForNativeRegNum(reg); 267 if (set == -1) { 268 // This is likely an internal register for lldb use only and should not be 269 // directly queried. 270 error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 271 reg_info->name); 272 return error; 273 } 274 275 if (ReadRegisterSet(set) != 0) { 276 // This is likely an internal register for lldb use only and should not be 277 // directly queried. 278 error.SetErrorStringWithFormat( 279 "reading register set for register \"%s\" failed", reg_info->name); 280 return error; 281 } 282 283 switch (reg) { 284 case lldb_rax_x86_64: 285 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX]; 286 break; 287 case lldb_rbx_x86_64: 288 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX]; 289 break; 290 case lldb_rcx_x86_64: 291 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX]; 292 break; 293 case lldb_rdx_x86_64: 294 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX]; 295 break; 296 case lldb_rdi_x86_64: 297 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI]; 298 break; 299 case lldb_rsi_x86_64: 300 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI]; 301 break; 302 case lldb_rbp_x86_64: 303 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP]; 304 break; 305 case lldb_rsp_x86_64: 306 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP]; 307 break; 308 case lldb_r8_x86_64: 309 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8]; 310 break; 311 case lldb_r9_x86_64: 312 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9]; 313 break; 314 case lldb_r10_x86_64: 315 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10]; 316 break; 317 case lldb_r11_x86_64: 318 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11]; 319 break; 320 case lldb_r12_x86_64: 321 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12]; 322 break; 323 case lldb_r13_x86_64: 324 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13]; 325 break; 326 case lldb_r14_x86_64: 327 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14]; 328 break; 329 case lldb_r15_x86_64: 330 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15]; 331 break; 332 case lldb_rip_x86_64: 333 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP]; 334 break; 335 case lldb_rflags_x86_64: 336 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS]; 337 break; 338 case lldb_cs_x86_64: 339 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS]; 340 break; 341 case lldb_fs_x86_64: 342 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS]; 343 break; 344 case lldb_gs_x86_64: 345 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS]; 346 break; 347 case lldb_ss_x86_64: 348 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS]; 349 break; 350 case lldb_ds_x86_64: 351 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS]; 352 break; 353 case lldb_es_x86_64: 354 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES]; 355 break; 356 case lldb_fctrl_x86_64: 357 reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_cw; 358 break; 359 case lldb_fstat_x86_64: 360 reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_sw; 361 break; 362 case lldb_ftag_x86_64: 363 reg_value = (uint8_t)m_fpr_x86_64.fxstate.fx_tw; 364 break; 365 case lldb_fop_x86_64: 366 reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_opcode; 367 break; 368 case lldb_fiseg_x86_64: 369 reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_ip.fa_64; 370 break; 371 case lldb_fioff_x86_64: 372 reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off; 373 break; 374 case lldb_foseg_x86_64: 375 reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_dp.fa_64; 376 break; 377 case lldb_fooff_x86_64: 378 reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off; 379 break; 380 case lldb_mxcsr_x86_64: 381 reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr; 382 break; 383 case lldb_mxcsrmask_x86_64: 384 reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr_mask; 385 break; 386 case lldb_st0_x86_64: 387 case lldb_st1_x86_64: 388 case lldb_st2_x86_64: 389 case lldb_st3_x86_64: 390 case lldb_st4_x86_64: 391 case lldb_st5_x86_64: 392 case lldb_st6_x86_64: 393 case lldb_st7_x86_64: 394 reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64], 395 reg_info->byte_size, endian::InlHostByteOrder()); 396 break; 397 case lldb_mm0_x86_64: 398 case lldb_mm1_x86_64: 399 case lldb_mm2_x86_64: 400 case lldb_mm3_x86_64: 401 case lldb_mm4_x86_64: 402 case lldb_mm5_x86_64: 403 case lldb_mm6_x86_64: 404 case lldb_mm7_x86_64: 405 reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], 406 reg_info->byte_size, endian::InlHostByteOrder()); 407 break; 408 case lldb_xmm0_x86_64: 409 case lldb_xmm1_x86_64: 410 case lldb_xmm2_x86_64: 411 case lldb_xmm3_x86_64: 412 case lldb_xmm4_x86_64: 413 case lldb_xmm5_x86_64: 414 case lldb_xmm6_x86_64: 415 case lldb_xmm7_x86_64: 416 case lldb_xmm8_x86_64: 417 case lldb_xmm9_x86_64: 418 case lldb_xmm10_x86_64: 419 case lldb_xmm11_x86_64: 420 case lldb_xmm12_x86_64: 421 case lldb_xmm13_x86_64: 422 case lldb_xmm14_x86_64: 423 case lldb_xmm15_x86_64: 424 reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], 425 reg_info->byte_size, endian::InlHostByteOrder()); 426 break; 427 case lldb_dr0_x86_64: 428 case lldb_dr1_x86_64: 429 case lldb_dr2_x86_64: 430 case lldb_dr3_x86_64: 431 case lldb_dr4_x86_64: 432 case lldb_dr5_x86_64: 433 case lldb_dr6_x86_64: 434 case lldb_dr7_x86_64: 435 reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64]; 436 break; 437 } 438 439 return error; 440 } 441 442 Status NativeRegisterContextNetBSD_x86_64::WriteRegister( 443 const RegisterInfo *reg_info, const RegisterValue ®_value) { 444 445 Status error; 446 447 if (!reg_info) { 448 error.SetErrorString("reg_info NULL"); 449 return error; 450 } 451 452 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 453 if (reg == LLDB_INVALID_REGNUM) { 454 // This is likely an internal register for lldb use only and should not be 455 // directly queried. 456 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 457 "register, cannot read directly", 458 reg_info->name); 459 return error; 460 } 461 462 int set = GetSetForNativeRegNum(reg); 463 if (set == -1) { 464 // This is likely an internal register for lldb use only and should not be 465 // directly queried. 466 error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 467 reg_info->name); 468 return error; 469 } 470 471 if (ReadRegisterSet(set) != 0) { 472 // This is likely an internal register for lldb use only and should not be 473 // directly queried. 474 error.SetErrorStringWithFormat( 475 "reading register set for register \"%s\" failed", reg_info->name); 476 return error; 477 } 478 479 switch (reg) { 480 case lldb_rax_x86_64: 481 m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64(); 482 break; 483 case lldb_rbx_x86_64: 484 m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64(); 485 break; 486 case lldb_rcx_x86_64: 487 m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64(); 488 break; 489 case lldb_rdx_x86_64: 490 m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64(); 491 break; 492 case lldb_rdi_x86_64: 493 m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64(); 494 break; 495 case lldb_rsi_x86_64: 496 m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64(); 497 break; 498 case lldb_rbp_x86_64: 499 m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64(); 500 break; 501 case lldb_rsp_x86_64: 502 m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64(); 503 break; 504 case lldb_r8_x86_64: 505 m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64(); 506 break; 507 case lldb_r9_x86_64: 508 m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64(); 509 break; 510 case lldb_r10_x86_64: 511 m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64(); 512 break; 513 case lldb_r11_x86_64: 514 m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64(); 515 break; 516 case lldb_r12_x86_64: 517 m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64(); 518 break; 519 case lldb_r13_x86_64: 520 m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64(); 521 break; 522 case lldb_r14_x86_64: 523 m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64(); 524 break; 525 case lldb_r15_x86_64: 526 m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64(); 527 break; 528 case lldb_rip_x86_64: 529 m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64(); 530 break; 531 case lldb_rflags_x86_64: 532 m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64(); 533 break; 534 case lldb_cs_x86_64: 535 m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64(); 536 break; 537 case lldb_fs_x86_64: 538 m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64(); 539 break; 540 case lldb_gs_x86_64: 541 m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64(); 542 break; 543 case lldb_ss_x86_64: 544 m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64(); 545 break; 546 case lldb_ds_x86_64: 547 m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64(); 548 break; 549 case lldb_es_x86_64: 550 m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64(); 551 break; 552 case lldb_fctrl_x86_64: 553 m_fpr_x86_64.fxstate.fx_cw = reg_value.GetAsUInt16(); 554 break; 555 case lldb_fstat_x86_64: 556 m_fpr_x86_64.fxstate.fx_sw = reg_value.GetAsUInt16(); 557 break; 558 case lldb_ftag_x86_64: 559 m_fpr_x86_64.fxstate.fx_tw = reg_value.GetAsUInt8(); 560 break; 561 case lldb_fop_x86_64: 562 m_fpr_x86_64.fxstate.fx_opcode = reg_value.GetAsUInt16(); 563 break; 564 case lldb_fiseg_x86_64: 565 m_fpr_x86_64.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64(); 566 break; 567 case lldb_fioff_x86_64: 568 m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32(); 569 break; 570 case lldb_foseg_x86_64: 571 m_fpr_x86_64.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64(); 572 break; 573 case lldb_fooff_x86_64: 574 m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32(); 575 break; 576 case lldb_mxcsr_x86_64: 577 m_fpr_x86_64.fxstate.fx_mxcsr = reg_value.GetAsUInt32(); 578 break; 579 case lldb_mxcsrmask_x86_64: 580 m_fpr_x86_64.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32(); 581 break; 582 case lldb_st0_x86_64: 583 case lldb_st1_x86_64: 584 case lldb_st2_x86_64: 585 case lldb_st3_x86_64: 586 case lldb_st4_x86_64: 587 case lldb_st5_x86_64: 588 case lldb_st6_x86_64: 589 case lldb_st7_x86_64: 590 ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64], 591 reg_value.GetBytes(), reg_value.GetByteSize()); 592 break; 593 case lldb_mm0_x86_64: 594 case lldb_mm1_x86_64: 595 case lldb_mm2_x86_64: 596 case lldb_mm3_x86_64: 597 case lldb_mm4_x86_64: 598 case lldb_mm5_x86_64: 599 case lldb_mm6_x86_64: 600 case lldb_mm7_x86_64: 601 ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], 602 reg_value.GetBytes(), reg_value.GetByteSize()); 603 break; 604 case lldb_xmm0_x86_64: 605 case lldb_xmm1_x86_64: 606 case lldb_xmm2_x86_64: 607 case lldb_xmm3_x86_64: 608 case lldb_xmm4_x86_64: 609 case lldb_xmm5_x86_64: 610 case lldb_xmm6_x86_64: 611 case lldb_xmm7_x86_64: 612 case lldb_xmm8_x86_64: 613 case lldb_xmm9_x86_64: 614 case lldb_xmm10_x86_64: 615 case lldb_xmm11_x86_64: 616 case lldb_xmm12_x86_64: 617 case lldb_xmm13_x86_64: 618 case lldb_xmm14_x86_64: 619 case lldb_xmm15_x86_64: 620 ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], 621 reg_value.GetBytes(), reg_value.GetByteSize()); 622 break; 623 case lldb_dr0_x86_64: 624 case lldb_dr1_x86_64: 625 case lldb_dr2_x86_64: 626 case lldb_dr3_x86_64: 627 case lldb_dr4_x86_64: 628 case lldb_dr5_x86_64: 629 case lldb_dr6_x86_64: 630 case lldb_dr7_x86_64: 631 m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64(); 632 break; 633 } 634 635 if (WriteRegisterSet(set) != 0) 636 error.SetErrorStringWithFormat("failed to write register set"); 637 638 return error; 639 } 640 641 Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues( 642 lldb::DataBufferSP &data_sp) { 643 Status error; 644 645 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 646 if (!data_sp) { 647 error.SetErrorStringWithFormat( 648 "failed to allocate DataBufferHeap instance of size %" PRIu64, 649 REG_CONTEXT_SIZE); 650 return error; 651 } 652 653 error = ReadGPR(); 654 if (error.Fail()) 655 return error; 656 657 uint8_t *dst = data_sp->GetBytes(); 658 if (dst == nullptr) { 659 error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 660 " returned a null pointer", 661 REG_CONTEXT_SIZE); 662 return error; 663 } 664 665 ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize()); 666 dst += GetRegisterInfoInterface().GetGPRSize(); 667 668 RegisterValue value((uint64_t)-1); 669 const RegisterInfo *reg_info = 670 GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax"); 671 if (reg_info == nullptr) 672 reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax"); 673 return error; 674 } 675 676 Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( 677 const lldb::DataBufferSP &data_sp) { 678 Status error; 679 680 if (!data_sp) { 681 error.SetErrorStringWithFormat( 682 "NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided", 683 __FUNCTION__); 684 return error; 685 } 686 687 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 688 error.SetErrorStringWithFormat( 689 "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched " 690 "data size, expected %" PRIu64 ", actual %" PRIu64, 691 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 692 return error; 693 } 694 695 uint8_t *src = data_sp->GetBytes(); 696 if (src == nullptr) { 697 error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s " 698 "DataBuffer::GetBytes() returned a null " 699 "pointer", 700 __FUNCTION__); 701 return error; 702 } 703 ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize()); 704 705 error = WriteGPR(); 706 if (error.Fail()) 707 return error; 708 src += GetRegisterInfoInterface().GetGPRSize(); 709 710 return error; 711 } 712 713 Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index, 714 bool &is_hit) { 715 if (wp_index >= NumSupportedHardwareWatchpoints()) 716 return Status("Watchpoint index out of range"); 717 718 RegisterValue reg_value; 719 const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64); 720 Status error = ReadRegister(reg_info, reg_value); 721 if (error.Fail()) { 722 is_hit = false; 723 return error; 724 } 725 726 uint64_t status_bits = reg_value.GetAsUInt64(); 727 728 is_hit = status_bits & (1 << wp_index); 729 730 return error; 731 } 732 733 Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex( 734 uint32_t &wp_index, lldb::addr_t trap_addr) { 735 uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); 736 for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { 737 bool is_hit; 738 Status error = IsWatchpointHit(wp_index, is_hit); 739 if (error.Fail()) { 740 wp_index = LLDB_INVALID_INDEX32; 741 return error; 742 } else if (is_hit) { 743 return error; 744 } 745 } 746 wp_index = LLDB_INVALID_INDEX32; 747 return Status(); 748 } 749 750 Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index, 751 bool &is_vacant) { 752 if (wp_index >= NumSupportedHardwareWatchpoints()) 753 return Status("Watchpoint index out of range"); 754 755 RegisterValue reg_value; 756 const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64); 757 Status error = ReadRegister(reg_info, reg_value); 758 if (error.Fail()) { 759 is_vacant = false; 760 return error; 761 } 762 763 uint64_t control_bits = reg_value.GetAsUInt64(); 764 765 is_vacant = !(control_bits & (1 << (2 * wp_index))); 766 767 return error; 768 } 769 770 Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( 771 lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { 772 773 if (wp_index >= NumSupportedHardwareWatchpoints()) 774 return Status("Watchpoint index out of range"); 775 776 // Read only watchpoints aren't supported on x86_64. Fall back to read/write 777 // waitchpoints instead. 778 // TODO: Add logic to detect when a write happens and ignore that watchpoint 779 // hit. 780 if (watch_flags == 0x2) 781 watch_flags = 0x3; 782 783 if (watch_flags != 0x1 && watch_flags != 0x3) 784 return Status("Invalid read/write bits for watchpoint"); 785 786 if (size != 1 && size != 2 && size != 4 && size != 8) 787 return Status("Invalid size for watchpoint"); 788 789 bool is_vacant; 790 Status error = IsWatchpointVacant(wp_index, is_vacant); 791 if (error.Fail()) 792 return error; 793 if (!is_vacant) 794 return Status("Watchpoint index not vacant"); 795 796 RegisterValue reg_value; 797 const RegisterInfo *const reg_info_dr7 = 798 GetRegisterInfoAtIndex(lldb_dr7_x86_64); 799 error = ReadRegister(reg_info_dr7, reg_value); 800 if (error.Fail()) 801 return error; 802 803 // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 804 uint64_t enable_bit = 1 << (2 * wp_index); 805 806 // set bits 16-17, 20-21, 24-25, or 28-29 807 // with 0b01 for write, and 0b11 for read/write 808 uint64_t rw_bits = watch_flags << (16 + 4 * wp_index); 809 810 // set bits 18-19, 22-23, 26-27, or 30-31 811 // with 0b00, 0b01, 0b10, or 0b11 812 // for 1, 2, 8 (if supported), or 4 bytes, respectively 813 uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); 814 815 uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 816 817 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 818 819 control_bits |= enable_bit | rw_bits | size_bits; 820 821 const RegisterInfo *const reg_info_drN = 822 GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index); 823 error = WriteRegister(reg_info_drN, RegisterValue(addr)); 824 if (error.Fail()) 825 return error; 826 827 error = WriteRegister(reg_info_dr7, RegisterValue(control_bits)); 828 if (error.Fail()) 829 return error; 830 831 error.Clear(); 832 return error; 833 } 834 835 bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( 836 uint32_t wp_index) { 837 if (wp_index >= NumSupportedHardwareWatchpoints()) 838 return false; 839 840 RegisterValue reg_value; 841 842 // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of 843 // the debug status register (DR6) 844 const RegisterInfo *const reg_info_dr6 = 845 GetRegisterInfoAtIndex(lldb_dr6_x86_64); 846 Status error = ReadRegister(reg_info_dr6, reg_value); 847 if (error.Fail()) 848 return false; 849 uint64_t bit_mask = 1 << wp_index; 850 uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; 851 error = WriteRegister(reg_info_dr6, RegisterValue(status_bits)); 852 if (error.Fail()) 853 return false; 854 855 // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, 856 // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register 857 // (DR7) 858 const RegisterInfo *const reg_info_dr7 = 859 GetRegisterInfoAtIndex(lldb_dr7_x86_64); 860 error = ReadRegister(reg_info_dr7, reg_value); 861 if (error.Fail()) 862 return false; 863 bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 864 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 865 return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success(); 866 } 867 868 Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() { 869 RegisterValue reg_value; 870 871 // clear bits {0-4} of the debug status register (DR6) 872 const RegisterInfo *const reg_info_dr6 = 873 GetRegisterInfoAtIndex(lldb_dr6_x86_64); 874 Status error = ReadRegister(reg_info_dr6, reg_value); 875 if (error.Fail()) 876 return error; 877 uint64_t bit_mask = 0xF; 878 uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; 879 error = WriteRegister(reg_info_dr6, RegisterValue(status_bits)); 880 if (error.Fail()) 881 return error; 882 883 // clear bits {0-7,16-31} of the debug control register (DR7) 884 const RegisterInfo *const reg_info_dr7 = 885 GetRegisterInfoAtIndex(lldb_dr7_x86_64); 886 error = ReadRegister(reg_info_dr7, reg_value); 887 if (error.Fail()) 888 return error; 889 bit_mask = 0xFF | (0xFFFF << 16); 890 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 891 return WriteRegister(reg_info_dr7, RegisterValue(control_bits)); 892 } 893 894 uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint( 895 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 896 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 897 const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); 898 for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) { 899 bool is_vacant; 900 Status error = IsWatchpointVacant(wp_index, is_vacant); 901 if (is_vacant) { 902 error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); 903 if (error.Success()) 904 return wp_index; 905 } 906 if (error.Fail() && log) { 907 log->Printf("NativeRegisterContextNetBSD_x86_64::%s Error: %s", 908 __FUNCTION__, error.AsCString()); 909 } 910 } 911 return LLDB_INVALID_INDEX32; 912 } 913 914 lldb::addr_t 915 NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) { 916 if (wp_index >= NumSupportedHardwareWatchpoints()) 917 return LLDB_INVALID_ADDRESS; 918 RegisterValue reg_value; 919 const RegisterInfo *const reg_info_drN = 920 GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index); 921 if (ReadRegister(reg_info_drN, reg_value).Fail()) 922 return LLDB_INVALID_ADDRESS; 923 return reg_value.GetAsUInt64(); 924 } 925 926 uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() { 927 // Available debug address registers: dr0, dr1, dr2, dr3 928 return 4; 929 } 930 931 #endif // defined(__x86_64__) 932