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(__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", 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 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 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 246 if (!reg_info) { 247 error.SetErrorString("reg_info NULL"); 248 return error; 249 } 250 251 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 252 if (reg == LLDB_INVALID_REGNUM) { 253 // This is likely an internal register for lldb use only and should not be 254 // directly queried. 255 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 256 "register, cannot read directly", 257 reg_info->name); 258 return error; 259 } 260 261 if (IsGPR(reg)) 262 return GPRRead(reg, reg_value); 263 264 return Status("unimplemented"); 265 } 266 267 Status NativeRegisterContextWindows_i386::WriteRegister( 268 const RegisterInfo *reg_info, const RegisterValue ®_value) { 269 Status error; 270 271 if (!reg_info) { 272 error.SetErrorString("reg_info NULL"); 273 return error; 274 } 275 276 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 277 if (reg == LLDB_INVALID_REGNUM) { 278 // This is likely an internal register for lldb use only and should not be 279 // directly written. 280 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 281 "register, cannot write directly", 282 reg_info->name); 283 return error; 284 } 285 286 if (IsGPR(reg)) 287 return GPRWrite(reg, reg_value); 288 289 return Status("unimplemented"); 290 } 291 292 Status NativeRegisterContextWindows_i386::ReadAllRegisterValues( 293 lldb::DataBufferSP &data_sp) { 294 const size_t data_size = REG_CONTEXT_SIZE; 295 data_sp = std::make_shared<DataBufferHeap>(data_size, 0); 296 ::CONTEXT tls_context; 297 Status error = 298 GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL); 299 if (error.Fail()) 300 return error; 301 302 uint8_t *dst = data_sp->GetBytes(); 303 ::memcpy(dst, &tls_context, data_size); 304 return error; 305 } 306 307 Status NativeRegisterContextWindows_i386::WriteAllRegisterValues( 308 const lldb::DataBufferSP &data_sp) { 309 Status error; 310 const size_t data_size = REG_CONTEXT_SIZE; 311 if (!data_sp) { 312 error.SetErrorStringWithFormat( 313 "NativeRegisterContextWindows_i386::%s invalid data_sp provided", 314 __FUNCTION__); 315 return error; 316 } 317 318 if (data_sp->GetByteSize() != data_size) { 319 error.SetErrorStringWithFormatv( 320 "data_sp contained mismatched data size, expected {0}, actual {1}", 321 data_size, data_sp->GetByteSize()); 322 return error; 323 } 324 325 ::CONTEXT tls_context; 326 memcpy(&tls_context, data_sp->GetBytes(), data_size); 327 return SetThreadContextHelper(GetThreadHandle(), &tls_context); 328 } 329 330 Status NativeRegisterContextWindows_i386::IsWatchpointHit(uint32_t wp_index, 331 bool &is_hit) { 332 return Status("unimplemented"); 333 } 334 335 Status NativeRegisterContextWindows_i386::GetWatchpointHitIndex( 336 uint32_t &wp_index, lldb::addr_t trap_addr) { 337 return Status("unimplemented"); 338 } 339 340 Status NativeRegisterContextWindows_i386::IsWatchpointVacant(uint32_t wp_index, 341 bool &is_vacant) { 342 return Status("unimplemented"); 343 } 344 345 Status NativeRegisterContextWindows_i386::SetHardwareWatchpointWithIndex( 346 lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { 347 return Status("unimplemented"); 348 } 349 350 bool NativeRegisterContextWindows_i386::ClearHardwareWatchpoint( 351 uint32_t wp_index) { 352 return false; 353 } 354 355 Status NativeRegisterContextWindows_i386::ClearAllHardwareWatchpoints() { 356 return Status("unimplemented"); 357 } 358 359 uint32_t NativeRegisterContextWindows_i386::SetHardwareWatchpoint( 360 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 361 return LLDB_INVALID_INDEX32; 362 } 363 364 lldb::addr_t 365 NativeRegisterContextWindows_i386::GetWatchpointAddress(uint32_t wp_index) { 366 return LLDB_INVALID_ADDRESS; 367 } 368 369 uint32_t NativeRegisterContextWindows_i386::NumSupportedHardwareWatchpoints() { 370 // Not implemented 371 return 0; 372 } 373 374 #endif 375