1 //===-- NativeRegisterContextWindows_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__) || 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 = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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 = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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 uint32_t NativeRegisterContextWindows_x86_64::GetRegisterSetCount() const { 125 return k_num_register_sets; 126 } 127 128 const RegisterSet * 129 NativeRegisterContextWindows_x86_64::GetRegisterSet(uint32_t set_index) const { 130 if (set_index >= k_num_register_sets) 131 return nullptr; 132 return &g_reg_sets_x86_64[set_index]; 133 } 134 135 Status NativeRegisterContextWindows_x86_64::GPRRead(const uint32_t reg, 136 RegisterValue ®_value) { 137 ::CONTEXT tls_context; 138 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; 139 Status error = 140 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag); 141 if (error.Fail()) 142 return error; 143 144 switch (reg) { 145 case lldb_rax_x86_64: 146 reg_value.SetUInt64(tls_context.Rax); 147 break; 148 case lldb_rbx_x86_64: 149 reg_value.SetUInt64(tls_context.Rbx); 150 break; 151 case lldb_rcx_x86_64: 152 reg_value.SetUInt64(tls_context.Rcx); 153 break; 154 case lldb_rdx_x86_64: 155 reg_value.SetUInt64(tls_context.Rdx); 156 break; 157 case lldb_rdi_x86_64: 158 reg_value.SetUInt64(tls_context.Rdi); 159 break; 160 case lldb_rsi_x86_64: 161 reg_value.SetUInt64(tls_context.Rsi); 162 break; 163 case lldb_rbp_x86_64: 164 reg_value.SetUInt64(tls_context.Rbp); 165 break; 166 case lldb_rsp_x86_64: 167 reg_value.SetUInt64(tls_context.Rsp); 168 break; 169 case lldb_r8_x86_64: 170 reg_value.SetUInt64(tls_context.R8); 171 break; 172 case lldb_r9_x86_64: 173 reg_value.SetUInt64(tls_context.R9); 174 break; 175 case lldb_r10_x86_64: 176 reg_value.SetUInt64(tls_context.R10); 177 break; 178 case lldb_r11_x86_64: 179 reg_value.SetUInt64(tls_context.R11); 180 break; 181 case lldb_r12_x86_64: 182 reg_value.SetUInt64(tls_context.R12); 183 break; 184 case lldb_r13_x86_64: 185 reg_value.SetUInt64(tls_context.R13); 186 break; 187 case lldb_r14_x86_64: 188 reg_value.SetUInt64(tls_context.R14); 189 break; 190 case lldb_r15_x86_64: 191 reg_value.SetUInt64(tls_context.R15); 192 break; 193 case lldb_rip_x86_64: 194 reg_value.SetUInt64(tls_context.Rip); 195 break; 196 case lldb_rflags_x86_64: 197 reg_value.SetUInt64(tls_context.EFlags | 0x2); // Bit #1 always 1 198 break; 199 case lldb_cs_x86_64: 200 reg_value.SetUInt16(tls_context.SegCs); 201 break; 202 case lldb_fs_x86_64: 203 reg_value.SetUInt16(tls_context.SegFs); 204 break; 205 case lldb_gs_x86_64: 206 reg_value.SetUInt16(tls_context.SegGs); 207 break; 208 case lldb_ss_x86_64: 209 reg_value.SetUInt16(tls_context.SegSs); 210 break; 211 case lldb_ds_x86_64: 212 reg_value.SetUInt16(tls_context.SegDs); 213 break; 214 case lldb_es_x86_64: 215 reg_value.SetUInt16(tls_context.SegEs); 216 break; 217 } 218 219 return error; 220 } 221 222 Status 223 NativeRegisterContextWindows_x86_64::GPRWrite(const uint32_t reg, 224 const RegisterValue ®_value) { 225 ::CONTEXT tls_context; 226 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; 227 auto thread_handle = GetThreadHandle(); 228 Status error = 229 GetThreadContextHelper(thread_handle, &tls_context, context_flag); 230 if (error.Fail()) 231 return error; 232 233 switch (reg) { 234 case lldb_rax_x86_64: 235 tls_context.Rax = reg_value.GetAsUInt64(); 236 break; 237 case lldb_rbx_x86_64: 238 tls_context.Rbx = reg_value.GetAsUInt64(); 239 break; 240 case lldb_rcx_x86_64: 241 tls_context.Rcx = reg_value.GetAsUInt64(); 242 break; 243 case lldb_rdx_x86_64: 244 tls_context.Rdx = reg_value.GetAsUInt64(); 245 break; 246 case lldb_rdi_x86_64: 247 tls_context.Rdi = reg_value.GetAsUInt64(); 248 break; 249 case lldb_rsi_x86_64: 250 tls_context.Rsi = reg_value.GetAsUInt64(); 251 break; 252 case lldb_rbp_x86_64: 253 tls_context.Rbp = reg_value.GetAsUInt64(); 254 break; 255 case lldb_rsp_x86_64: 256 tls_context.Rsp = reg_value.GetAsUInt64(); 257 break; 258 case lldb_r8_x86_64: 259 tls_context.R8 = reg_value.GetAsUInt64(); 260 break; 261 case lldb_r9_x86_64: 262 tls_context.R9 = reg_value.GetAsUInt64(); 263 break; 264 case lldb_r10_x86_64: 265 tls_context.R10 = reg_value.GetAsUInt64(); 266 break; 267 case lldb_r11_x86_64: 268 tls_context.R11 = reg_value.GetAsUInt64(); 269 break; 270 case lldb_r12_x86_64: 271 tls_context.R12 = reg_value.GetAsUInt64(); 272 break; 273 case lldb_r13_x86_64: 274 tls_context.R13 = reg_value.GetAsUInt64(); 275 break; 276 case lldb_r14_x86_64: 277 tls_context.R14 = reg_value.GetAsUInt64(); 278 break; 279 case lldb_r15_x86_64: 280 tls_context.R15 = reg_value.GetAsUInt64(); 281 break; 282 case lldb_rip_x86_64: 283 tls_context.Rip = reg_value.GetAsUInt64(); 284 break; 285 case lldb_rflags_x86_64: 286 tls_context.EFlags = reg_value.GetAsUInt64(); 287 break; 288 case lldb_cs_x86_64: 289 tls_context.SegCs = reg_value.GetAsUInt16(); 290 break; 291 case lldb_fs_x86_64: 292 tls_context.SegFs = reg_value.GetAsUInt16(); 293 break; 294 case lldb_gs_x86_64: 295 tls_context.SegGs = reg_value.GetAsUInt16(); 296 break; 297 case lldb_ss_x86_64: 298 tls_context.SegSs = reg_value.GetAsUInt16(); 299 break; 300 case lldb_ds_x86_64: 301 tls_context.SegDs = reg_value.GetAsUInt16(); 302 break; 303 case lldb_es_x86_64: 304 tls_context.SegEs = reg_value.GetAsUInt16(); 305 break; 306 } 307 308 return SetThreadContextHelper(thread_handle, &tls_context); 309 } 310 311 Status NativeRegisterContextWindows_x86_64::FPRRead(const uint32_t reg, 312 RegisterValue ®_value) { 313 ::CONTEXT tls_context; 314 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_FLOATING_POINT; 315 Status error = 316 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag); 317 if (error.Fail()) 318 return error; 319 320 switch (reg) { 321 case lldb_xmm0_x86_64: 322 reg_value.SetBytes(&tls_context.Xmm0, 16, endian::InlHostByteOrder()); 323 break; 324 case lldb_xmm1_x86_64: 325 reg_value.SetBytes(&tls_context.Xmm1, 16, endian::InlHostByteOrder()); 326 break; 327 case lldb_xmm2_x86_64: 328 reg_value.SetBytes(&tls_context.Xmm2, 16, endian::InlHostByteOrder()); 329 break; 330 case lldb_xmm3_x86_64: 331 reg_value.SetBytes(&tls_context.Xmm3, 16, endian::InlHostByteOrder()); 332 break; 333 case lldb_xmm4_x86_64: 334 reg_value.SetBytes(&tls_context.Xmm4, 16, endian::InlHostByteOrder()); 335 break; 336 case lldb_xmm5_x86_64: 337 reg_value.SetBytes(&tls_context.Xmm5, 16, endian::InlHostByteOrder()); 338 break; 339 case lldb_xmm6_x86_64: 340 reg_value.SetBytes(&tls_context.Xmm6, 16, endian::InlHostByteOrder()); 341 break; 342 case lldb_xmm7_x86_64: 343 reg_value.SetBytes(&tls_context.Xmm7, 16, endian::InlHostByteOrder()); 344 break; 345 case lldb_xmm8_x86_64: 346 reg_value.SetBytes(&tls_context.Xmm8, 16, endian::InlHostByteOrder()); 347 break; 348 case lldb_xmm9_x86_64: 349 reg_value.SetBytes(&tls_context.Xmm9, 16, endian::InlHostByteOrder()); 350 break; 351 case lldb_xmm10_x86_64: 352 reg_value.SetBytes(&tls_context.Xmm10, 16, endian::InlHostByteOrder()); 353 break; 354 case lldb_xmm11_x86_64: 355 reg_value.SetBytes(&tls_context.Xmm11, 16, endian::InlHostByteOrder()); 356 break; 357 case lldb_xmm12_x86_64: 358 reg_value.SetBytes(&tls_context.Xmm12, 16, endian::InlHostByteOrder()); 359 break; 360 case lldb_xmm13_x86_64: 361 reg_value.SetBytes(&tls_context.Xmm13, 16, endian::InlHostByteOrder()); 362 break; 363 case lldb_xmm14_x86_64: 364 reg_value.SetBytes(&tls_context.Xmm14, 16, endian::InlHostByteOrder()); 365 break; 366 case lldb_xmm15_x86_64: 367 reg_value.SetBytes(&tls_context.Xmm15, 16, endian::InlHostByteOrder()); 368 break; 369 } 370 371 return error; 372 } 373 374 Status 375 NativeRegisterContextWindows_x86_64::FPRWrite(const uint32_t reg, 376 const RegisterValue ®_value) { 377 ::CONTEXT tls_context; 378 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_FLOATING_POINT; 379 auto thread_handle = GetThreadHandle(); 380 Status error = 381 GetThreadContextHelper(thread_handle, &tls_context, context_flag); 382 if (error.Fail()) 383 return error; 384 385 switch (reg) { 386 case lldb_xmm0_x86_64: 387 memcpy(&tls_context.Xmm0, reg_value.GetBytes(), 16); 388 break; 389 case lldb_xmm1_x86_64: 390 memcpy(&tls_context.Xmm1, reg_value.GetBytes(), 16); 391 break; 392 case lldb_xmm2_x86_64: 393 memcpy(&tls_context.Xmm2, reg_value.GetBytes(), 16); 394 break; 395 case lldb_xmm3_x86_64: 396 memcpy(&tls_context.Xmm3, reg_value.GetBytes(), 16); 397 break; 398 case lldb_xmm4_x86_64: 399 memcpy(&tls_context.Xmm4, reg_value.GetBytes(), 16); 400 break; 401 case lldb_xmm5_x86_64: 402 memcpy(&tls_context.Xmm5, reg_value.GetBytes(), 16); 403 break; 404 case lldb_xmm6_x86_64: 405 memcpy(&tls_context.Xmm6, reg_value.GetBytes(), 16); 406 break; 407 case lldb_xmm7_x86_64: 408 memcpy(&tls_context.Xmm7, reg_value.GetBytes(), 16); 409 break; 410 case lldb_xmm8_x86_64: 411 memcpy(&tls_context.Xmm8, reg_value.GetBytes(), 16); 412 break; 413 case lldb_xmm9_x86_64: 414 memcpy(&tls_context.Xmm9, reg_value.GetBytes(), 16); 415 break; 416 case lldb_xmm10_x86_64: 417 memcpy(&tls_context.Xmm10, reg_value.GetBytes(), 16); 418 break; 419 case lldb_xmm11_x86_64: 420 memcpy(&tls_context.Xmm11, reg_value.GetBytes(), 16); 421 break; 422 case lldb_xmm12_x86_64: 423 memcpy(&tls_context.Xmm12, reg_value.GetBytes(), 16); 424 break; 425 case lldb_xmm13_x86_64: 426 memcpy(&tls_context.Xmm13, reg_value.GetBytes(), 16); 427 break; 428 case lldb_xmm14_x86_64: 429 memcpy(&tls_context.Xmm14, reg_value.GetBytes(), 16); 430 break; 431 case lldb_xmm15_x86_64: 432 memcpy(&tls_context.Xmm15, reg_value.GetBytes(), 16); 433 break; 434 } 435 436 return SetThreadContextHelper(thread_handle, &tls_context); 437 } 438 439 Status 440 NativeRegisterContextWindows_x86_64::ReadRegister(const RegisterInfo *reg_info, 441 RegisterValue ®_value) { 442 Status error; 443 if (!reg_info) { 444 error.SetErrorString("reg_info NULL"); 445 return error; 446 } 447 448 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 449 if (reg == LLDB_INVALID_REGNUM) { 450 // This is likely an internal register for lldb use only and should not be 451 // directly queried. 452 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 453 "register, cannot read directly", 454 reg_info->name); 455 return error; 456 } 457 458 if (IsGPR(reg)) 459 return GPRRead(reg, reg_value); 460 461 if (IsFPR(reg)) 462 return FPRRead(reg, reg_value); 463 464 return Status("unimplemented"); 465 } 466 467 Status NativeRegisterContextWindows_x86_64::WriteRegister( 468 const RegisterInfo *reg_info, const RegisterValue ®_value) { 469 Status error; 470 471 if (!reg_info) { 472 error.SetErrorString("reg_info NULL"); 473 return error; 474 } 475 476 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 477 if (reg == LLDB_INVALID_REGNUM) { 478 // This is likely an internal register for lldb use only and should not be 479 // directly written. 480 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 481 "register, cannot write directly", 482 reg_info->name); 483 return error; 484 } 485 486 if (IsGPR(reg)) 487 return GPRWrite(reg, reg_value); 488 489 if (IsFPR(reg)) 490 return FPRWrite(reg, reg_value); 491 492 return Status("unimplemented"); 493 } 494 495 Status NativeRegisterContextWindows_x86_64::ReadAllRegisterValues( 496 lldb::DataBufferSP &data_sp) { 497 const size_t data_size = REG_CONTEXT_SIZE; 498 data_sp = std::make_shared<DataBufferHeap>(data_size, 0); 499 ::CONTEXT tls_context; 500 Status error = 501 GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL); 502 if (error.Fail()) 503 return error; 504 505 uint8_t *dst = data_sp->GetBytes(); 506 ::memcpy(dst, &tls_context, data_size); 507 return error; 508 } 509 510 Status NativeRegisterContextWindows_x86_64::WriteAllRegisterValues( 511 const lldb::DataBufferSP &data_sp) { 512 Status error; 513 const size_t data_size = REG_CONTEXT_SIZE; 514 if (!data_sp) { 515 error.SetErrorStringWithFormat( 516 "NativeRegisterContextWindows_x86_64::%s invalid data_sp provided", 517 __FUNCTION__); 518 return error; 519 } 520 521 if (data_sp->GetByteSize() != data_size) { 522 error.SetErrorStringWithFormatv( 523 "data_sp contained mismatched data size, expected {0}, actual {1}", 524 data_size, data_sp->GetByteSize()); 525 return error; 526 } 527 528 ::CONTEXT tls_context; 529 memcpy(&tls_context, data_sp->GetBytes(), data_size); 530 return SetThreadContextHelper(GetThreadHandle(), &tls_context); 531 } 532 533 Status NativeRegisterContextWindows_x86_64::IsWatchpointHit(uint32_t wp_index, 534 bool &is_hit) { 535 return Status("unimplemented"); 536 } 537 538 Status NativeRegisterContextWindows_x86_64::GetWatchpointHitIndex( 539 uint32_t &wp_index, lldb::addr_t trap_addr) { 540 return Status("unimplemented"); 541 } 542 543 Status 544 NativeRegisterContextWindows_x86_64::IsWatchpointVacant(uint32_t wp_index, 545 bool &is_vacant) { 546 return Status("unimplemented"); 547 } 548 549 Status NativeRegisterContextWindows_x86_64::SetHardwareWatchpointWithIndex( 550 lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { 551 return Status("unimplemented"); 552 } 553 554 bool NativeRegisterContextWindows_x86_64::ClearHardwareWatchpoint( 555 uint32_t wp_index) { 556 return false; 557 } 558 559 Status NativeRegisterContextWindows_x86_64::ClearAllHardwareWatchpoints() { 560 return Status("unimplemented"); 561 } 562 563 uint32_t NativeRegisterContextWindows_x86_64::SetHardwareWatchpoint( 564 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 565 return LLDB_INVALID_INDEX32; 566 } 567 568 lldb::addr_t 569 NativeRegisterContextWindows_x86_64::GetWatchpointAddress(uint32_t wp_index) { 570 return LLDB_INVALID_ADDRESS; 571 } 572 573 uint32_t 574 NativeRegisterContextWindows_x86_64::NumSupportedHardwareWatchpoints() { 575 // Not implemented 576 return 0; 577 } 578 579 #endif // defined(__x86_64__) || defined(_M_X64) 580