1 //===-- NativeRegisterContextWindows_i386.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(_WIN32) && !defined(_WIN64) 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", 41 llvm::array_lengthof(g_gpr_regnums_i386) - 1, 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 = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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.SetError(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 = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 75 Status error; 76 77 if (!::SetThreadContext(thread_handle, context_ptr)) { 78 error.SetError(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 llvm::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 uint32_t NativeRegisterContextWindows_i386::GetRegisterSetCount() const { 103 return k_num_register_sets; 104 } 105 106 const RegisterSet * 107 NativeRegisterContextWindows_i386::GetRegisterSet(uint32_t set_index) const { 108 if (set_index >= k_num_register_sets) 109 return nullptr; 110 return &g_reg_sets_i386[set_index]; 111 } 112 113 Status NativeRegisterContextWindows_i386::GPRRead(const uint32_t reg, 114 RegisterValue ®_value) { 115 ::CONTEXT tls_context; 116 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; 117 Status error = 118 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag); 119 if (error.Fail()) 120 return error; 121 122 switch (reg) { 123 case lldb_eax_i386: 124 reg_value.SetUInt32(tls_context.Eax); 125 break; 126 case lldb_ebx_i386: 127 reg_value.SetUInt32(tls_context.Ebx); 128 break; 129 case lldb_ecx_i386: 130 reg_value.SetUInt32(tls_context.Ecx); 131 break; 132 case lldb_edx_i386: 133 reg_value.SetUInt32(tls_context.Edx); 134 break; 135 case lldb_edi_i386: 136 reg_value.SetUInt32(tls_context.Edi); 137 break; 138 case lldb_esi_i386: 139 reg_value.SetUInt32(tls_context.Esi); 140 break; 141 case lldb_ebp_i386: 142 reg_value.SetUInt32(tls_context.Ebp); 143 break; 144 case lldb_esp_i386: 145 reg_value.SetUInt32(tls_context.Esp); 146 break; 147 case lldb_eip_i386: 148 reg_value.SetUInt32(tls_context.Eip); 149 break; 150 case lldb_eflags_i386: 151 reg_value.SetUInt32(tls_context.EFlags); 152 break; 153 case lldb_cs_i386: 154 reg_value.SetUInt32(tls_context.SegCs); 155 break; 156 case lldb_fs_i386: 157 reg_value.SetUInt32(tls_context.SegFs); 158 break; 159 case lldb_gs_i386: 160 reg_value.SetUInt32(tls_context.SegGs); 161 break; 162 case lldb_ss_i386: 163 reg_value.SetUInt32(tls_context.SegSs); 164 break; 165 case lldb_ds_i386: 166 reg_value.SetUInt32(tls_context.SegDs); 167 break; 168 case lldb_es_i386: 169 reg_value.SetUInt32(tls_context.SegEs); 170 break; 171 } 172 173 return error; 174 } 175 176 Status 177 NativeRegisterContextWindows_i386::GPRWrite(const uint32_t reg, 178 const RegisterValue ®_value) { 179 ::CONTEXT tls_context; 180 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; 181 auto thread_handle = GetThreadHandle(); 182 Status error = 183 GetThreadContextHelper(thread_handle, &tls_context, context_flag); 184 if (error.Fail()) 185 return error; 186 187 switch (reg) { 188 case lldb_eax_i386: 189 tls_context.Eax = reg_value.GetAsUInt32(); 190 break; 191 case lldb_ebx_i386: 192 tls_context.Ebx = reg_value.GetAsUInt32(); 193 break; 194 case lldb_ecx_i386: 195 tls_context.Ecx = reg_value.GetAsUInt32(); 196 break; 197 case lldb_edx_i386: 198 tls_context.Edx = reg_value.GetAsUInt32(); 199 break; 200 case lldb_edi_i386: 201 tls_context.Edi = reg_value.GetAsUInt32(); 202 break; 203 case lldb_esi_i386: 204 tls_context.Esi = reg_value.GetAsUInt32(); 205 break; 206 case lldb_ebp_i386: 207 tls_context.Ebp = reg_value.GetAsUInt32(); 208 break; 209 case lldb_esp_i386: 210 tls_context.Esp = reg_value.GetAsUInt32(); 211 break; 212 case lldb_eip_i386: 213 tls_context.Eip = reg_value.GetAsUInt32(); 214 break; 215 case lldb_eflags_i386: 216 tls_context.EFlags = reg_value.GetAsUInt32(); 217 break; 218 case lldb_cs_i386: 219 tls_context.SegCs = reg_value.GetAsUInt32(); 220 break; 221 case lldb_fs_i386: 222 tls_context.SegFs = reg_value.GetAsUInt32(); 223 break; 224 case lldb_gs_i386: 225 tls_context.SegGs = reg_value.GetAsUInt32(); 226 break; 227 case lldb_ss_i386: 228 tls_context.SegSs = reg_value.GetAsUInt32(); 229 break; 230 case lldb_ds_i386: 231 tls_context.SegDs = reg_value.GetAsUInt32(); 232 break; 233 case lldb_es_i386: 234 tls_context.SegEs = reg_value.GetAsUInt32(); 235 break; 236 } 237 238 return SetThreadContextHelper(thread_handle, &tls_context); 239 } 240 241 Status 242 NativeRegisterContextWindows_i386::ReadRegister(const RegisterInfo *reg_info, 243 RegisterValue ®_value) { 244 Status error; 245 Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 246 247 if (!reg_info) { 248 error.SetErrorString("reg_info NULL"); 249 return error; 250 } 251 252 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 253 if (reg == LLDB_INVALID_REGNUM) { 254 // This is likely an internal register for lldb use only and should not be 255 // directly queried. 256 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 257 "register, cannot read directly", 258 reg_info->name); 259 return error; 260 } 261 262 if (IsGPR(reg)) 263 return GPRRead(reg, reg_value); 264 265 return Status("unimplemented"); 266 } 267 268 Status NativeRegisterContextWindows_i386::WriteRegister( 269 const RegisterInfo *reg_info, const RegisterValue ®_value) { 270 Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 271 Status error; 272 273 if (!reg_info) { 274 error.SetErrorString("reg_info NULL"); 275 return error; 276 } 277 278 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 279 if (reg == LLDB_INVALID_REGNUM) { 280 // This is likely an internal register for lldb use only and should not be 281 // directly queried. 282 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 283 "register, cannot read directly", 284 reg_info->name); 285 return error; 286 } 287 288 if (IsGPR(reg)) 289 return GPRRead(reg, reg_value); 290 291 return Status("unimplemented"); 292 } 293 294 Status NativeRegisterContextWindows_x86_64::ReadAllRegisterValues( 295 lldb::DataBufferSP &data_sp) { 296 const size_t data_size = REG_CONTEXT_SIZE; 297 data_sp = std::make_shared<DataBufferHeap>(data_size, 0); 298 ::CONTEXT tls_context; 299 Status error = 300 GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL); 301 if (error.Fail()) 302 return error; 303 304 uint8_t *dst = data_sp->GetBytes(); 305 ::memcpy(dst, &tls_context, data_size); 306 return error; 307 } 308 309 Status NativeRegisterContextWindows_i386::WriteAllRegisterValues( 310 const lldb::DataBufferSP &data_sp) { 311 Status error; 312 const size_t data_size = REG_CONTEXT_SIZE; 313 if (!data_sp) { 314 error.SetErrorStringWithFormat( 315 "NativeRegisterContextWindows_i386::%s invalid data_sp provided", 316 __FUNCTION__); 317 return error; 318 } 319 320 if (data_sp->GetByteSize() != data_size) { 321 error.SetErrorStringWithFormatv( 322 "data_sp contained mismatched data size, expected {0}, actual {1}", 323 data_size, data_sp->GetByteSize()); 324 return error; 325 } 326 327 ::CONTEXT tls_context; 328 memcpy(&tls_context, data_sp->GetBytes(), data_size); 329 return SetThreadContextHelper(GetThreadHandle(), &tls_context); 330 } 331 332 Status NativeRegisterContextWindows_i386::IsWatchpointHit(uint32_t wp_index, 333 bool &is_hit) { 334 return Status("unimplemented"); 335 } 336 337 Status NativeRegisterContextWindows_i386::GetWatchpointHitIndex( 338 uint32_t &wp_index, lldb::addr_t trap_addr) { 339 return Status("unimplemented"); 340 } 341 342 Status NativeRegisterContextWindows_i386::IsWatchpointVacant(uint32_t wp_index, 343 bool &is_vacant) { 344 return Status("unimplemented"); 345 } 346 347 Status NativeRegisterContextWindows_i386::SetHardwareWatchpointWithIndex( 348 lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { 349 return Status("unimplemented"); 350 } 351 352 bool NativeRegisterContextWindows_i386::ClearHardwareWatchpoint( 353 uint32_t wp_index) { 354 return false; 355 } 356 357 Status NativeRegisterContextWindows_i386::ClearAllHardwareWatchpoints() { 358 return Status("unimplemented"); 359 } 360 361 uint32_t NativeRegisterContextWindows_i386::SetHardwareWatchpoint( 362 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 363 return LLDB_INVALID_INDEX32; 364 } 365 366 lldb::addr_t 367 NativeRegisterContextWindows_i386::GetWatchpointAddress(uint32_t wp_index) { 368 return LLDB_INVALID_ADDRESS; 369 } 370 371 uint32_t NativeRegisterContextWindows_i386::NumSupportedHardwareWatchpoints() { 372 // Not implemented 373 return 0; 374 } 375 376 #endif 377