1 //===-- NativeRegisterContextWindows_WoW64.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(_WIN64) 10 11 #include "NativeRegisterContextWindows_WoW64.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(::WOW64_CONTEXT) 29 30 namespace { 31 static const uint32_t g_gpr_regnums_WoW64[] = { 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 set must be terminated with this flag. 37 }; 38 39 static const RegisterSet g_reg_sets_WoW64[] = { 40 {"General Purpose Registers", "gpr", 41 llvm::array_lengthof(g_gpr_regnums_WoW64) - 1, g_gpr_regnums_WoW64}, 42 }; 43 enum { k_num_register_sets = 1 }; 44 45 static const DWORD kWoW64ContextFlags = 46 WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS; 47 48 } // namespace 49 50 static RegisterInfoInterface * 51 CreateRegisterInfoInterface(const ArchSpec &target_arch) { 52 // i686 32bit instruction set. 53 assert((target_arch.GetAddressByteSize() == 4 && 54 HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 55 "Register setting path assumes this is a 64-bit host"); 56 return new RegisterContextWindows_i386(target_arch); 57 } 58 59 static Status GetWoW64ThreadContextHelper(lldb::thread_t thread_handle, 60 PWOW64_CONTEXT context_ptr) { 61 Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 62 Status error; 63 memset(context_ptr, 0, sizeof(::WOW64_CONTEXT)); 64 context_ptr->ContextFlags = kWoW64ContextFlags; 65 if (!::Wow64GetThreadContext(thread_handle, context_ptr)) { 66 error.SetError(GetLastError(), eErrorTypeWin32); 67 LLDB_LOG(log, "{0} Wow64GetThreadContext failed with error {1}", 68 __FUNCTION__, error); 69 return error; 70 } 71 return Status(); 72 } 73 74 static Status SetWoW64ThreadContextHelper(lldb::thread_t thread_handle, 75 PWOW64_CONTEXT context_ptr) { 76 Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 77 Status error; 78 if (!::Wow64SetThreadContext(thread_handle, context_ptr)) { 79 error.SetError(GetLastError(), eErrorTypeWin32); 80 LLDB_LOG(log, "{0} Wow64SetThreadContext failed with error {1}", 81 __FUNCTION__, error); 82 return error; 83 } 84 return Status(); 85 } 86 87 NativeRegisterContextWindows_WoW64::NativeRegisterContextWindows_WoW64( 88 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 89 : NativeRegisterContextWindows(native_thread, 90 CreateRegisterInfoInterface(target_arch)) {} 91 92 bool NativeRegisterContextWindows_WoW64::IsGPR(uint32_t reg_index) const { 93 return (reg_index >= k_first_gpr_i386 && reg_index < k_first_alias_i386); 94 } 95 96 uint32_t NativeRegisterContextWindows_WoW64::GetRegisterSetCount() const { 97 return k_num_register_sets; 98 } 99 100 const RegisterSet * 101 NativeRegisterContextWindows_WoW64::GetRegisterSet(uint32_t set_index) const { 102 if (set_index >= k_num_register_sets) 103 return nullptr; 104 return &g_reg_sets_WoW64[set_index]; 105 } 106 107 Status NativeRegisterContextWindows_WoW64::GPRRead(const uint32_t reg, 108 RegisterValue ®_value) { 109 ::WOW64_CONTEXT tls_context; 110 Status error = GetWoW64ThreadContextHelper(GetThreadHandle(), &tls_context); 111 if (error.Fail()) 112 return error; 113 114 switch (reg) { 115 case lldb_eax_i386: 116 reg_value.SetUInt32(tls_context.Eax); 117 break; 118 case lldb_ebx_i386: 119 reg_value.SetUInt32(tls_context.Ebx); 120 break; 121 case lldb_ecx_i386: 122 reg_value.SetUInt32(tls_context.Ecx); 123 break; 124 case lldb_edx_i386: 125 reg_value.SetUInt32(tls_context.Edx); 126 break; 127 case lldb_edi_i386: 128 reg_value.SetUInt32(tls_context.Edi); 129 break; 130 case lldb_esi_i386: 131 reg_value.SetUInt32(tls_context.Esi); 132 break; 133 case lldb_ebp_i386: 134 reg_value.SetUInt32(tls_context.Ebp); 135 break; 136 case lldb_esp_i386: 137 reg_value.SetUInt32(tls_context.Esp); 138 break; 139 case lldb_eip_i386: 140 reg_value.SetUInt32(tls_context.Eip); 141 break; 142 case lldb_eflags_i386: 143 reg_value.SetUInt32(tls_context.EFlags); 144 break; 145 case lldb_cs_i386: 146 reg_value.SetUInt32(tls_context.SegCs); 147 break; 148 case lldb_fs_i386: 149 reg_value.SetUInt32(tls_context.SegFs); 150 break; 151 case lldb_gs_i386: 152 reg_value.SetUInt32(tls_context.SegGs); 153 break; 154 case lldb_ss_i386: 155 reg_value.SetUInt32(tls_context.SegSs); 156 break; 157 case lldb_ds_i386: 158 reg_value.SetUInt32(tls_context.SegDs); 159 break; 160 case lldb_es_i386: 161 reg_value.SetUInt32(tls_context.SegEs); 162 break; 163 } 164 165 return error; 166 } 167 168 Status 169 NativeRegisterContextWindows_WoW64::GPRWrite(const uint32_t reg, 170 const RegisterValue ®_value) { 171 ::WOW64_CONTEXT tls_context; 172 auto thread_handle = GetThreadHandle(); 173 Status error = GetWoW64ThreadContextHelper(thread_handle, &tls_context); 174 if (error.Fail()) 175 return error; 176 177 switch (reg) { 178 case lldb_eax_i386: 179 tls_context.Eax = reg_value.GetAsUInt32(); 180 break; 181 case lldb_ebx_i386: 182 tls_context.Ebx = reg_value.GetAsUInt32(); 183 break; 184 case lldb_ecx_i386: 185 tls_context.Ecx = reg_value.GetAsUInt32(); 186 break; 187 case lldb_edx_i386: 188 tls_context.Edx = reg_value.GetAsUInt32(); 189 break; 190 case lldb_edi_i386: 191 tls_context.Edi = reg_value.GetAsUInt32(); 192 break; 193 case lldb_esi_i386: 194 tls_context.Esi = reg_value.GetAsUInt32(); 195 break; 196 case lldb_ebp_i386: 197 tls_context.Ebp = reg_value.GetAsUInt32(); 198 break; 199 case lldb_esp_i386: 200 tls_context.Esp = reg_value.GetAsUInt32(); 201 break; 202 case lldb_eip_i386: 203 tls_context.Eip = reg_value.GetAsUInt32(); 204 break; 205 case lldb_eflags_i386: 206 tls_context.EFlags = reg_value.GetAsUInt32(); 207 break; 208 case lldb_cs_i386: 209 tls_context.SegCs = reg_value.GetAsUInt32(); 210 break; 211 case lldb_fs_i386: 212 tls_context.SegFs = reg_value.GetAsUInt32(); 213 break; 214 case lldb_gs_i386: 215 tls_context.SegGs = reg_value.GetAsUInt32(); 216 break; 217 case lldb_ss_i386: 218 tls_context.SegSs = reg_value.GetAsUInt32(); 219 break; 220 case lldb_ds_i386: 221 tls_context.SegDs = reg_value.GetAsUInt32(); 222 break; 223 case lldb_es_i386: 224 tls_context.SegEs = reg_value.GetAsUInt32(); 225 break; 226 } 227 228 return SetWoW64ThreadContextHelper(thread_handle, &tls_context); 229 } 230 231 Status 232 NativeRegisterContextWindows_WoW64::ReadRegister(const RegisterInfo *reg_info, 233 RegisterValue ®_value) { 234 Status error; 235 if (!reg_info) { 236 error.SetErrorString("reg_info NULL"); 237 return error; 238 } 239 240 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 241 if (reg == LLDB_INVALID_REGNUM) { 242 // This is likely an internal register for lldb use only and should not be 243 // directly queried. 244 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 245 "register, cannot read directly", 246 reg_info->name); 247 return error; 248 } 249 250 if (IsGPR(reg)) 251 return GPRRead(reg, reg_value); 252 253 return Status("unimplemented"); 254 } 255 256 Status NativeRegisterContextWindows_WoW64::WriteRegister( 257 const RegisterInfo *reg_info, const RegisterValue ®_value) { 258 Status error; 259 260 if (!reg_info) { 261 error.SetErrorString("reg_info NULL"); 262 return error; 263 } 264 265 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 266 if (reg == LLDB_INVALID_REGNUM) { 267 // This is likely an internal register for lldb use only and should not be 268 // directly queried. 269 error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " 270 "register, cannot read directly", 271 reg_info->name); 272 return error; 273 } 274 275 if (IsGPR(reg)) 276 return GPRWrite(reg, reg_value); 277 278 return Status("unimplemented"); 279 } 280 281 Status NativeRegisterContextWindows_WoW64::ReadAllRegisterValues( 282 lldb::DataBufferSP &data_sp) { 283 const size_t data_size = REG_CONTEXT_SIZE; 284 data_sp = std::make_shared<DataBufferHeap>(data_size, 0); 285 ::WOW64_CONTEXT tls_context; 286 Status error = GetWoW64ThreadContextHelper(GetThreadHandle(), &tls_context); 287 if (error.Fail()) 288 return error; 289 290 uint8_t *dst = data_sp->GetBytes(); 291 ::memcpy(dst, &tls_context, data_size); 292 return error; 293 } 294 295 Status NativeRegisterContextWindows_WoW64::WriteAllRegisterValues( 296 const lldb::DataBufferSP &data_sp) { 297 Status error; 298 const size_t data_size = REG_CONTEXT_SIZE; 299 if (!data_sp) { 300 error.SetErrorStringWithFormat( 301 "NativeRegisterContextWindows_WoW64::%s invalid data_sp provided", 302 __FUNCTION__); 303 return error; 304 } 305 306 if (data_sp->GetByteSize() != data_size) { 307 error.SetErrorStringWithFormatv( 308 "data_sp contained mismatched data size, expected {0}, actual {1}", 309 data_size, data_sp->GetByteSize()); 310 return error; 311 } 312 313 ::WOW64_CONTEXT tls_context; 314 memcpy(&tls_context, data_sp->GetBytes(), data_size); 315 return SetWoW64ThreadContextHelper(GetThreadHandle(), &tls_context); 316 } 317 318 Status NativeRegisterContextWindows_WoW64::IsWatchpointHit(uint32_t wp_index, 319 bool &is_hit) { 320 return Status("unimplemented"); 321 } 322 323 Status NativeRegisterContextWindows_WoW64::GetWatchpointHitIndex( 324 uint32_t &wp_index, lldb::addr_t trap_addr) { 325 return Status("unimplemented"); 326 } 327 328 Status NativeRegisterContextWindows_WoW64::IsWatchpointVacant(uint32_t wp_index, 329 bool &is_vacant) { 330 return Status("unimplemented"); 331 } 332 333 Status NativeRegisterContextWindows_WoW64::SetHardwareWatchpointWithIndex( 334 lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { 335 return Status("unimplemented"); 336 } 337 338 bool NativeRegisterContextWindows_WoW64::ClearHardwareWatchpoint( 339 uint32_t wp_index) { 340 return false; 341 } 342 343 Status NativeRegisterContextWindows_WoW64::ClearAllHardwareWatchpoints() { 344 return Status("unimplemented"); 345 } 346 347 uint32_t NativeRegisterContextWindows_WoW64::SetHardwareWatchpoint( 348 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 349 return LLDB_INVALID_INDEX32; 350 } 351 352 lldb::addr_t 353 NativeRegisterContextWindows_WoW64::GetWatchpointAddress(uint32_t wp_index) { 354 return LLDB_INVALID_ADDRESS; 355 } 356 357 uint32_t NativeRegisterContextWindows_WoW64::NumSupportedHardwareWatchpoints() { 358 // Not implemented 359 return 0; 360 } 361 362 #endif // defined(_WIN64) 363