1 //===-- NativeRegisterContextWindows_i386.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(__i386__) || defined(_M_IX86) 10 11 #include "NativeRegisterContextWindows_i386.h" 12 13 #include "NativeThreadWindows.h" 14 #include "Plugins/Process/Utility/RegisterContextWindows_i386.h" 15 #include "ProcessWindowsLog.h" 16 #include "lldb/Host/HostInfo.h" 17 #include "lldb/Host/HostThread.h" 18 #include "lldb/Host/windows/HostThreadWindows.h" 19 #include "lldb/Host/windows/windows.h" 20 21 #include "lldb/Utility/Log.h" 22 #include "lldb/Utility/RegisterValue.h" 23 #include "llvm/ADT/STLExtras.h" 24 25 using namespace lldb; 26 using namespace lldb_private; 27 28 #define REG_CONTEXT_SIZE sizeof(::CONTEXT) 29 30 namespace { 31 static const uint32_t g_gpr_regnums_i386[] = { 32 lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386, 33 lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386, 34 lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386, 35 lldb_gs_i386, lldb_ss_i386, lldb_ds_i386, lldb_es_i386, 36 LLDB_INVALID_REGNUM // Register sets must be terminated with this flag. 37 }; 38 39 static const RegisterSet g_reg_sets_i386[] = { 40 {"General Purpose Registers", "gpr", std::size(g_gpr_regnums_i386) - 1, 41 g_gpr_regnums_i386}, 42 }; 43 44 enum { k_num_register_sets = 1 }; 45 46 } // namespace 47 48 static RegisterInfoInterface * 49 CreateRegisterInfoInterface(const ArchSpec &target_arch) { 50 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 4) && 51 "Register setting path assumes this is a 32-bit host"); 52 return new RegisterContextWindows_i386(target_arch); 53 } 54 55 static Status GetThreadContextHelper(lldb::thread_t thread_handle, 56 PCONTEXT context_ptr, 57 const DWORD control_flag) { 58 Log *log = GetLog(WindowsLog::Registers); 59 Status error; 60 61 memset(context_ptr, 0, sizeof(::CONTEXT)); 62 context_ptr->ContextFlags = control_flag; 63 if (!::GetThreadContext(thread_handle, context_ptr)) { 64 error = Status(GetLastError(), eErrorTypeWin32); 65 LLDB_LOG(log, "{0} GetThreadContext failed with error {1}", __FUNCTION__, 66 error); 67 return error; 68 } 69 return Status(); 70 } 71 72 static Status SetThreadContextHelper(lldb::thread_t thread_handle, 73 PCONTEXT context_ptr) { 74 Log *log = GetLog(WindowsLog::Registers); 75 Status error; 76 77 if (!::SetThreadContext(thread_handle, context_ptr)) { 78 error = Status(GetLastError(), eErrorTypeWin32); 79 LLDB_LOG(log, "{0} SetThreadContext failed with error {1}", __FUNCTION__, 80 error); 81 return error; 82 } 83 return Status(); 84 } 85 86 std::unique_ptr<NativeRegisterContextWindows> 87 NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows( 88 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 89 return std::make_unique<NativeRegisterContextWindows_i386>(target_arch, 90 native_thread); 91 } 92 93 NativeRegisterContextWindows_i386::NativeRegisterContextWindows_i386( 94 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 95 : NativeRegisterContextWindows(native_thread, 96 CreateRegisterInfoInterface(target_arch)) {} 97 98 bool NativeRegisterContextWindows_i386::IsGPR(uint32_t reg_index) const { 99 return (reg_index < k_first_alias_i386); 100 } 101 102 bool NativeRegisterContextWindows_i386::IsDR(uint32_t reg_index) const { 103 return (reg_index >= lldb_dr0_i386 && reg_index <= lldb_dr7_i386); 104 } 105 106 uint32_t NativeRegisterContextWindows_i386::GetRegisterSetCount() const { 107 return k_num_register_sets; 108 } 109 110 const RegisterSet * 111 NativeRegisterContextWindows_i386::GetRegisterSet(uint32_t set_index) const { 112 if (set_index >= k_num_register_sets) 113 return nullptr; 114 return &g_reg_sets_i386[set_index]; 115 } 116 117 Status NativeRegisterContextWindows_i386::GPRRead(const uint32_t reg, 118 RegisterValue ®_value) { 119 ::CONTEXT tls_context; 120 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; 121 Status error = 122 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag); 123 if (error.Fail()) 124 return error; 125 126 switch (reg) { 127 case lldb_eax_i386: 128 reg_value.SetUInt32(tls_context.Eax); 129 break; 130 case lldb_ebx_i386: 131 reg_value.SetUInt32(tls_context.Ebx); 132 break; 133 case lldb_ecx_i386: 134 reg_value.SetUInt32(tls_context.Ecx); 135 break; 136 case lldb_edx_i386: 137 reg_value.SetUInt32(tls_context.Edx); 138 break; 139 case lldb_edi_i386: 140 reg_value.SetUInt32(tls_context.Edi); 141 break; 142 case lldb_esi_i386: 143 reg_value.SetUInt32(tls_context.Esi); 144 break; 145 case lldb_ebp_i386: 146 reg_value.SetUInt32(tls_context.Ebp); 147 break; 148 case lldb_esp_i386: 149 reg_value.SetUInt32(tls_context.Esp); 150 break; 151 case lldb_eip_i386: 152 reg_value.SetUInt32(tls_context.Eip); 153 break; 154 case lldb_eflags_i386: 155 reg_value.SetUInt32(tls_context.EFlags); 156 break; 157 case lldb_cs_i386: 158 reg_value.SetUInt32(tls_context.SegCs); 159 break; 160 case lldb_fs_i386: 161 reg_value.SetUInt32(tls_context.SegFs); 162 break; 163 case lldb_gs_i386: 164 reg_value.SetUInt32(tls_context.SegGs); 165 break; 166 case lldb_ss_i386: 167 reg_value.SetUInt32(tls_context.SegSs); 168 break; 169 case lldb_ds_i386: 170 reg_value.SetUInt32(tls_context.SegDs); 171 break; 172 case lldb_es_i386: 173 reg_value.SetUInt32(tls_context.SegEs); 174 break; 175 } 176 177 return error; 178 } 179 180 Status 181 NativeRegisterContextWindows_i386::GPRWrite(const uint32_t reg, 182 const RegisterValue ®_value) { 183 ::CONTEXT tls_context; 184 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; 185 auto thread_handle = GetThreadHandle(); 186 Status error = 187 GetThreadContextHelper(thread_handle, &tls_context, context_flag); 188 if (error.Fail()) 189 return error; 190 191 switch (reg) { 192 case lldb_eax_i386: 193 tls_context.Eax = reg_value.GetAsUInt32(); 194 break; 195 case lldb_ebx_i386: 196 tls_context.Ebx = reg_value.GetAsUInt32(); 197 break; 198 case lldb_ecx_i386: 199 tls_context.Ecx = reg_value.GetAsUInt32(); 200 break; 201 case lldb_edx_i386: 202 tls_context.Edx = reg_value.GetAsUInt32(); 203 break; 204 case lldb_edi_i386: 205 tls_context.Edi = reg_value.GetAsUInt32(); 206 break; 207 case lldb_esi_i386: 208 tls_context.Esi = reg_value.GetAsUInt32(); 209 break; 210 case lldb_ebp_i386: 211 tls_context.Ebp = reg_value.GetAsUInt32(); 212 break; 213 case lldb_esp_i386: 214 tls_context.Esp = reg_value.GetAsUInt32(); 215 break; 216 case lldb_eip_i386: 217 tls_context.Eip = reg_value.GetAsUInt32(); 218 break; 219 case lldb_eflags_i386: 220 tls_context.EFlags = reg_value.GetAsUInt32(); 221 break; 222 case lldb_cs_i386: 223 tls_context.SegCs = reg_value.GetAsUInt32(); 224 break; 225 case lldb_fs_i386: 226 tls_context.SegFs = reg_value.GetAsUInt32(); 227 break; 228 case lldb_gs_i386: 229 tls_context.SegGs = reg_value.GetAsUInt32(); 230 break; 231 case lldb_ss_i386: 232 tls_context.SegSs = reg_value.GetAsUInt32(); 233 break; 234 case lldb_ds_i386: 235 tls_context.SegDs = reg_value.GetAsUInt32(); 236 break; 237 case lldb_es_i386: 238 tls_context.SegEs = reg_value.GetAsUInt32(); 239 break; 240 } 241 242 return SetThreadContextHelper(thread_handle, &tls_context); 243 } 244 245 Status NativeRegisterContextWindows_i386::DRRead(const uint32_t reg, 246 RegisterValue ®_value) { 247 ::CONTEXT tls_context; 248 DWORD context_flag = CONTEXT_DEBUG_REGISTERS; 249 Status error = 250 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag); 251 if (error.Fail()) 252 return error; 253 254 switch (reg) { 255 case lldb_dr0_i386: 256 reg_value.SetUInt32(tls_context.Dr0); 257 break; 258 case lldb_dr1_i386: 259 reg_value.SetUInt32(tls_context.Dr1); 260 break; 261 case lldb_dr2_i386: 262 reg_value.SetUInt32(tls_context.Dr2); 263 break; 264 case lldb_dr3_i386: 265 reg_value.SetUInt32(tls_context.Dr3); 266 break; 267 case lldb_dr4_i386: 268 return Status::FromErrorString("register DR4 is obsolete"); 269 case lldb_dr5_i386: 270 return Status::FromErrorString("register DR5 is obsolete"); 271 case lldb_dr6_i386: 272 reg_value.SetUInt32(tls_context.Dr6); 273 break; 274 case lldb_dr7_i386: 275 reg_value.SetUInt32(tls_context.Dr7); 276 break; 277 } 278 279 return {}; 280 } 281 282 Status 283 NativeRegisterContextWindows_i386::DRWrite(const uint32_t reg, 284 const RegisterValue ®_value) { 285 ::CONTEXT tls_context; 286 DWORD context_flag = CONTEXT_DEBUG_REGISTERS; 287 auto thread_handle = GetThreadHandle(); 288 Status error = 289 GetThreadContextHelper(thread_handle, &tls_context, context_flag); 290 if (error.Fail()) 291 return error; 292 293 switch (reg) { 294 case lldb_dr0_i386: 295 tls_context.Dr0 = reg_value.GetAsUInt32(); 296 break; 297 case lldb_dr1_i386: 298 tls_context.Dr1 = reg_value.GetAsUInt32(); 299 break; 300 case lldb_dr2_i386: 301 tls_context.Dr2 = reg_value.GetAsUInt32(); 302 break; 303 case lldb_dr3_i386: 304 tls_context.Dr3 = reg_value.GetAsUInt32(); 305 break; 306 case lldb_dr4_i386: 307 return Status::FromErrorString("register DR4 is obsolete"); 308 case lldb_dr5_i386: 309 return Status::FromErrorString("register DR5 is obsolete"); 310 case lldb_dr6_i386: 311 tls_context.Dr6 = reg_value.GetAsUInt32(); 312 break; 313 case lldb_dr7_i386: 314 tls_context.Dr7 = reg_value.GetAsUInt32(); 315 break; 316 } 317 318 return SetThreadContextHelper(thread_handle, &tls_context); 319 } 320 321 Status 322 NativeRegisterContextWindows_i386::ReadRegister(const RegisterInfo *reg_info, 323 RegisterValue ®_value) { 324 Status error; 325 326 if (!reg_info) { 327 error = Status::FromErrorString("reg_info NULL"); 328 return error; 329 } 330 331 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 332 if (reg == LLDB_INVALID_REGNUM) { 333 // This is likely an internal register for lldb use only and should not be 334 // directly queried. 335 error = Status::FromErrorStringWithFormat( 336 "register \"%s\" is an internal-only lldb " 337 "register, cannot read directly", 338 reg_info->name); 339 return error; 340 } 341 342 if (IsGPR(reg)) 343 return GPRRead(reg, reg_value); 344 345 if (IsDR(reg)) 346 return DRRead(reg, reg_value); 347 348 return Status::FromErrorString("unimplemented"); 349 } 350 351 Status NativeRegisterContextWindows_i386::WriteRegister( 352 const RegisterInfo *reg_info, const RegisterValue ®_value) { 353 Status error; 354 355 if (!reg_info) { 356 error = Status::FromErrorString("reg_info NULL"); 357 return error; 358 } 359 360 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 361 if (reg == LLDB_INVALID_REGNUM) { 362 // This is likely an internal register for lldb use only and should not be 363 // directly written. 364 error = Status::FromErrorStringWithFormat( 365 "register \"%s\" is an internal-only lldb " 366 "register, cannot write directly", 367 reg_info->name); 368 return error; 369 } 370 371 if (IsGPR(reg)) 372 return GPRWrite(reg, reg_value); 373 374 if (IsDR(reg)) 375 return DRWrite(reg, reg_value); 376 377 return Status::FromErrorString("unimplemented"); 378 } 379 380 Status NativeRegisterContextWindows_i386::ReadAllRegisterValues( 381 lldb::WritableDataBufferSP &data_sp) { 382 const size_t data_size = REG_CONTEXT_SIZE; 383 data_sp = std::make_shared<DataBufferHeap>(data_size, 0); 384 ::CONTEXT tls_context; 385 Status error = 386 GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL); 387 if (error.Fail()) 388 return error; 389 390 uint8_t *dst = data_sp->GetBytes(); 391 ::memcpy(dst, &tls_context, data_size); 392 return error; 393 } 394 395 Status NativeRegisterContextWindows_i386::WriteAllRegisterValues( 396 const lldb::DataBufferSP &data_sp) { 397 Status error; 398 const size_t data_size = REG_CONTEXT_SIZE; 399 if (!data_sp) { 400 error = Status::FromErrorStringWithFormat( 401 "NativeRegisterContextWindows_i386::%s invalid data_sp provided", 402 __FUNCTION__); 403 return error; 404 } 405 406 if (data_sp->GetByteSize() != data_size) { 407 error = Status::FromErrorStringWithFormatv( 408 "data_sp contained mismatched data size, expected {0}, actual {1}", 409 data_size, data_sp->GetByteSize()); 410 return error; 411 } 412 413 ::CONTEXT tls_context; 414 memcpy(&tls_context, data_sp->GetBytes(), data_size); 415 return SetThreadContextHelper(GetThreadHandle(), &tls_context); 416 } 417 418 Status NativeRegisterContextWindows_i386::IsWatchpointHit(uint32_t wp_index, 419 bool &is_hit) { 420 is_hit = false; 421 422 if (wp_index >= NumSupportedHardwareWatchpoints()) 423 return Status::FromErrorString("watchpoint index out of range"); 424 425 RegisterValue reg_value; 426 Status error = DRRead(lldb_dr6_i386, reg_value); 427 if (error.Fail()) 428 return error; 429 430 is_hit = reg_value.GetAsUInt32() & (1 << wp_index); 431 432 return {}; 433 } 434 435 Status NativeRegisterContextWindows_i386::GetWatchpointHitIndex( 436 uint32_t &wp_index, lldb::addr_t trap_addr) { 437 wp_index = LLDB_INVALID_INDEX32; 438 439 for (uint32_t i = 0; i < NumSupportedHardwareWatchpoints(); i++) { 440 bool is_hit; 441 Status error = IsWatchpointHit(i, is_hit); 442 if (error.Fail()) 443 return error; 444 445 if (is_hit) { 446 wp_index = i; 447 return {}; 448 } 449 } 450 451 return {}; 452 } 453 454 Status NativeRegisterContextWindows_i386::IsWatchpointVacant(uint32_t wp_index, 455 bool &is_vacant) { 456 is_vacant = false; 457 458 if (wp_index >= NumSupportedHardwareWatchpoints()) 459 return Status::FromErrorString("Watchpoint index out of range"); 460 461 RegisterValue reg_value; 462 Status error = DRRead(lldb_dr7_i386, reg_value); 463 if (error.Fail()) 464 return error; 465 466 is_vacant = !(reg_value.GetAsUInt32() & (1 << (2 * wp_index))); 467 468 return error; 469 } 470 471 bool NativeRegisterContextWindows_i386::ClearHardwareWatchpoint( 472 uint32_t wp_index) { 473 if (wp_index >= NumSupportedHardwareWatchpoints()) 474 return false; 475 476 // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of 477 // the debug status register (DR6) 478 479 RegisterValue reg_value; 480 Status error = DRRead(lldb_dr6_i386, reg_value); 481 if (error.Fail()) 482 return false; 483 484 uint32_t bit_mask = 1 << wp_index; 485 uint32_t status_bits = reg_value.GetAsUInt32() & ~bit_mask; 486 error = DRWrite(lldb_dr6_i386, RegisterValue(status_bits)); 487 if (error.Fail()) 488 return false; 489 490 // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, 491 // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register 492 // (DR7) 493 494 error = DRRead(lldb_dr7_i386, reg_value); 495 if (error.Fail()) 496 return false; 497 498 bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 499 uint32_t control_bits = reg_value.GetAsUInt32() & ~bit_mask; 500 return DRWrite(lldb_dr7_i386, RegisterValue(control_bits)).Success(); 501 } 502 503 Status NativeRegisterContextWindows_i386::ClearAllHardwareWatchpoints() { 504 RegisterValue reg_value; 505 506 // clear bits {0-4} of the debug status register (DR6) 507 508 Status error = DRRead(lldb_dr6_i386, reg_value); 509 if (error.Fail()) 510 return error; 511 512 uint32_t status_bits = reg_value.GetAsUInt32() & ~0xF; 513 error = DRWrite(lldb_dr6_i386, RegisterValue(status_bits)); 514 if (error.Fail()) 515 return error; 516 517 // clear bits {0-7,16-31} of the debug control register (DR7) 518 519 error = DRRead(lldb_dr7_i386, reg_value); 520 if (error.Fail()) 521 return error; 522 523 uint32_t control_bits = reg_value.GetAsUInt32() & ~0xFFFF00FF; 524 return DRWrite(lldb_dr7_i386, RegisterValue(control_bits)); 525 } 526 527 uint32_t NativeRegisterContextWindows_i386::SetHardwareWatchpoint( 528 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 529 switch (size) { 530 case 1: 531 case 2: 532 case 4: 533 break; 534 default: 535 return LLDB_INVALID_INDEX32; 536 } 537 538 if (watch_flags == 0x2) 539 watch_flags = 0x3; 540 541 if (watch_flags != 0x1 && watch_flags != 0x3) 542 return LLDB_INVALID_INDEX32; 543 544 for (uint32_t wp_index = 0; wp_index < NumSupportedHardwareWatchpoints(); 545 ++wp_index) { 546 bool is_vacant; 547 if (IsWatchpointVacant(wp_index, is_vacant).Fail()) 548 return LLDB_INVALID_INDEX32; 549 550 if (is_vacant) { 551 if (!ClearHardwareWatchpoint(wp_index)) 552 return LLDB_INVALID_INDEX32; 553 554 if (ApplyHardwareBreakpoint(wp_index, addr, size, watch_flags).Fail()) 555 return LLDB_INVALID_INDEX32; 556 557 return wp_index; 558 } 559 } 560 return LLDB_INVALID_INDEX32; 561 } 562 563 Status NativeRegisterContextWindows_i386::ApplyHardwareBreakpoint( 564 uint32_t wp_index, lldb::addr_t addr, size_t size, uint32_t flags) { 565 RegisterValue reg_value; 566 auto error = DRRead(lldb_dr7_i386, reg_value); 567 if (error.Fail()) 568 return error; 569 570 // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 571 uint32_t enable_bit = 1 << (2 * wp_index); 572 573 // set bits 16-17, 20-21, 24-25, or 28-29 574 // with 0b01 for write, and 0b11 for read/write 575 uint32_t rw_bits = flags << (16 + 4 * wp_index); 576 577 // set bits 18-19, 22-23, 26-27, or 30-31 578 // with 0b00, 0b01, 0b10, or 0b11 579 // for 1, 2, 8 (if supported), or 4 bytes, respectively 580 uint32_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); 581 582 uint32_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); 583 584 uint32_t control_bits = reg_value.GetAsUInt32() & ~bit_mask; 585 control_bits |= enable_bit | rw_bits | size_bits; 586 587 error = DRWrite(lldb_dr7_i386, RegisterValue(control_bits)); 588 if (error.Fail()) 589 return error; 590 591 error = DRWrite(lldb_dr0_i386 + wp_index, RegisterValue(addr)); 592 if (error.Fail()) 593 return error; 594 595 return {}; 596 } 597 598 lldb::addr_t 599 NativeRegisterContextWindows_i386::GetWatchpointAddress(uint32_t wp_index) { 600 if (wp_index >= NumSupportedHardwareWatchpoints()) 601 return LLDB_INVALID_ADDRESS; 602 603 RegisterValue reg_value; 604 if (DRRead(lldb_dr0_i386 + wp_index, reg_value).Fail()) 605 return LLDB_INVALID_ADDRESS; 606 607 return reg_value.GetAsUInt32(); 608 } 609 610 uint32_t NativeRegisterContextWindows_i386::NumSupportedHardwareWatchpoints() { 611 return 4; 612 } 613 614 #endif 615