| 1 | //===-- RegisterContextWindows_x86.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 "lldb/Host/windows/HostThreadWindows.h" |
| 12 | #include "lldb/Host/windows/windows.h" |
| 13 | #include "lldb/Utility/RegisterValue.h" |
| 14 | #include "lldb/Utility/Status.h" |
| 15 | #include "lldb/lldb-private-types.h" |
| 16 | |
| 17 | #include "ProcessWindowsLog.h" |
| 18 | #include "RegisterContextWindows_x86.h" |
| 19 | #include "Plugins/Process/Utility/RegisterContext_x86.h" |
| 20 | #include "TargetThreadWindows.h" |
| 21 | #include "Plugins/Process/Utility/lldb-x86-register-enums.h" |
| 22 | |
| 23 | #include "llvm/ADT/STLExtras.h" |
| 24 | |
| 25 | using namespace lldb; |
| 26 | using namespace lldb_private; |
| 27 | |
| 28 | #define DEFINE_GPR(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatHexUppercase |
| 29 | #define DEFINE_GPR_BIN(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatBinary |
| 30 | |
| 31 | namespace { |
| 32 | |
| 33 | // This enum defines the layout of the global RegisterInfo array. This is |
| 34 | // necessary because lldb register sets are defined in terms of indices into |
| 35 | // the register array. As such, the order of RegisterInfos defined in global |
| 36 | // registers array must match the order defined here. When defining the |
| 37 | // register set layouts, these values can appear in an arbitrary order, and |
| 38 | // that determines the order that register values are displayed in a dump. |
| 39 | enum RegisterIndex { |
| 40 | eRegisterIndexEax, |
| 41 | eRegisterIndexEbx, |
| 42 | eRegisterIndexEcx, |
| 43 | eRegisterIndexEdx, |
| 44 | eRegisterIndexEdi, |
| 45 | eRegisterIndexEsi, |
| 46 | eRegisterIndexEbp, |
| 47 | eRegisterIndexEsp, |
| 48 | eRegisterIndexEip, |
| 49 | eRegisterIndexEflags |
| 50 | }; |
| 51 | |
| 52 | // Array of all register information supported by Windows x86 |
| 53 | RegisterInfo g_register_infos[] = { |
| 54 | {DEFINE_GPR(eax, nullptr), |
| 55 | {ehframe_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, |
| 56 | LLDB_INVALID_REGNUM, lldb_eax_i386}, |
| 57 | nullptr, |
| 58 | nullptr, |
| 59 | nullptr, |
| 60 | }, |
| 61 | {DEFINE_GPR(ebx, nullptr), |
| 62 | {ehframe_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, |
| 63 | LLDB_INVALID_REGNUM, lldb_ebx_i386}, |
| 64 | nullptr, |
| 65 | nullptr, |
| 66 | nullptr, |
| 67 | }, |
| 68 | {DEFINE_GPR(ecx, nullptr), |
| 69 | {ehframe_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, |
| 70 | LLDB_INVALID_REGNUM, lldb_ecx_i386}, |
| 71 | nullptr, |
| 72 | nullptr, |
| 73 | nullptr, |
| 74 | }, |
| 75 | {DEFINE_GPR(edx, nullptr), |
| 76 | {ehframe_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, |
| 77 | LLDB_INVALID_REGNUM, lldb_edx_i386}, |
| 78 | nullptr, |
| 79 | nullptr, |
| 80 | nullptr, |
| 81 | }, |
| 82 | {DEFINE_GPR(edi, nullptr), |
| 83 | {ehframe_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, |
| 84 | LLDB_INVALID_REGNUM, lldb_edi_i386}, |
| 85 | nullptr, |
| 86 | nullptr, |
| 87 | nullptr, |
| 88 | }, |
| 89 | {DEFINE_GPR(esi, nullptr), |
| 90 | {ehframe_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, |
| 91 | LLDB_INVALID_REGNUM, lldb_esi_i386}, |
| 92 | nullptr, |
| 93 | nullptr, |
| 94 | nullptr, |
| 95 | }, |
| 96 | {DEFINE_GPR(ebp, "fp" ), |
| 97 | {ehframe_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, |
| 98 | LLDB_INVALID_REGNUM, lldb_ebp_i386}, |
| 99 | nullptr, |
| 100 | nullptr, |
| 101 | nullptr, |
| 102 | }, |
| 103 | {DEFINE_GPR(esp, "sp" ), |
| 104 | {ehframe_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, |
| 105 | LLDB_INVALID_REGNUM, lldb_esp_i386}, |
| 106 | nullptr, |
| 107 | nullptr, |
| 108 | nullptr, |
| 109 | }, |
| 110 | {DEFINE_GPR(eip, "pc" ), |
| 111 | {ehframe_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, |
| 112 | LLDB_INVALID_REGNUM, lldb_eip_i386}, |
| 113 | nullptr, |
| 114 | nullptr, |
| 115 | nullptr, |
| 116 | }, |
| 117 | {DEFINE_GPR_BIN(eflags, "flags" ), |
| 118 | {ehframe_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, |
| 119 | LLDB_INVALID_REGNUM, lldb_eflags_i386}, |
| 120 | nullptr, |
| 121 | nullptr, |
| 122 | nullptr, |
| 123 | }, |
| 124 | }; |
| 125 | static size_t k_num_register_infos = std::size(g_register_infos); |
| 126 | |
| 127 | // Array of lldb register numbers used to define the set of all General Purpose |
| 128 | // Registers |
| 129 | uint32_t g_gpr_reg_indices[] = {eRegisterIndexEax, eRegisterIndexEbx, |
| 130 | eRegisterIndexEcx, eRegisterIndexEdx, |
| 131 | eRegisterIndexEdi, eRegisterIndexEsi, |
| 132 | eRegisterIndexEbp, eRegisterIndexEsp, |
| 133 | eRegisterIndexEip, eRegisterIndexEflags}; |
| 134 | |
| 135 | RegisterSet g_register_sets[] = { |
| 136 | {"General Purpose Registers" , "gpr" , std::size(g_gpr_reg_indices), |
| 137 | g_gpr_reg_indices}, |
| 138 | }; |
| 139 | } |
| 140 | |
| 141 | // Constructors and Destructors |
| 142 | RegisterContextWindows_x86::RegisterContextWindows_x86( |
| 143 | Thread &thread, uint32_t concrete_frame_idx) |
| 144 | : RegisterContextWindows(thread, concrete_frame_idx) {} |
| 145 | |
| 146 | RegisterContextWindows_x86::~RegisterContextWindows_x86() {} |
| 147 | |
| 148 | size_t RegisterContextWindows_x86::GetRegisterCount() { |
| 149 | return std::size(g_register_infos); |
| 150 | } |
| 151 | |
| 152 | const RegisterInfo * |
| 153 | RegisterContextWindows_x86::GetRegisterInfoAtIndex(size_t reg) { |
| 154 | if (reg < k_num_register_infos) |
| 155 | return &g_register_infos[reg]; |
| 156 | return NULL; |
| 157 | } |
| 158 | |
| 159 | size_t RegisterContextWindows_x86::GetRegisterSetCount() { |
| 160 | return std::size(g_register_sets); |
| 161 | } |
| 162 | |
| 163 | const RegisterSet *RegisterContextWindows_x86::GetRegisterSet(size_t reg_set) { |
| 164 | return &g_register_sets[reg_set]; |
| 165 | } |
| 166 | |
| 167 | bool RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, |
| 168 | RegisterValue ®_value) { |
| 169 | if (!CacheAllRegisterValues()) |
| 170 | return false; |
| 171 | |
| 172 | if (reg_info == nullptr) |
| 173 | return false; |
| 174 | |
| 175 | uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; |
| 176 | switch (reg) { |
| 177 | case lldb_eax_i386: |
| 178 | return ReadRegisterHelper(CONTEXT_INTEGER, "EAX" , m_context.Eax, reg_value); |
| 179 | case lldb_ebx_i386: |
| 180 | return ReadRegisterHelper(CONTEXT_INTEGER, "EBX" , m_context.Ebx, reg_value); |
| 181 | case lldb_ecx_i386: |
| 182 | return ReadRegisterHelper(CONTEXT_INTEGER, "ECX" , m_context.Ecx, reg_value); |
| 183 | case lldb_edx_i386: |
| 184 | return ReadRegisterHelper(CONTEXT_INTEGER, "EDX" , m_context.Edx, reg_value); |
| 185 | case lldb_edi_i386: |
| 186 | return ReadRegisterHelper(CONTEXT_INTEGER, "EDI" , m_context.Edi, reg_value); |
| 187 | case lldb_esi_i386: |
| 188 | return ReadRegisterHelper(CONTEXT_INTEGER, "ESI" , m_context.Esi, reg_value); |
| 189 | case lldb_ebp_i386: |
| 190 | return ReadRegisterHelper(CONTEXT_CONTROL, "EBP" , m_context.Ebp, reg_value); |
| 191 | case lldb_esp_i386: |
| 192 | return ReadRegisterHelper(CONTEXT_CONTROL, "ESP" , m_context.Esp, reg_value); |
| 193 | case lldb_eip_i386: |
| 194 | return ReadRegisterHelper(CONTEXT_CONTROL, "EIP" , m_context.Eip, reg_value); |
| 195 | case lldb_eflags_i386: |
| 196 | return ReadRegisterHelper(CONTEXT_CONTROL, "EFLAGS" , m_context.EFlags, |
| 197 | reg_value); |
| 198 | default: |
| 199 | Log *log = GetLog(WindowsLog::Registers); |
| 200 | LLDB_LOG(log, "Requested unknown register {0}" , reg); |
| 201 | break; |
| 202 | } |
| 203 | return false; |
| 204 | } |
| 205 | |
| 206 | bool RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info, |
| 207 | const RegisterValue ®_value) { |
| 208 | // Since we cannot only write a single register value to the inferior, we |
| 209 | // need to make sure our cached copy of the register values are fresh. |
| 210 | // Otherwise when writing EAX, for example, we may also overwrite some other |
| 211 | // register with a stale value. |
| 212 | if (!CacheAllRegisterValues()) |
| 213 | return false; |
| 214 | |
| 215 | Log *log = GetLog(WindowsLog::Registers); |
| 216 | uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; |
| 217 | switch (reg) { |
| 218 | case lldb_eax_i386: |
| 219 | LLDB_LOG(log, "Write value {0:x} to EAX" , reg_value.GetAsUInt32()); |
| 220 | m_context.Eax = reg_value.GetAsUInt32(); |
| 221 | break; |
| 222 | case lldb_ebx_i386: |
| 223 | LLDB_LOG(log, "Write value {0:x} to EBX" , reg_value.GetAsUInt32()); |
| 224 | m_context.Ebx = reg_value.GetAsUInt32(); |
| 225 | break; |
| 226 | case lldb_ecx_i386: |
| 227 | LLDB_LOG(log, "Write value {0:x} to ECX" , reg_value.GetAsUInt32()); |
| 228 | m_context.Ecx = reg_value.GetAsUInt32(); |
| 229 | break; |
| 230 | case lldb_edx_i386: |
| 231 | LLDB_LOG(log, "Write value {0:x} to EDX" , reg_value.GetAsUInt32()); |
| 232 | m_context.Edx = reg_value.GetAsUInt32(); |
| 233 | break; |
| 234 | case lldb_edi_i386: |
| 235 | LLDB_LOG(log, "Write value {0:x} to EDI" , reg_value.GetAsUInt32()); |
| 236 | m_context.Edi = reg_value.GetAsUInt32(); |
| 237 | break; |
| 238 | case lldb_esi_i386: |
| 239 | LLDB_LOG(log, "Write value {0:x} to ESI" , reg_value.GetAsUInt32()); |
| 240 | m_context.Esi = reg_value.GetAsUInt32(); |
| 241 | break; |
| 242 | case lldb_ebp_i386: |
| 243 | LLDB_LOG(log, "Write value {0:x} to EBP" , reg_value.GetAsUInt32()); |
| 244 | m_context.Ebp = reg_value.GetAsUInt32(); |
| 245 | break; |
| 246 | case lldb_esp_i386: |
| 247 | LLDB_LOG(log, "Write value {0:x} to ESP" , reg_value.GetAsUInt32()); |
| 248 | m_context.Esp = reg_value.GetAsUInt32(); |
| 249 | break; |
| 250 | case lldb_eip_i386: |
| 251 | LLDB_LOG(log, "Write value {0:x} to EIP" , reg_value.GetAsUInt32()); |
| 252 | m_context.Eip = reg_value.GetAsUInt32(); |
| 253 | break; |
| 254 | case lldb_eflags_i386: |
| 255 | LLDB_LOG(log, "Write value {0:x} to EFLAGS" , reg_value.GetAsUInt32()); |
| 256 | m_context.EFlags = reg_value.GetAsUInt32(); |
| 257 | break; |
| 258 | default: |
| 259 | LLDB_LOG(log, "Write value {0:x} to unknown register {1}" , |
| 260 | reg_value.GetAsUInt32(), reg); |
| 261 | } |
| 262 | |
| 263 | // Physically update the registers in the target process. |
| 264 | return ApplyAllRegisterValues(); |
| 265 | } |
| 266 | |
| 267 | bool RegisterContextWindows_x86::ReadRegisterHelper( |
| 268 | DWORD flags_required, const char *reg_name, DWORD value, |
| 269 | RegisterValue ®_value) const { |
| 270 | Log *log = GetLog(WindowsLog::Registers); |
| 271 | if ((m_context.ContextFlags & flags_required) != flags_required) { |
| 272 | LLDB_LOG(log, "Thread context doesn't have {0}" , reg_name); |
| 273 | return false; |
| 274 | } |
| 275 | LLDB_LOG(log, "Read value {0:x} from {1}" , value, reg_name); |
| 276 | reg_value.SetUInt32(value); |
| 277 | return true; |
| 278 | } |
| 279 | |
| 280 | #endif // defined(__i386__) || defined(_M_IX86) |
| 281 | |