|
| 1 | +//===-- RegisterContextWindows_x86.h ----------------------------*- C++ -*-===// |
| 2 | +// |
| 3 | +// The LLVM Compiler Infrastructure |
| 4 | +// |
| 5 | +// This file is distributed under the University of Illinois Open Source |
| 6 | +// License. See LICENSE.TXT for details. |
| 7 | +// |
| 8 | +//===----------------------------------------------------------------------===// |
| 9 | + |
| 10 | +#include "lldb/lldb-private-types.h" |
| 11 | +#include "lldb/Core/DataBufferHeap.h" |
| 12 | +#include "lldb/Core/Error.h" |
| 13 | +#include "lldb/Core/RegisterValue.h" |
| 14 | +#include "lldb/Host/windows/HostThreadWindows.h" |
| 15 | +#include "lldb/Host/windows/windows.h" |
| 16 | + |
| 17 | +#include "lldb-x86-register-enums.h" |
| 18 | +#include "RegisterContext_x86.h" |
| 19 | +#include "RegisterContextWindows_x86.h" |
| 20 | +#include "TargetThreadWindows.h" |
| 21 | + |
| 22 | +#include "llvm/ADT/STLExtras.h" |
| 23 | + |
| 24 | +using namespace lldb; |
| 25 | +using namespace lldb_private; |
| 26 | + |
| 27 | +#define DEFINE_GPR32(reg, offset, generic_reg) \ |
| 28 | + { \ |
| 29 | + #reg, nullptr, 4, offset, eEncodingUint, eFormatHexUppercase, \ |
| 30 | + {gcc_##reg##_i386, dwarf_##reg##_i386, generic_reg, gdb_##reg##_i386, gpr_##reg##_i386 }, nullptr, nullptr \ |
| 31 | + } |
| 32 | + |
| 33 | +#define GPR_REGNUM(reg) gpr_##reg##_i386 |
| 34 | + |
| 35 | +// For now we're only supporting general purpose registers. Unfortunately we have to maintain |
| 36 | +// parallel arrays since that's how the RegisterContext interface expects things to be returned. |
| 37 | +// We might be able to fix this by initializing these arrays at runtime during the construction of |
| 38 | +// the RegisterContext by using helper functions that can update multiple arrays, register sets, |
| 39 | +// etc all at once through a more easily understandable interface. |
| 40 | + |
| 41 | +RegisterInfo g_register_infos[] = {DEFINE_GPR32(eax, offsetof(CONTEXT, Eax), LLDB_INVALID_REGNUM), |
| 42 | + DEFINE_GPR32(ebx, offsetof(CONTEXT, Ebx), LLDB_INVALID_REGNUM), |
| 43 | + DEFINE_GPR32(ecx, offsetof(CONTEXT, Ecx), LLDB_INVALID_REGNUM), |
| 44 | + DEFINE_GPR32(edx, offsetof(CONTEXT, Edx), LLDB_INVALID_REGNUM), |
| 45 | + DEFINE_GPR32(edi, offsetof(CONTEXT, Edi), LLDB_INVALID_REGNUM), |
| 46 | + DEFINE_GPR32(esi, offsetof(CONTEXT, Esi), LLDB_INVALID_REGNUM), |
| 47 | + DEFINE_GPR32(ebp, offsetof(CONTEXT, Ebp), LLDB_REGNUM_GENERIC_FP), |
| 48 | + DEFINE_GPR32(esp, offsetof(CONTEXT, Esp), LLDB_REGNUM_GENERIC_SP), |
| 49 | + DEFINE_GPR32(eip, offsetof(CONTEXT, Eip), LLDB_REGNUM_GENERIC_PC), |
| 50 | + DEFINE_GPR32(eflags, offsetof(CONTEXT, EFlags), LLDB_REGNUM_GENERIC_FLAGS)}; |
| 51 | + |
| 52 | +uint32_t g_gpr_regnums[] = { |
| 53 | + GPR_REGNUM(eax), GPR_REGNUM(ebx), GPR_REGNUM(ecx), GPR_REGNUM(edx), GPR_REGNUM(edi), |
| 54 | + GPR_REGNUM(esi), GPR_REGNUM(ebp), GPR_REGNUM(esp), GPR_REGNUM(eip), GPR_REGNUM(eflags), |
| 55 | +}; |
| 56 | + |
| 57 | +RegisterSet g_register_sets[] = {{"General Purpose Registers", "gpr", llvm::array_lengthof(g_register_infos), g_gpr_regnums}}; |
| 58 | + |
| 59 | +//------------------------------------------------------------------ |
| 60 | +// Constructors and Destructors |
| 61 | +//------------------------------------------------------------------ |
| 62 | +RegisterContextWindows_x86::RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx) |
| 63 | + : RegisterContext(thread, concrete_frame_idx) |
| 64 | + , m_context_valid(false) |
| 65 | + , m_cached_context(new DataBufferHeap(sizeof(CONTEXT), 0)) |
| 66 | +{ |
| 67 | +} |
| 68 | + |
| 69 | +RegisterContextWindows_x86::~RegisterContextWindows_x86() |
| 70 | +{ |
| 71 | +} |
| 72 | + |
| 73 | +void |
| 74 | +RegisterContextWindows_x86::InvalidateAllRegisters() |
| 75 | +{ |
| 76 | + m_context_valid = false; |
| 77 | +} |
| 78 | + |
| 79 | +size_t |
| 80 | +RegisterContextWindows_x86::GetRegisterCount() |
| 81 | +{ |
| 82 | + return llvm::array_lengthof(g_register_infos); |
| 83 | +} |
| 84 | + |
| 85 | +const RegisterInfo * |
| 86 | +RegisterContextWindows_x86::GetRegisterInfoAtIndex(size_t reg) |
| 87 | +{ |
| 88 | + return &g_register_infos[reg]; |
| 89 | +} |
| 90 | + |
| 91 | +size_t |
| 92 | +RegisterContextWindows_x86::GetRegisterSetCount() |
| 93 | +{ |
| 94 | + return llvm::array_lengthof(g_register_sets); |
| 95 | +} |
| 96 | + |
| 97 | +const RegisterSet * |
| 98 | +RegisterContextWindows_x86::GetRegisterSet(size_t reg_set) |
| 99 | +{ |
| 100 | + return &g_register_sets[reg_set]; |
| 101 | +} |
| 102 | + |
| 103 | +bool |
| 104 | +RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) |
| 105 | +{ |
| 106 | + // For now we're reading the value of every register, and then returning the one that was |
| 107 | + // requested. We should be smarter about this in the future. |
| 108 | + if (!CacheAllRegisterValues()) |
| 109 | + return false; |
| 110 | + |
| 111 | + CONTEXT *context = GetSystemContext(); |
| 112 | + switch (reg_info->kinds[eRegisterKindLLDB]) |
| 113 | + { |
| 114 | + case gpr_eax_i386: |
| 115 | + reg_value.SetUInt32(context->Eax); |
| 116 | + break; |
| 117 | + case gpr_ebx_i386: |
| 118 | + reg_value.SetUInt32(context->Ebx); |
| 119 | + break; |
| 120 | + case gpr_ecx_i386: |
| 121 | + reg_value.SetUInt32(context->Ecx); |
| 122 | + break; |
| 123 | + case gpr_edx_i386: |
| 124 | + reg_value.SetUInt32(context->Edx); |
| 125 | + break; |
| 126 | + case gpr_edi_i386: |
| 127 | + reg_value.SetUInt32(context->Edi); |
| 128 | + break; |
| 129 | + case gpr_esi_i386: |
| 130 | + reg_value.SetUInt32(context->Esi); |
| 131 | + break; |
| 132 | + case gpr_ebp_i386: |
| 133 | + reg_value.SetUInt32(context->Ebp); |
| 134 | + break; |
| 135 | + case gpr_esp_i386: |
| 136 | + reg_value.SetUInt32(context->Esp); |
| 137 | + break; |
| 138 | + case gpr_eip_i386: |
| 139 | + reg_value.SetUInt32(context->Eip); |
| 140 | + break; |
| 141 | + case gpr_eflags_i386: |
| 142 | + reg_value.SetUInt32(context->EFlags); |
| 143 | + break; |
| 144 | + } |
| 145 | + return true; |
| 146 | +} |
| 147 | + |
| 148 | +bool |
| 149 | +RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value) |
| 150 | +{ |
| 151 | + // Since we cannot only write a single register value to the inferior, we need to make sure |
| 152 | + // our cached copy of the register values are fresh. Otherwise when writing EAX, for example, |
| 153 | + // we may also overwrite some other register with a stale value. |
| 154 | + if (!CacheAllRegisterValues()) |
| 155 | + return false; |
| 156 | + |
| 157 | + CONTEXT *context = GetSystemContext(); |
| 158 | + switch (reg_info->kinds[eRegisterKindLLDB]) |
| 159 | + { |
| 160 | + case gpr_eax_i386: |
| 161 | + context->Eax = reg_value.GetAsUInt32(); |
| 162 | + break; |
| 163 | + case gpr_ebx_i386: |
| 164 | + context->Ebx = reg_value.GetAsUInt32(); |
| 165 | + break; |
| 166 | + case gpr_ecx_i386: |
| 167 | + context->Ecx = reg_value.GetAsUInt32(); |
| 168 | + break; |
| 169 | + case gpr_edx_i386: |
| 170 | + context->Edx = reg_value.GetAsUInt32(); |
| 171 | + break; |
| 172 | + case gpr_edi_i386: |
| 173 | + context->Edi = reg_value.GetAsUInt32(); |
| 174 | + break; |
| 175 | + case gpr_esi_i386: |
| 176 | + context->Esi = reg_value.GetAsUInt32(); |
| 177 | + break; |
| 178 | + case gpr_ebp_i386: |
| 179 | + context->Ebp = reg_value.GetAsUInt32(); |
| 180 | + break; |
| 181 | + case gpr_esp_i386: |
| 182 | + context->Esp = reg_value.GetAsUInt32(); |
| 183 | + break; |
| 184 | + case gpr_eip_i386: |
| 185 | + context->Eip = reg_value.GetAsUInt32(); |
| 186 | + break; |
| 187 | + case gpr_eflags_i386: |
| 188 | + context->EFlags = reg_value.GetAsUInt32(); |
| 189 | + break; |
| 190 | + } |
| 191 | + |
| 192 | + // Physically update the registers in the target process. |
| 193 | + TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); |
| 194 | + return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context); |
| 195 | +} |
| 196 | + |
| 197 | +bool |
| 198 | +RegisterContextWindows_x86::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) |
| 199 | +{ |
| 200 | + if (!CacheAllRegisterValues()) |
| 201 | + return false; |
| 202 | + |
| 203 | + if (data_sp->GetByteSize() != m_cached_context->GetByteSize()) |
| 204 | + return false; |
| 205 | + |
| 206 | + // Write the OS's internal CONTEXT structure into the buffer. |
| 207 | + memcpy(data_sp->GetBytes(), m_cached_context->GetBytes(), data_sp->GetByteSize()); |
| 208 | + return true; |
| 209 | +} |
| 210 | + |
| 211 | +bool |
| 212 | +RegisterContextWindows_x86::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) |
| 213 | +{ |
| 214 | + // Since we're given every register value in the input buffer, we don't need to worry about |
| 215 | + // making sure our cached copy is valid and then overwriting the modified values before we |
| 216 | + // push the full update to the OS. We do however need to update the cached copy with the value |
| 217 | + // that we're pushing to the OS. |
| 218 | + if (data_sp->GetByteSize() != m_cached_context->GetByteSize()) |
| 219 | + return false; |
| 220 | + |
| 221 | + CONTEXT *context = GetSystemContext(); |
| 222 | + TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); |
| 223 | + |
| 224 | + if (!::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context)) |
| 225 | + return false; |
| 226 | + |
| 227 | + // Since the thread context was set successfully, update our cached copy. |
| 228 | + memcpy(m_cached_context->GetBytes(), data_sp->GetBytes(), data_sp->GetByteSize()); |
| 229 | + return true; |
| 230 | +} |
| 231 | + |
| 232 | +uint32_t |
| 233 | +RegisterContextWindows_x86::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) |
| 234 | +{ |
| 235 | + const uint32_t num_regs = GetRegisterCount(); |
| 236 | + |
| 237 | + assert(kind < kNumRegisterKinds); |
| 238 | + for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) |
| 239 | + { |
| 240 | + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); |
| 241 | + |
| 242 | + if (reg_info->kinds[kind] == num) |
| 243 | + return reg_idx; |
| 244 | + } |
| 245 | + |
| 246 | + return LLDB_INVALID_REGNUM; |
| 247 | +} |
| 248 | + |
| 249 | +//------------------------------------------------------------------ |
| 250 | +// Subclasses can these functions if desired |
| 251 | +//------------------------------------------------------------------ |
| 252 | +uint32_t |
| 253 | +RegisterContextWindows_x86::NumSupportedHardwareBreakpoints() |
| 254 | +{ |
| 255 | + // Support for hardware breakpoints not yet implemented. |
| 256 | + return 0; |
| 257 | +} |
| 258 | + |
| 259 | +uint32_t |
| 260 | +RegisterContextWindows_x86::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) |
| 261 | +{ |
| 262 | + return 0; |
| 263 | +} |
| 264 | + |
| 265 | +bool |
| 266 | +RegisterContextWindows_x86::ClearHardwareBreakpoint(uint32_t hw_idx) |
| 267 | +{ |
| 268 | + return false; |
| 269 | +} |
| 270 | + |
| 271 | +uint32_t |
| 272 | +RegisterContextWindows_x86::NumSupportedHardwareWatchpoints() |
| 273 | +{ |
| 274 | + // Support for hardware watchpoints not yet implemented. |
| 275 | + return 0; |
| 276 | +} |
| 277 | + |
| 278 | +uint32_t |
| 279 | +RegisterContextWindows_x86::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write) |
| 280 | +{ |
| 281 | + return 0; |
| 282 | +} |
| 283 | + |
| 284 | +bool |
| 285 | +RegisterContextWindows_x86::ClearHardwareWatchpoint(uint32_t hw_index) |
| 286 | +{ |
| 287 | + return false; |
| 288 | +} |
| 289 | + |
| 290 | +bool |
| 291 | +RegisterContextWindows_x86::HardwareSingleStep(bool enable) |
| 292 | +{ |
| 293 | + return false; |
| 294 | +} |
| 295 | + |
| 296 | +CONTEXT * |
| 297 | +RegisterContextWindows_x86::GetSystemContext() |
| 298 | +{ |
| 299 | + return reinterpret_cast<CONTEXT *>(m_cached_context->GetBytes()); |
| 300 | +} |
| 301 | + |
| 302 | +bool |
| 303 | +RegisterContextWindows_x86::CacheAllRegisterValues() |
| 304 | +{ |
| 305 | + if (m_context_valid) |
| 306 | + return true; |
| 307 | + |
| 308 | + CONTEXT *context = GetSystemContext(); |
| 309 | + // Right now we just pull every single register, regardless of what register we're ultimately |
| 310 | + // going to read. We could be smarter about this, although it's not clear what the advantage |
| 311 | + // would be. |
| 312 | + context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; |
| 313 | + TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); |
| 314 | + if (!::GetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context)) |
| 315 | + return false; |
| 316 | + m_context_valid = true; |
| 317 | + return true; |
| 318 | +} |
0 commit comments