1 //===-- NativeRegisterContextWindows_x86_64.cpp ---------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #if defined(__x86_64__) || defined(_M_X64) 10 11 #include "NativeRegisterContextWindows_x86_64.h" 12 #include "NativeRegisterContextWindows_WoW64.h" 13 #include "NativeThreadWindows.h" 14 #include "Plugins/Process/Utility/RegisterContextWindows_i386.h" 15 #include "Plugins/Process/Utility/RegisterContextWindows_x86_64.h" 16 #include "ProcessWindowsLog.h" 17 #include "lldb/Host/HostInfo.h" 18 #include "lldb/Host/HostThread.h" 19 #include "lldb/Host/windows/HostThreadWindows.h" 20 #include "lldb/Host/windows/windows.h" 21 22 #include "lldb/Utility/Log.h" 23 #include "lldb/Utility/RegisterValue.h" 24 #include "llvm/ADT/STLExtras.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 #define REG_CONTEXT_SIZE sizeof(::CONTEXT) 30 31 namespace { 32 static const uint32_t g_gpr_regnums_x86_64[] = { 33 lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, 34 lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64, 35 lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64, 36 lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64, 37 lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64, 38 lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64, 39 LLDB_INVALID_REGNUM // Register set must be terminated with this flag 40 }; 41 42 static const uint32_t g_fpr_regnums_x86_64[] = { 43 lldb_xmm0_x86_64, lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, 44 lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64, 45 lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64, lldb_xmm11_x86_64, 46 lldb_xmm12_x86_64, lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, 47 LLDB_INVALID_REGNUM // Register set must be terminated with this flag 48 }; 49 50 static const RegisterSet g_reg_sets_x86_64[] = { 51 {"General Purpose Registers", "gpr", 52 llvm::array_lengthof(g_gpr_regnums_x86_64) - 1, g_gpr_regnums_x86_64}, 53 {"Floating Point Registers", "fpr", 54 llvm::array_lengthof(g_fpr_regnums_x86_64) - 1, g_fpr_regnums_x86_64}}; 55 56 enum { k_num_register_sets = 2 }; 57 58 } // namespace 59 60 static RegisterInfoInterface * 61 CreateRegisterInfoInterface(const ArchSpec &target_arch) { 62 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 63 "Register setting path assumes this is a 64-bit host"); 64 return new RegisterContextWindows_x86_64(target_arch); 65 } 66 67 static Status GetThreadContextHelper(lldb::thread_t thread_handle, 68 PCONTEXT context_ptr, 69 const DWORD control_flag) { 70 Log *log = GetLog(WindowsLog::Registers); 71 Status error; 72 73 memset(context_ptr, 0, sizeof(::CONTEXT)); 74 context_ptr->ContextFlags = control_flag; 75 if (!::GetThreadContext(thread_handle, context_ptr)) { 76 error.SetError(GetLastError(), eErrorTypeWin32); 77 LLDB_LOG(log, "{0} GetThreadContext failed with error {1}", __FUNCTION__, 78 error); 79 return error; 80 } 81 return Status(); 82 } 83 84 static Status SetThreadContextHelper(lldb::thread_t thread_handle, 85 PCONTEXT context_ptr) { 86 Log *log = GetLog(WindowsLog::Registers); 87 Status error; 88 // It's assumed that the thread has stopped. 89 if (!::SetThreadContext(thread_handle, context_ptr)) { 90 error.SetError(GetLastError(), eErrorTypeWin32); 91 LLDB_LOG(log, "{0} SetThreadContext failed with error {1}", __FUNCTION__, 92 error); 93 return error; 94 } 95 return Status(); 96 } 97 98 std::unique_ptr<NativeRegisterContextWindows> 99 NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows( 100 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 101 // Register context for a WoW64 application. 102 if (target_arch.GetAddressByteSize() == 4) 103 return std::make_unique<NativeRegisterContextWindows_WoW64>(target_arch, 104 native_thread); 105 106 // Register context for a native 64-bit application. 107 return std::make_unique<NativeRegisterContextWindows_x86_64>(target_arch, 108 native_thread); 109 } 110 111 NativeRegisterContextWindows_x86_64::NativeRegisterContextWindows_x86_64( 112 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 113 : NativeRegisterContextWindows(native_thread, 114 CreateRegisterInfoInterface(target_arch)) {} 115 116 bool NativeRegisterContextWindows_x86_64::IsGPR(uint32_t reg_index) const { 117 return (reg_index >= k_first_gpr_x86_64 && reg_index < k_first_alias_x86_64); 118 } 119 120 bool NativeRegisterContextWindows_x86_64::IsFPR(uint32_t reg_index) const { 121 return (reg_index >= lldb_xmm0_x86_64 && reg_index <= k_last_fpr_x86_64); 122 } 123 124 bool NativeRegisterContextWindows_x86_64::IsDR(uint32_t reg_index) const { 125 return (reg_index >= lldb_dr0_x86_64 && reg_index <= lldb_dr7_x86_64); 126 } 127 128 uint32_t NativeRegisterContextWindows_x86_64::GetRegisterSetCount() const { 129 return k_num_register_sets; 130 } 131 132 const RegisterSet * 133 NativeRegisterContextWindows_x86_64::GetRegisterSet(uint32_t set_index) const { 134 if (set_index >= k_num_register_sets) 135 return nullptr; 136 return &g_reg_sets_x86_64[set_index]; 137 } 138 139 Status NativeRegisterContextWindows_x86_64::GPRRead(const uint32_t reg, 140 RegisterValue ®_value) { 141 ::CONTEXT tls_context; 142 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; 143 Status error = 144 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag); 145 if (error.Fail()) 146 return error; 147 148 switch (reg) { 149 case lldb_rax_x86_64: 150 reg_value.SetUInt64(tls_context.Rax); 151 break; 152 case lldb_rbx_x86_64: 153 reg_value.SetUInt64(tls_context.Rbx); 154 break; 155 case lldb_rcx_x86_64: 156 reg_value.SetUInt64(tls_context.Rcx); 157 break; 158 case lldb_rdx_x86_64: 159 reg_value.SetUInt64(tls_context.Rdx); 160 break; 161 case lldb_rdi_x86_64: 162 reg_value.SetUInt64(tls_context.Rdi); 163 break; 164 case lldb_rsi_x86_64: 165 reg_value.SetUInt64(tls_context.Rsi); 166 break; 167 case lldb_rbp_x86_64: 168 reg_value.SetUInt64(tls_context.Rbp); 169 break; 170 case lldb_rsp_x86_64: 171 reg_value.SetUInt64(tls_context.Rsp); 172 break; 173 case lldb_r8_x86_64: 174 reg_value.SetUInt64(tls_context.R8); 175 break; 176 case lldb_r9_x86_64: 177 reg_value.SetUInt64(tls_context.R9); 178 break; 179 case lldb_r10_x86_64: 180 reg_value.SetUInt64(tls_context.R10); 181 break; 182 case lldb_r11_x86_64: 183 reg_value.SetUInt64(tls_context.R11); 184 break; 185 case lldb_r12_x86_64: 186 reg_value.SetUInt64(tls_context.R12); 187 break; 188 case lldb_r13_x86_64: 189 reg_value.SetUInt64(tls_context.R13); 190 break; 191 case lldb_r14_x86_64: 192 reg_value.SetUInt64(tls_context.R14); 193 break; 194 case lldb_r15_x86_64: 195 reg_value.SetUInt64(tls_context.R15); 196 break; 197 case lldb_rip_x86_64: 198 reg_value.SetUInt64(tls_context.Rip); 199 break; 200 case lldb_rflags_x86_64: 201 reg_value.SetUInt64(tls_context.EFlags | 0x2); // Bit #1 always 1 202 break; 203 case lldb_cs_x86_64: 204 reg_value.SetUInt16(tls_context.SegCs); 205 break; 206 case lldb_fs_x86_64: 207 reg_value.SetUInt16(tls_context.SegFs); 208 break; 209 case lldb_gs_x86_64: 210 reg_value.SetUInt16(tls_context.SegGs); 211 break; 212 case lldb_ss_x86_64: 213 reg_value.SetUInt16(tls_context.SegSs); 214 break; 215 case lldb_ds_x86_64: 216 reg_value.SetUInt16(tls_context.SegDs); 217 break; 218 case lldb_es_x86_64: 219 reg_value.SetUInt16(tls_context.SegEs); 220 break; 221 } 222 223 return error; 224 } 225 226 Status 227 NativeRegisterContextWindows_x86_64::GPRWrite(const uint32_t reg, 228 const RegisterValue ®_value) { 229 ::CONTEXT tls_context; 230 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; 231 auto thread_handle = GetThreadHandle(); 232 Status error = 233 GetThreadContextHelper(thread_handle, &tls_context, context_flag); 234 if (error.Fail()) 235 return error; 236 237 switch (reg) { 238 case lldb_rax_x86_64: 239 tls_context.Rax = reg_value.GetAsUInt64(); 240 break; 241 case lldb_rbx_x86_64: 242 tls_context.Rbx = reg_value.GetAsUInt64(); 243 break; 244 case lldb_rcx_x86_64: 245 tls_context.Rcx = reg_value.GetAsUInt64(); 246 break; 247 case lldb_rdx_x86_64: 248 tls_context.Rdx = reg_value.GetAsUInt64(); 249 break; 250 case lldb_rdi_x86_64: 251 tls_context.Rdi = reg_value.GetAsUInt64(); 252 break; 253 case lldb_rsi_x86_64: 254 tls_context.Rsi = reg_value.GetAsUInt64(); 255 break; 256 case lldb_rbp_x86_64: 257 tls_context.Rbp = reg_value.GetAsUInt64(); 258 break; 259 case lldb_rsp_x86_64: 260 tls_context.Rsp = reg_value.GetAsUInt64(); 261 break; 262 case lldb_r8_x86_64: 263 tls_context.R8 = reg_value.GetAsUInt64(); 264 break; 265 case lldb_r9_x86_64: 266 tls_context.R9 = reg_value.GetAsUInt64(); 267 break; 268 case lldb_r10_x86_64: 269 tls_context.R10 = reg_value.GetAsUInt64(); 270 break; 271 case lldb_r11_x86_64: 272 tls_context.R11 = reg_value.GetAsUInt64(); 273 break; 274 case lldb_r12_x86_64: 275 tls_context.R12 = reg_value.GetAsUInt64(); 276 break; 277 case lldb_r13_x86_64: 278 tls_context.R13 = reg_value.GetAsUInt64(); 279 break; 280 case lldb_r14_x86_64: 281 tls_context.R14 = reg_value.GetAsUInt64(); 282 break; 283 case lldb_r15_x86_64: 284 tls_context.R15 = reg_value.GetAsUInt64(); 285 break; 286 case lldb_rip_x86_64: 287 tls_context.Rip = reg_value.GetAsUInt64(); 288 break; 289 case lldb_rflags_x86_64: 290 tls_context.EFlags = reg_value.GetAsUInt64(); 291 break; 292 case lldb_cs_x86_64: 293 tls_context.SegCs = reg_value.GetAsUInt16(); 294 break; 295 case lldb_fs_x86_64: 296 tls_context.SegFs = reg_value.GetAsUInt16(); 297 break; 298 case lldb_gs_x86_64: 299 tls_context.SegGs = reg_value.GetAsUInt16(); 300 break; 301 case lldb_ss_x86_64: 302 tls_context.SegSs = reg_value.GetAsUInt16(); 303 break; 304 case lldb_ds_x86_64: 305 tls_context.SegDs = reg_value.GetAsUInt16(); 306 break; 307 case lldb_es_x86_64: 308 tls_context.SegEs = reg_value.GetAsUInt16(); 309 break; 310 } 311 312 return SetThreadContextHelper(thread_handle, &tls_context); 313 } 314 315 Status NativeRegisterContextWindows_x86_64::FPRRead(const uint32_t reg, 316 RegisterValue ®_value) { 317 ::CONTEXT tls_context; 318 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_FLOATING_POINT; 319 Status error = 320 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag); 321 if (error.Fail()) 322 return error; 323 324 switch (reg) { 325 case lldb_xmm0_x86_64: 326 reg_value.SetBytes(&tls_context.Xmm0, 16, endian::InlHostByteOrder()); 327 break; 328 case lldb_xmm1_x86_64: 329 reg_value.SetBytes(&tls_context.Xmm1, 16, endian::InlHostByteOrder()); 330 break; 331 case lldb_xmm2_x86_64: 332 reg_value.SetBytes(&tls_context.Xmm2, 16, endian::InlHostByteOrder()); 333 break; 334 case lldb_xmm3_x86_64: 335 reg_value.SetBytes(&tls_context.Xmm3, 16, endian::InlHostByteOrder()); 336 break; 337 case lldb_xmm4_x86_64: 338 reg_value.SetBytes(&tls_context.Xmm4, 16, endian::InlHostByteOrder()); 339 break; 340 case lldb_xmm5_x86_64: 341 reg_value.SetBytes(&tls_context.Xmm5, 16, endian::InlHostByteOrder()); 342 break; 343 case lldb_xmm6_x86_64: 344 reg_value.SetBytes(&tls_context.Xmm6, 16, endian::InlHostByteOrder()); 345 break; 346 case lldb_xmm7_x86_64: 347 reg_value.SetBytes(&tls_context.Xmm7, 16, endian::InlHostByteOrder()); 348 break; 349 case lldb_xmm8_x86_64: 350 reg_value.SetBytes(&tls_context.Xmm8, 16, endian::InlHostByteOrder()); 351 break; 352 case lldb_xmm9_x86_64: 353 reg_value.SetBytes(&tls_context.Xmm9, 16, endian::InlHostByteOrder()); 354 break; 355 case lldb_xmm10_x86_64: 356 reg_value.SetBytes(&tls_context.Xmm10, 16, endian::InlHostByteOrder()); 357 break; 358 case lldb_xmm11_x86_64: 359 reg_value.SetBytes(&tls_context.Xmm11, 16, endian::InlHostByteOrder()); 360 break; 361 case lldb_xmm12_x86_64: 362 reg_value.SetBytes(&tls_context.Xmm12, 16, endian::InlHostByteOrder()); 363 break; 364 case lldb_xmm13_x86_64: 365 reg_value.SetBytes(&tls_context.Xmm13, 16, endian::InlHostByteOrder()); 366 break; 367 case lldb_xmm14_x86_64: 368 reg_value.SetBytes(&tls_context.Xmm14, 16, endian::InlHostByteOrder()); 369 break; 370 case lldb_xmm15_x86_64: 371 reg_value.SetBytes(&tls_context.Xmm15, 16, endian::InlHostByteOrder()); 372 break; 373 } 374 375 return error; 376 } 377 378 Status 379 NativeRegisterContextWindows_x86_64::FPRWrite(const uint32_t reg, 380 const RegisterValue ®_value) { 381 ::CONTEXT tls_context; 382 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_FLOATING_POINT; 383 auto thread_handle = GetThreadHandle(); 384 Status error = 385 GetThreadContextHelper(thread_handle, &tls_context, context_flag); 386 if (error.Fail()) 387 return error; 388 389 switch (reg) { 390 case lldb_xmm0_x86_64: 391 memcpy(&tls_context.Xmm0, reg_value.GetBytes(), 16); 392 break; 393 case lldb_xmm1_x86_64: 394 memcpy(&tls_context.Xmm1, reg_value.GetBytes(), 16); 395 break; 396 case lldb_xmm2_x86_64: 397 memcpy(&tls_context.Xmm2, reg_value.GetBytes(), 16); 398 break; 399 case lldb_xmm3_x86_64: 400 memcpy(&tls_context.Xmm3, reg_value.GetBytes(), 16); 401 break; 402 case lldb_xmm4_x86_64: 403 memcpy(&tls_context.Xmm4, reg_value.GetBytes(), 16); 404 break; 405 case lldb_xmm5_x86_64: 406 memcpy(&tls_context.Xmm5, reg_value.GetBytes(), 16); 407 break; 408 case lldb_xmm6_x86_64: 409 memcpy(&tls_context.Xmm6, reg_value.GetBytes(), 16); 410 break; 411 case lldb_xmm7_x86_64: 412 memcpy(&tls_context.Xmm7, reg_value.GetBytes(), 16); 413 break; 414 case lldb_xmm8_x86_64: 415 memcpy(&tls_context.Xmm8, reg_value.GetBytes(), 16); 416 break; 417 case lldb_xmm9_x86_64: 418 memcpy(&tls_context.Xmm9, reg_value.GetBytes(), 16); 419 break; 420 case lldb_xmm10_x86_64: 421 memcpy(&tls_context.Xmm10, reg_value.GetBytes(), 16); 422 break; 423 case lldb_xmm11_x86_64: 424 memcpy(&tls_context.Xmm11, reg_value.GetBytes(), 16); 425 break; 426 case lldb_xmm12_x86_64: 427 memcpy(&tls_context.Xmm12, reg_value.GetBytes(), 16); 428 break; 429 case lldb_xmm13_x86_64: 430 memcpy(&tls_context.Xmm13, reg_value.GetBytes(), 16); 431 break; 432 case lldb_xmm14_x86_64: 433 memcpy(&tls_context.Xmm14, reg_value.GetBytes(), 16); 434 break; 435 case lldb_xmm15_x86_64: 436 memcpy(&tls_context.Xmm15, reg_value.GetBytes(), 16); 437 break; 438 } 439 440 return SetThreadContextHelper(thread_handle, &tls_context); 441 } 442 443 Status NativeRegisterContextWindows_x86_64::DRRead(const uint32_t reg, 444 RegisterValue ®_value) { 445 ::CONTEXT tls_context; 446 DWORD context_flag = CONTEXT_DEBUG_REGISTERS; 447 Status error = 448 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag); 449 if (error.Fail()) 450 return error; 451 452 switch (reg) { 453 case lldb_dr0_x86_64: 454 reg_value.SetUInt64(tls_context.Dr0); 455 break; 456 case lldb_dr1_x86_64: 457 reg_value.SetUInt64(tls_context.Dr1); 458 break; 459 case lldb_dr2_x86_64: 460 reg_value.SetUInt64(tls_context.Dr2); 461 break; 462 case lldb_dr3_x86_64: 463 reg_value.SetUInt64(tls_context.Dr3); 464 break; 465 case lldb_dr4_x86_64: 466 return Status("register DR4 is obsolete"); 467 case lldb_dr5_x86_64: 468 return Status("register DR5 is obsolete"); 469 case lldb_dr6_x86_64: 470 reg_value.SetUInt64(tls_context.Dr6); 471 break; 472 case lldb_dr7_x86_64: 473 reg_value.SetUInt64(tls_context.Dr7); 474 break; 475 } 476 477 return {}; 478 } 479 480 Status 481 NativeRegisterContextWindows_x86_64::DRWrite(const uint32_t reg, 482 const RegisterValue ®_value) { 483 ::CONTEXT tls_context; 484 DWORD context_flag = CONTEXT_DEBUG_REGISTERS; 485 auto thread_handle = GetThreadHandle(); 486 Status error = 487 GetThreadContextHelper(thread_handle, &tls_context, context_flag); 488 if (error.Fail()) 489 return error; 490 491 switch (reg) { 492 case lldb_dr0_x86_64: 493 tls_context.Dr0 = reg_value.GetAsUInt64(); 494 break; 495 case lldb_dr1_x86_64: 496 tls_context.Dr1 = reg_value.GetAsUInt64(); 497 break; 498 case lldb_dr2_x86_64: 499 tls_context.Dr2 = reg_value.GetAsUInt64(); 500 break; 501 case lldb_dr3_x86_64: 502 tls_context.Dr3 = reg_value.GetAsUInt64(); 503 break; 504 case lldb_dr4_x86_64: 505 return Status("register DR4 is obsolete"); 506 case lldb_dr5_x86_64: 507 return Status("register DR5 is obsolete"); 508 case lldb_dr6_x86_64: 509 tls_context.Dr6 = reg_value.GetAsUInt64(); 510 break; 511 case lldb_dr7_x86_64: 512 tls_context.Dr7 = reg_value.GetAsUInt64(); 513 break; 514 } 515 516 return SetThreadContextHelper(thread_handle, &tls_context); 517 } 518 519 Status 520 NativeRegisterContextWindows_x86_64::ReadRegister(const RegisterInfo *reg_info, 521 RegisterValue ®_value) { 522 Status error; 523 if (!reg_info) { 524 error.SetErrorString("reg_info NULL"); 525 return error; 526 } 527 528 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 529 if (reg == LLDB_INVALID_REGNUM) { 530 // This is likely an internal register for lldb use only and should not be 531 // directly queried. 532 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 533 "register, cannot read directly", 534 reg_info->name); 535 return error; 536 } 537 538 if (IsGPR(reg)) 539 return GPRRead(reg, reg_value); 540 541 if (IsFPR(reg)) 542 return FPRRead(reg, reg_value); 543 544 if (IsDR(reg)) 545 return DRRead(reg, reg_value); 546 547 return Status("unimplemented"); 548 } 549 550 Status NativeRegisterContextWindows_x86_64::WriteRegister( 551 const RegisterInfo *reg_info, const RegisterValue ®_value) { 552 Status error; 553 554 if (!reg_info) { 555 error.SetErrorString("reg_info NULL"); 556 return error; 557 } 558 559 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 560 if (reg == LLDB_INVALID_REGNUM) { 561 // This is likely an internal register for lldb use only and should not be 562 // directly written. 563 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 564 "register, cannot write directly", 565 reg_info->name); 566 return error; 567 } 568 569 if (IsGPR(reg)) 570 return GPRWrite(reg, reg_value); 571 572 if (IsFPR(reg)) 573 return FPRWrite(reg, reg_value); 574 575 if (IsDR(reg)) 576 return DRWrite(reg, reg_value); 577 578 return Status("unimplemented"); 579 } 580 581 Status NativeRegisterContextWindows_x86_64::ReadAllRegisterValues( 582 lldb::WritableDataBufferSP &data_sp) { 583 const size_t data_size = REG_CONTEXT_SIZE; 584 data_sp = std::make_shared<DataBufferHeap>(data_size, 0); 585 ::CONTEXT tls_context; 586 Status error = 587 GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL); 588 if (error.Fail()) 589 return error; 590 591 uint8_t *dst = data_sp->GetBytes(); 592 ::memcpy(dst, &tls_context, data_size); 593 return error; 594 } 595 596 Status NativeRegisterContextWindows_x86_64::WriteAllRegisterValues( 597 const lldb::DataBufferSP &data_sp) { 598 Status error; 599 const size_t data_size = REG_CONTEXT_SIZE; 600 if (!data_sp) { 601 error.SetErrorStringWithFormat( 602 "NativeRegisterContextWindows_x86_64::%s invalid data_sp provided", 603 __FUNCTION__); 604 return error; 605 } 606 607 if (data_sp->GetByteSize() != data_size) { 608 error.SetErrorStringWithFormatv( 609 "data_sp contained mismatched data size, expected {0}, actual {1}", 610 data_size, data_sp->GetByteSize()); 611 return error; 612 } 613 614 ::CONTEXT tls_context; 615 memcpy(&tls_context, data_sp->GetBytes(), data_size); 616 return SetThreadContextHelper(GetThreadHandle(), &tls_context); 617 } 618 619 Status NativeRegisterContextWindows_x86_64::IsWatchpointHit(uint32_t wp_index, 620 bool &is_hit) { 621 is_hit = false; 622 623 if (wp_index >= NumSupportedHardwareWatchpoints()) 624 return Status("watchpoint index out of range"); 625 626 RegisterValue reg_value; 627 Status error = DRRead(lldb_dr6_x86_64, reg_value); 628 if (error.Fail()) 629 return error; 630 631 is_hit = reg_value.GetAsUInt64() & (1ULL << wp_index); 632 633 return {}; 634 } 635 636 Status NativeRegisterContextWindows_x86_64::GetWatchpointHitIndex( 637 uint32_t &wp_index, lldb::addr_t trap_addr) { 638 wp_index = LLDB_INVALID_INDEX32; 639 640 for (uint32_t i = 0; i < NumSupportedHardwareWatchpoints(); i++) { 641 bool is_hit; 642 Status error = IsWatchpointHit(i, is_hit); 643 if (error.Fail()) 644 return error; 645 646 if (is_hit) { 647 wp_index = i; 648 return {}; 649 } 650 } 651 652 return {}; 653 } 654 655 Status 656 NativeRegisterContextWindows_x86_64::IsWatchpointVacant(uint32_t wp_index, 657 bool &is_vacant) { 658 is_vacant = false; 659 660 if (wp_index >= NumSupportedHardwareWatchpoints()) 661 return Status("Watchpoint index out of range"); 662 663 RegisterValue reg_value; 664 Status error = DRRead(lldb_dr7_x86_64, reg_value); 665 if (error.Fail()) 666 return error; 667 668 is_vacant = !(reg_value.GetAsUInt64() & (1ULL << (2 * wp_index))); 669 670 return error; 671 } 672 673 bool NativeRegisterContextWindows_x86_64::ClearHardwareWatchpoint( 674 uint32_t wp_index) { 675 if (wp_index >= NumSupportedHardwareWatchpoints()) 676 return false; 677 678 // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of 679 // the debug status register (DR6) 680 681 RegisterValue reg_value; 682 Status error = DRRead(lldb_dr6_x86_64, reg_value); 683 if (error.Fail()) 684 return false; 685 686 uint64_t bit_mask = 1ULL << wp_index; 687 uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; 688 error = DRWrite(lldb_dr6_x86_64, RegisterValue(status_bits)); 689 if (error.Fail()) 690 return false; 691 692 // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, 693 // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register 694 // (DR7) 695 696 error = DRRead(lldb_dr7_x86_64, reg_value); 697 if (error.Fail()) 698 return false; 699 700 bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 701 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 702 return DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits)).Success(); 703 } 704 705 Status NativeRegisterContextWindows_x86_64::ClearAllHardwareWatchpoints() { 706 RegisterValue reg_value; 707 708 // clear bits {0-4} of the debug status register (DR6) 709 710 Status error = DRRead(lldb_dr6_x86_64, reg_value); 711 if (error.Fail()) 712 return error; 713 714 uint64_t status_bits = reg_value.GetAsUInt64() & ~0xFULL; 715 error = DRWrite(lldb_dr6_x86_64, RegisterValue(status_bits)); 716 if (error.Fail()) 717 return error; 718 719 // clear bits {0-7,16-31} of the debug control register (DR7) 720 721 error = DRRead(lldb_dr7_x86_64, reg_value); 722 if (error.Fail()) 723 return error; 724 725 uint64_t control_bits = reg_value.GetAsUInt64() & ~0xFFFF00FFULL; 726 return DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits)); 727 } 728 729 uint32_t NativeRegisterContextWindows_x86_64::SetHardwareWatchpoint( 730 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 731 switch (size) { 732 case 1: 733 case 2: 734 case 4: 735 case 8: 736 break; 737 default: 738 return LLDB_INVALID_INDEX32; 739 } 740 741 if (watch_flags == 0x2) 742 watch_flags = 0x3; 743 744 if (watch_flags != 0x1 && watch_flags != 0x3) 745 return LLDB_INVALID_INDEX32; 746 747 for (uint32_t wp_index = 0; wp_index < NumSupportedHardwareWatchpoints(); 748 ++wp_index) { 749 bool is_vacant; 750 if (IsWatchpointVacant(wp_index, is_vacant).Fail()) 751 return LLDB_INVALID_INDEX32; 752 753 if (is_vacant) { 754 if (!ClearHardwareWatchpoint(wp_index)) 755 return LLDB_INVALID_INDEX32; 756 757 if (ApplyHardwareBreakpoint(wp_index, addr, size, watch_flags).Fail()) 758 return LLDB_INVALID_INDEX32; 759 760 return wp_index; 761 } 762 } 763 return LLDB_INVALID_INDEX32; 764 } 765 766 Status NativeRegisterContextWindows_x86_64::ApplyHardwareBreakpoint( 767 uint32_t wp_index, lldb::addr_t addr, size_t size, uint32_t flags) { 768 RegisterValue reg_value; 769 auto error = DRRead(lldb_dr7_x86_64, reg_value); 770 if (error.Fail()) 771 return error; 772 773 // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 774 uint64_t enable_bit = 1ULL << (2 * wp_index); 775 776 // set bits 16-17, 20-21, 24-25, or 28-29 777 // with 0b01 for write, and 0b11 for read/write 778 uint64_t rw_bits = flags << (16 + 4 * wp_index); 779 780 // set bits 18-19, 22-23, 26-27, or 30-31 781 // with 0b00, 0b01, 0b10, or 0b11 782 // for 1, 2, 8 (if supported), or 4 bytes, respectively 783 uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); 784 785 uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 786 787 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 788 control_bits |= enable_bit | rw_bits | size_bits; 789 790 error = DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits)); 791 if (error.Fail()) 792 return error; 793 794 error = DRWrite(lldb_dr0_x86_64 + wp_index, RegisterValue(addr)); 795 if (error.Fail()) 796 return error; 797 798 return {}; 799 } 800 801 lldb::addr_t 802 NativeRegisterContextWindows_x86_64::GetWatchpointAddress(uint32_t wp_index) { 803 if (wp_index >= NumSupportedHardwareWatchpoints()) 804 return LLDB_INVALID_ADDRESS; 805 806 RegisterValue reg_value; 807 if (DRRead(lldb_dr0_x86_64 + wp_index, reg_value).Fail()) 808 return LLDB_INVALID_ADDRESS; 809 810 return reg_value.GetAsUInt64(); 811 } 812 813 uint32_t 814 NativeRegisterContextWindows_x86_64::NumSupportedHardwareWatchpoints() { 815 return 4; 816 } 817 818 #endif // defined(__x86_64__) || defined(_M_X64) 819