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", std::size(g_gpr_regnums_x86_64) - 1, 52 g_gpr_regnums_x86_64}, 53 {"Floating Point Registers", "fpr", std::size(g_fpr_regnums_x86_64) - 1, 54 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 = Status(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 = Status(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::FromErrorString("register DR4 is obsolete"); 467 case lldb_dr5_x86_64: 468 return Status::FromErrorString("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::FromErrorString("register DR4 is obsolete"); 506 case lldb_dr5_x86_64: 507 return Status::FromErrorString("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 = Status::FromErrorString("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 = Status::FromErrorStringWithFormat( 533 "register \"%s\" is an internal-only lldb " 534 "register, cannot read directly", 535 reg_info->name); 536 return error; 537 } 538 539 if (IsGPR(reg)) 540 return GPRRead(reg, reg_value); 541 542 if (IsFPR(reg)) 543 return FPRRead(reg, reg_value); 544 545 if (IsDR(reg)) 546 return DRRead(reg, reg_value); 547 548 return Status::FromErrorString("unimplemented"); 549 } 550 551 Status NativeRegisterContextWindows_x86_64::WriteRegister( 552 const RegisterInfo *reg_info, const RegisterValue ®_value) { 553 Status error; 554 555 if (!reg_info) { 556 error = Status::FromErrorString("reg_info NULL"); 557 return error; 558 } 559 560 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 561 if (reg == LLDB_INVALID_REGNUM) { 562 // This is likely an internal register for lldb use only and should not be 563 // directly written. 564 error = Status::FromErrorStringWithFormat( 565 "register \"%s\" is an internal-only lldb " 566 "register, cannot write directly", 567 reg_info->name); 568 return error; 569 } 570 571 if (IsGPR(reg)) 572 return GPRWrite(reg, reg_value); 573 574 if (IsFPR(reg)) 575 return FPRWrite(reg, reg_value); 576 577 if (IsDR(reg)) 578 return DRWrite(reg, reg_value); 579 580 return Status::FromErrorString("unimplemented"); 581 } 582 583 Status NativeRegisterContextWindows_x86_64::ReadAllRegisterValues( 584 lldb::WritableDataBufferSP &data_sp) { 585 const size_t data_size = REG_CONTEXT_SIZE; 586 data_sp = std::make_shared<DataBufferHeap>(data_size, 0); 587 ::CONTEXT tls_context; 588 Status error = 589 GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL); 590 if (error.Fail()) 591 return error; 592 593 uint8_t *dst = data_sp->GetBytes(); 594 ::memcpy(dst, &tls_context, data_size); 595 return error; 596 } 597 598 Status NativeRegisterContextWindows_x86_64::WriteAllRegisterValues( 599 const lldb::DataBufferSP &data_sp) { 600 Status error; 601 const size_t data_size = REG_CONTEXT_SIZE; 602 if (!data_sp) { 603 error = Status::FromErrorStringWithFormat( 604 "NativeRegisterContextWindows_x86_64::%s invalid data_sp provided", 605 __FUNCTION__); 606 return error; 607 } 608 609 if (data_sp->GetByteSize() != data_size) { 610 error = Status::FromErrorStringWithFormatv( 611 "data_sp contained mismatched data size, expected {0}, actual {1}", 612 data_size, data_sp->GetByteSize()); 613 return error; 614 } 615 616 ::CONTEXT tls_context; 617 memcpy(&tls_context, data_sp->GetBytes(), data_size); 618 return SetThreadContextHelper(GetThreadHandle(), &tls_context); 619 } 620 621 Status NativeRegisterContextWindows_x86_64::IsWatchpointHit(uint32_t wp_index, 622 bool &is_hit) { 623 is_hit = false; 624 625 if (wp_index >= NumSupportedHardwareWatchpoints()) 626 return Status::FromErrorString("watchpoint index out of range"); 627 628 RegisterValue reg_value; 629 Status error = DRRead(lldb_dr6_x86_64, reg_value); 630 if (error.Fail()) 631 return error; 632 633 is_hit = reg_value.GetAsUInt64() & (1ULL << wp_index); 634 635 return {}; 636 } 637 638 Status NativeRegisterContextWindows_x86_64::GetWatchpointHitIndex( 639 uint32_t &wp_index, lldb::addr_t trap_addr) { 640 wp_index = LLDB_INVALID_INDEX32; 641 642 for (uint32_t i = 0; i < NumSupportedHardwareWatchpoints(); i++) { 643 bool is_hit; 644 Status error = IsWatchpointHit(i, is_hit); 645 if (error.Fail()) 646 return error; 647 648 if (is_hit) { 649 wp_index = i; 650 return {}; 651 } 652 } 653 654 return {}; 655 } 656 657 Status 658 NativeRegisterContextWindows_x86_64::IsWatchpointVacant(uint32_t wp_index, 659 bool &is_vacant) { 660 is_vacant = false; 661 662 if (wp_index >= NumSupportedHardwareWatchpoints()) 663 return Status::FromErrorString("Watchpoint index out of range"); 664 665 RegisterValue reg_value; 666 Status error = DRRead(lldb_dr7_x86_64, reg_value); 667 if (error.Fail()) 668 return error; 669 670 is_vacant = !(reg_value.GetAsUInt64() & (1ULL << (2 * wp_index))); 671 672 return error; 673 } 674 675 bool NativeRegisterContextWindows_x86_64::ClearHardwareWatchpoint( 676 uint32_t wp_index) { 677 if (wp_index >= NumSupportedHardwareWatchpoints()) 678 return false; 679 680 // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of 681 // the debug status register (DR6) 682 683 RegisterValue reg_value; 684 Status error = DRRead(lldb_dr6_x86_64, reg_value); 685 if (error.Fail()) 686 return false; 687 688 uint64_t bit_mask = 1ULL << wp_index; 689 uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; 690 error = DRWrite(lldb_dr6_x86_64, RegisterValue(status_bits)); 691 if (error.Fail()) 692 return false; 693 694 // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, 695 // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register 696 // (DR7) 697 698 error = DRRead(lldb_dr7_x86_64, reg_value); 699 if (error.Fail()) 700 return false; 701 702 bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 703 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 704 return DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits)).Success(); 705 } 706 707 Status NativeRegisterContextWindows_x86_64::ClearAllHardwareWatchpoints() { 708 RegisterValue reg_value; 709 710 // clear bits {0-4} of the debug status register (DR6) 711 712 Status error = DRRead(lldb_dr6_x86_64, reg_value); 713 if (error.Fail()) 714 return error; 715 716 uint64_t status_bits = reg_value.GetAsUInt64() & ~0xFULL; 717 error = DRWrite(lldb_dr6_x86_64, RegisterValue(status_bits)); 718 if (error.Fail()) 719 return error; 720 721 // clear bits {0-7,16-31} of the debug control register (DR7) 722 723 error = DRRead(lldb_dr7_x86_64, reg_value); 724 if (error.Fail()) 725 return error; 726 727 uint64_t control_bits = reg_value.GetAsUInt64() & ~0xFFFF00FFULL; 728 return DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits)); 729 } 730 731 uint32_t NativeRegisterContextWindows_x86_64::SetHardwareWatchpoint( 732 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 733 switch (size) { 734 case 1: 735 case 2: 736 case 4: 737 case 8: 738 break; 739 default: 740 return LLDB_INVALID_INDEX32; 741 } 742 743 if (watch_flags == 0x2) 744 watch_flags = 0x3; 745 746 if (watch_flags != 0x1 && watch_flags != 0x3) 747 return LLDB_INVALID_INDEX32; 748 749 for (uint32_t wp_index = 0; wp_index < NumSupportedHardwareWatchpoints(); 750 ++wp_index) { 751 bool is_vacant; 752 if (IsWatchpointVacant(wp_index, is_vacant).Fail()) 753 return LLDB_INVALID_INDEX32; 754 755 if (is_vacant) { 756 if (!ClearHardwareWatchpoint(wp_index)) 757 return LLDB_INVALID_INDEX32; 758 759 if (ApplyHardwareBreakpoint(wp_index, addr, size, watch_flags).Fail()) 760 return LLDB_INVALID_INDEX32; 761 762 return wp_index; 763 } 764 } 765 return LLDB_INVALID_INDEX32; 766 } 767 768 Status NativeRegisterContextWindows_x86_64::ApplyHardwareBreakpoint( 769 uint32_t wp_index, lldb::addr_t addr, size_t size, uint32_t flags) { 770 RegisterValue reg_value; 771 auto error = DRRead(lldb_dr7_x86_64, reg_value); 772 if (error.Fail()) 773 return error; 774 775 // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 776 uint64_t enable_bit = 1ULL << (2 * wp_index); 777 778 // set bits 16-17, 20-21, 24-25, or 28-29 779 // with 0b01 for write, and 0b11 for read/write 780 uint64_t rw_bits = flags << (16 + 4 * wp_index); 781 782 // set bits 18-19, 22-23, 26-27, or 30-31 783 // with 0b00, 0b01, 0b10, or 0b11 784 // for 1, 2, 8 (if supported), or 4 bytes, respectively 785 uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); 786 787 uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 788 789 uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; 790 control_bits |= enable_bit | rw_bits | size_bits; 791 792 error = DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits)); 793 if (error.Fail()) 794 return error; 795 796 error = DRWrite(lldb_dr0_x86_64 + wp_index, RegisterValue(addr)); 797 if (error.Fail()) 798 return error; 799 800 return {}; 801 } 802 803 lldb::addr_t 804 NativeRegisterContextWindows_x86_64::GetWatchpointAddress(uint32_t wp_index) { 805 if (wp_index >= NumSupportedHardwareWatchpoints()) 806 return LLDB_INVALID_ADDRESS; 807 808 RegisterValue reg_value; 809 if (DRRead(lldb_dr0_x86_64 + wp_index, reg_value).Fail()) 810 return LLDB_INVALID_ADDRESS; 811 812 return reg_value.GetAsUInt64(); 813 } 814 815 uint32_t 816 NativeRegisterContextWindows_x86_64::NumSupportedHardwareWatchpoints() { 817 return 4; 818 } 819 820 #endif // defined(__x86_64__) || defined(_M_X64) 821