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 Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) { 214 switch (set) { 215 case GPRegSet: 216 return ReadGPR(); 217 case FPRegSet: 218 return ReadFPR(); 219 case DBRegSet: 220 return ReadDBR(); 221 } 222 llvm_unreachable("NativeRegisterContextNetBSD_x86_64::ReadRegisterSet"); 223 } 224 225 Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) { 226 switch (set) { 227 case GPRegSet: 228 return WriteGPR(); 229 case FPRegSet: 230 return WriteFPR(); 231 case DBRegSet: 232 return WriteDBR(); 233 } 234 llvm_unreachable("NativeRegisterContextNetBSD_x86_64::WriteRegisterSet"); 235 } 236 237 Status 238 NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, 239 RegisterValue ®_value) { 240 Status error; 241 242 if (!reg_info) { 243 error.SetErrorString("reg_info NULL"); 244 return error; 245 } 246 247 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 248 if (reg == LLDB_INVALID_REGNUM) { 249 // This is likely an internal register for lldb use only and should not be 250 // directly queried. 251 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 252 "register, cannot read directly", 253 reg_info->name); 254 return error; 255 } 256 257 int set = GetSetForNativeRegNum(reg); 258 if (set == -1) { 259 // This is likely an internal register for lldb use only and should not be 260 // directly queried. 261 error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 262 reg_info->name); 263 return error; 264 } 265 266 error = ReadRegisterSet(set); 267 if (error.Fail()) 268 return error; 269 270 switch (reg) { 271 case lldb_rax_x86_64: 272 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX]; 273 break; 274 case lldb_rbx_x86_64: 275 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX]; 276 break; 277 case lldb_rcx_x86_64: 278 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX]; 279 break; 280 case lldb_rdx_x86_64: 281 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX]; 282 break; 283 case lldb_rdi_x86_64: 284 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI]; 285 break; 286 case lldb_rsi_x86_64: 287 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI]; 288 break; 289 case lldb_rbp_x86_64: 290 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP]; 291 break; 292 case lldb_rsp_x86_64: 293 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP]; 294 break; 295 case lldb_r8_x86_64: 296 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8]; 297 break; 298 case lldb_r9_x86_64: 299 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9]; 300 break; 301 case lldb_r10_x86_64: 302 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10]; 303 break; 304 case lldb_r11_x86_64: 305 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11]; 306 break; 307 case lldb_r12_x86_64: 308 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12]; 309 break; 310 case lldb_r13_x86_64: 311 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13]; 312 break; 313 case lldb_r14_x86_64: 314 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14]; 315 break; 316 case lldb_r15_x86_64: 317 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15]; 318 break; 319 case lldb_rip_x86_64: 320 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP]; 321 break; 322 case lldb_rflags_x86_64: 323 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS]; 324 break; 325 case lldb_cs_x86_64: 326 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS]; 327 break; 328 case lldb_fs_x86_64: 329 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS]; 330 break; 331 case lldb_gs_x86_64: 332 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS]; 333 break; 334 case lldb_ss_x86_64: 335 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS]; 336 break; 337 case lldb_ds_x86_64: 338 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS]; 339 break; 340 case lldb_es_x86_64: 341 reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES]; 342 break; 343 case lldb_fctrl_x86_64: 344 reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_cw; 345 break; 346 case lldb_fstat_x86_64: 347 reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_sw; 348 break; 349 case lldb_ftag_x86_64: 350 reg_value = (uint8_t)m_fpr_x86_64.fxstate.fx_tw; 351 break; 352 case lldb_fop_x86_64: 353 reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_opcode; 354 break; 355 case lldb_fiseg_x86_64: 356 reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_ip.fa_64; 357 break; 358 case lldb_fioff_x86_64: 359 reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off; 360 break; 361 case lldb_foseg_x86_64: 362 reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_dp.fa_64; 363 break; 364 case lldb_fooff_x86_64: 365 reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off; 366 break; 367 case lldb_mxcsr_x86_64: 368 reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr; 369 break; 370 case lldb_mxcsrmask_x86_64: 371 reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr_mask; 372 break; 373 case lldb_st0_x86_64: 374 case lldb_st1_x86_64: 375 case lldb_st2_x86_64: 376 case lldb_st3_x86_64: 377 case lldb_st4_x86_64: 378 case lldb_st5_x86_64: 379 case lldb_st6_x86_64: 380 case lldb_st7_x86_64: 381 reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64], 382 reg_info->byte_size, endian::InlHostByteOrder()); 383 break; 384 case lldb_mm0_x86_64: 385 case lldb_mm1_x86_64: 386 case lldb_mm2_x86_64: 387 case lldb_mm3_x86_64: 388 case lldb_mm4_x86_64: 389 case lldb_mm5_x86_64: 390 case lldb_mm6_x86_64: 391 case lldb_mm7_x86_64: 392 reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], 393 reg_info->byte_size, endian::InlHostByteOrder()); 394 break; 395 case lldb_xmm0_x86_64: 396 case lldb_xmm1_x86_64: 397 case lldb_xmm2_x86_64: 398 case lldb_xmm3_x86_64: 399 case lldb_xmm4_x86_64: 400 case lldb_xmm5_x86_64: 401 case lldb_xmm6_x86_64: 402 case lldb_xmm7_x86_64: 403 case lldb_xmm8_x86_64: 404 case lldb_xmm9_x86_64: 405 case lldb_xmm10_x86_64: 406 case lldb_xmm11_x86_64: 407 case lldb_xmm12_x86_64: 408 case lldb_xmm13_x86_64: 409 case lldb_xmm14_x86_64: 410 case lldb_xmm15_x86_64: 411 reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], 412 reg_info->byte_size, endian::InlHostByteOrder()); 413 break; 414 case lldb_dr0_x86_64: 415 case lldb_dr1_x86_64: 416 case lldb_dr2_x86_64: 417 case lldb_dr3_x86_64: 418 case lldb_dr4_x86_64: 419 case lldb_dr5_x86_64: 420 case lldb_dr6_x86_64: 421 case lldb_dr7_x86_64: 422 reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64]; 423 break; 424 } 425 426 return error; 427 } 428 429 Status NativeRegisterContextNetBSD_x86_64::WriteRegister( 430 const RegisterInfo *reg_info, const RegisterValue ®_value) { 431 432 Status error; 433 434 if (!reg_info) { 435 error.SetErrorString("reg_info NULL"); 436 return error; 437 } 438 439 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 440 if (reg == LLDB_INVALID_REGNUM) { 441 // This is likely an internal register for lldb use only and should not be 442 // directly queried. 443 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 444 "register, cannot read directly", 445 reg_info->name); 446 return error; 447 } 448 449 int set = GetSetForNativeRegNum(reg); 450 if (set == -1) { 451 // This is likely an internal register for lldb use only and should not be 452 // directly queried. 453 error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 454 reg_info->name); 455 return error; 456 } 457 458 error = ReadRegisterSet(set); 459 if (error.Fail()) 460 return error; 461 462 switch (reg) { 463 case lldb_rax_x86_64: 464 m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64(); 465 break; 466 case lldb_rbx_x86_64: 467 m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64(); 468 break; 469 case lldb_rcx_x86_64: 470 m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64(); 471 break; 472 case lldb_rdx_x86_64: 473 m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64(); 474 break; 475 case lldb_rdi_x86_64: 476 m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64(); 477 break; 478 case lldb_rsi_x86_64: 479 m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64(); 480 break; 481 case lldb_rbp_x86_64: 482 m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64(); 483 break; 484 case lldb_rsp_x86_64: 485 m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64(); 486 break; 487 case lldb_r8_x86_64: 488 m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64(); 489 break; 490 case lldb_r9_x86_64: 491 m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64(); 492 break; 493 case lldb_r10_x86_64: 494 m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64(); 495 break; 496 case lldb_r11_x86_64: 497 m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64(); 498 break; 499 case lldb_r12_x86_64: 500 m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64(); 501 break; 502 case lldb_r13_x86_64: 503 m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64(); 504 break; 505 case lldb_r14_x86_64: 506 m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64(); 507 break; 508 case lldb_r15_x86_64: 509 m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64(); 510 break; 511 case lldb_rip_x86_64: 512 m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64(); 513 break; 514 case lldb_rflags_x86_64: 515 m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64(); 516 break; 517 case lldb_cs_x86_64: 518 m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64(); 519 break; 520 case lldb_fs_x86_64: 521 m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64(); 522 break; 523 case lldb_gs_x86_64: 524 m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64(); 525 break; 526 case lldb_ss_x86_64: 527 m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64(); 528 break; 529 case lldb_ds_x86_64: 530 m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64(); 531 break; 532 case lldb_es_x86_64: 533 m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64(); 534 break; 535 case lldb_fctrl_x86_64: 536 m_fpr_x86_64.fxstate.fx_cw = reg_value.GetAsUInt16(); 537 break; 538 case lldb_fstat_x86_64: 539 m_fpr_x86_64.fxstate.fx_sw = reg_value.GetAsUInt16(); 540 break; 541 case lldb_ftag_x86_64: 542 m_fpr_x86_64.fxstate.fx_tw = reg_value.GetAsUInt8(); 543 break; 544 case lldb_fop_x86_64: 545 m_fpr_x86_64.fxstate.fx_opcode = reg_value.GetAsUInt16(); 546 break; 547 case lldb_fiseg_x86_64: 548 m_fpr_x86_64.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64(); 549 break; 550 case lldb_fioff_x86_64: 551 m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32(); 552 break; 553 case lldb_foseg_x86_64: 554 m_fpr_x86_64.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64(); 555 break; 556 case lldb_fooff_x86_64: 557 m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32(); 558 break; 559 case lldb_mxcsr_x86_64: 560 m_fpr_x86_64.fxstate.fx_mxcsr = reg_value.GetAsUInt32(); 561 break; 562 case lldb_mxcsrmask_x86_64: 563 m_fpr_x86_64.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32(); 564 break; 565 case lldb_st0_x86_64: 566 case lldb_st1_x86_64: 567 case lldb_st2_x86_64: 568 case lldb_st3_x86_64: 569 case lldb_st4_x86_64: 570 case lldb_st5_x86_64: 571 case lldb_st6_x86_64: 572 case lldb_st7_x86_64: 573 ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64], 574 reg_value.GetBytes(), reg_value.GetByteSize()); 575 break; 576 case lldb_mm0_x86_64: 577 case lldb_mm1_x86_64: 578 case lldb_mm2_x86_64: 579 case lldb_mm3_x86_64: 580 case lldb_mm4_x86_64: 581 case lldb_mm5_x86_64: 582 case lldb_mm6_x86_64: 583 case lldb_mm7_x86_64: 584 ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], 585 reg_value.GetBytes(), reg_value.GetByteSize()); 586 break; 587 case lldb_xmm0_x86_64: 588 case lldb_xmm1_x86_64: 589 case lldb_xmm2_x86_64: 590 case lldb_xmm3_x86_64: 591 case lldb_xmm4_x86_64: 592 case lldb_xmm5_x86_64: 593 case lldb_xmm6_x86_64: 594 case lldb_xmm7_x86_64: 595 case lldb_xmm8_x86_64: 596 case lldb_xmm9_x86_64: 597 case lldb_xmm10_x86_64: 598 case lldb_xmm11_x86_64: 599 case lldb_xmm12_x86_64: 600 case lldb_xmm13_x86_64: 601 case lldb_xmm14_x86_64: 602 case lldb_xmm15_x86_64: 603 ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], 604 reg_value.GetBytes(), reg_value.GetByteSize()); 605 break; 606 case lldb_dr0_x86_64: 607 case lldb_dr1_x86_64: 608 case lldb_dr2_x86_64: 609 case lldb_dr3_x86_64: 610 case lldb_dr4_x86_64: 611 case lldb_dr5_x86_64: 612 case lldb_dr6_x86_64: 613 case lldb_dr7_x86_64: 614 m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64(); 615 break; 616 } 617 618 return WriteRegisterSet(set); 619 } 620 621 Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues( 622 lldb::DataBufferSP &data_sp) { 623 Status error; 624 625 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 626 if (!data_sp) { 627 error.SetErrorStringWithFormat( 628 "failed to allocate DataBufferHeap instance of size %" PRIu64, 629 REG_CONTEXT_SIZE); 630 return error; 631 } 632 633 error = ReadGPR(); 634 if (error.Fail()) 635 return error; 636 637 uint8_t *dst = data_sp->GetBytes(); 638 if (dst == nullptr) { 639 error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 640 " returned a null pointer", 641 REG_CONTEXT_SIZE); 642 return error; 643 } 644 645 ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize()); 646 dst += GetRegisterInfoInterface().GetGPRSize(); 647 648 RegisterValue value((uint64_t)-1); 649 const RegisterInfo *reg_info = 650 GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax"); 651 if (reg_info == nullptr) 652 reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax"); 653 return error; 654 } 655 656 Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( 657 const lldb::DataBufferSP &data_sp) { 658 Status error; 659 660 if (!data_sp) { 661 error.SetErrorStringWithFormat( 662 "NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided", 663 __FUNCTION__); 664 return error; 665 } 666 667 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 668 error.SetErrorStringWithFormat( 669 "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched " 670 "data size, expected %" PRIu64 ", actual %" PRIu64, 671 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 672 return error; 673 } 674 675 uint8_t *src = data_sp->GetBytes(); 676 if (src == nullptr) { 677 error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s " 678 "DataBuffer::GetBytes() returned a null " 679 "pointer", 680 __FUNCTION__); 681 return error; 682 } 683 ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize()); 684 685 error = WriteGPR(); 686 if (error.Fail()) 687 return error; 688 src += GetRegisterInfoInterface().GetGPRSize(); 689 690 return error; 691 } 692 693 Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index, 694 bool &is_hit) { 695 if (wp_index >= NumSupportedHardwareWatchpoints()) 696 return Status("Watchpoint index out of range"); 697 698 RegisterValue reg_value; 699 const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64); 700 Status error = ReadRegister(reg_info, reg_value); 701 if (error.Fail()) { 702 is_hit = false; 703 return error; 704 } 705 706 uint64_t status_bits = reg_value.GetAsUInt64(); 707 708 is_hit = status_bits & (1 << wp_index); 709 710 return error; 711 } 712 713 Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex( 714 uint32_t &wp_index, lldb::addr_t trap_addr) { 715 uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); 716 for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { 717 bool is_hit; 718 Status error = IsWatchpointHit(wp_index, is_hit); 719 if (error.Fail()) { 720 wp_index = LLDB_INVALID_INDEX32; 721 return error; 722 } else if (is_hit) { 723 return error; 724 } 725 } 726 wp_index = LLDB_INVALID_INDEX32; 727 return Status(); 728 } 729 730 Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index, 731 bool &is_vacant) { 732 if (wp_index >= NumSupportedHardwareWatchpoints()) 733 return Status("Watchpoint index out of range"); 734 735 RegisterValue reg_value; 736 const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64); 737 Status error = ReadRegister(reg_info, reg_value); 738 if (error.Fail()) { 739 is_vacant = false; 740 return error; 741 } 742 743 uint64_t control_bits = reg_value.GetAsUInt64(); 744 745 is_vacant = !(control_bits & (1 << (2 * wp_index))); 746 747 return error; 748 } 749 750 Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( 751 lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { 752 753 if (wp_index >= NumSupportedHardwareWatchpoints()) 754 return Status("Watchpoint index out of range"); 755 756 // Read only watchpoints aren't supported on x86_64. Fall back to read/write 757 // waitchpoints instead. 758 // TODO: Add logic to detect when a write happens and ignore that watchpoint 759 // hit. 760 if (watch_flags == 0x2) 761 watch_flags = 0x3; 762 763 if (watch_flags != 0x1 && watch_flags != 0x3) 764 return Status("Invalid read/write bits for watchpoint"); 765 766 if (size != 1 && size != 2 && size != 4 && size != 8) 767 return Status("Invalid size for watchpoint"); 768 769 bool is_vacant; 770 Status error = IsWatchpointVacant(wp_index, is_vacant); 771 if (error.Fail()) 772 return error; 773 if (!is_vacant) 774 return Status("Watchpoint index not vacant"); 775 776 RegisterValue reg_value; 777 const RegisterInfo *const reg_info_dr7 = 778 GetRegisterInfoAtIndex(lldb_dr7_x86_64); 779 error = ReadRegister(reg_info_dr7, reg_value); 780 if (error.Fail()) 781 return error; 782 783 // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 784 uint64_t enable_bit = 1 << (2 * wp_index); 785 786 // set bits 16-17, 20-21, 24-25, or 28-29 787 // with 0b01 for write, and 0b11 for read/write 788 uint64_t rw_bits = watch_flags << (16 + 4 * wp_index); 789 790 // set bits 18-19, 22-23, 26-27, or 30-31 791 // with 0b00, 0b01, 0b10, or 0b11 792 // for 1, 2, 8 (if supported), or 4 bytes, respectively 793 uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); 794 795 uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 796 797 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 798 799 control_bits |= enable_bit | rw_bits | size_bits; 800 801 const RegisterInfo *const reg_info_drN = 802 GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index); 803 error = WriteRegister(reg_info_drN, RegisterValue(addr)); 804 if (error.Fail()) 805 return error; 806 807 error = WriteRegister(reg_info_dr7, RegisterValue(control_bits)); 808 if (error.Fail()) 809 return error; 810 811 error.Clear(); 812 return error; 813 } 814 815 bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( 816 uint32_t wp_index) { 817 if (wp_index >= NumSupportedHardwareWatchpoints()) 818 return false; 819 820 RegisterValue reg_value; 821 822 // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of 823 // the debug status register (DR6) 824 const RegisterInfo *const reg_info_dr6 = 825 GetRegisterInfoAtIndex(lldb_dr6_x86_64); 826 Status error = ReadRegister(reg_info_dr6, reg_value); 827 if (error.Fail()) 828 return false; 829 uint64_t bit_mask = 1 << wp_index; 830 uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; 831 error = WriteRegister(reg_info_dr6, RegisterValue(status_bits)); 832 if (error.Fail()) 833 return false; 834 835 // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, 836 // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register 837 // (DR7) 838 const RegisterInfo *const reg_info_dr7 = 839 GetRegisterInfoAtIndex(lldb_dr7_x86_64); 840 error = ReadRegister(reg_info_dr7, reg_value); 841 if (error.Fail()) 842 return false; 843 bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 844 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 845 return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success(); 846 } 847 848 Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() { 849 RegisterValue reg_value; 850 851 // clear bits {0-4} of the debug status register (DR6) 852 const RegisterInfo *const reg_info_dr6 = 853 GetRegisterInfoAtIndex(lldb_dr6_x86_64); 854 Status error = ReadRegister(reg_info_dr6, reg_value); 855 if (error.Fail()) 856 return error; 857 uint64_t bit_mask = 0xF; 858 uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; 859 error = WriteRegister(reg_info_dr6, RegisterValue(status_bits)); 860 if (error.Fail()) 861 return error; 862 863 // clear bits {0-7,16-31} of the debug control register (DR7) 864 const RegisterInfo *const reg_info_dr7 = 865 GetRegisterInfoAtIndex(lldb_dr7_x86_64); 866 error = ReadRegister(reg_info_dr7, reg_value); 867 if (error.Fail()) 868 return error; 869 bit_mask = 0xFF | (0xFFFF << 16); 870 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 871 return WriteRegister(reg_info_dr7, RegisterValue(control_bits)); 872 } 873 874 uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint( 875 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 876 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 877 const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); 878 for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) { 879 bool is_vacant; 880 Status error = IsWatchpointVacant(wp_index, is_vacant); 881 if (is_vacant) { 882 error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); 883 if (error.Success()) 884 return wp_index; 885 } 886 if (error.Fail() && log) { 887 log->Printf("NativeRegisterContextNetBSD_x86_64::%s Error: %s", 888 __FUNCTION__, error.AsCString()); 889 } 890 } 891 return LLDB_INVALID_INDEX32; 892 } 893 894 lldb::addr_t 895 NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) { 896 if (wp_index >= NumSupportedHardwareWatchpoints()) 897 return LLDB_INVALID_ADDRESS; 898 RegisterValue reg_value; 899 const RegisterInfo *const reg_info_drN = 900 GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index); 901 if (ReadRegister(reg_info_drN, reg_value).Fail()) 902 return LLDB_INVALID_ADDRESS; 903 return reg_value.GetAsUInt64(); 904 } 905 906 uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() { 907 // Available debug address registers: dr0, dr1, dr2, dr3 908 return 4; 909 } 910 911 #endif // defined(__x86_64__) 912