Differential D56233 Diff 194380 source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_x86_64.cpp
Changeset View
Changeset View
Standalone View
Standalone View
source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_x86_64.cpp
- This file was added.
//===-- NativeRegisterContextWindows_x86_64.cpp -----------------*- C++ -*-===// | |||||
// | |||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||||
// See https://llvm.org/LICENSE.txt for license information. | |||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||||
// | |||||
//===----------------------------------------------------------------------===// | |||||
#if defined(_WIN64) | |||||
#include "NativeRegisterContextWindows_x86_64.h" | |||||
#include "NativeRegisterContextWindows_wow64.h" | |||||
#include "NativeThreadWindows.h" | |||||
#include "Plugins/Process/Utility/RegisterContextWindows_i386.h" | |||||
#include "Plugins/Process/Utility/RegisterContextWindows_x86_64.h" | |||||
#include "ProcessWindowsLog.h" | |||||
#include "lldb/Host/HostInfo.h" | |||||
#include "lldb/Host/HostThread.h" | |||||
#include "lldb/Host/Windows/HostThreadWindows.h" | |||||
#include "lldb/Host/windows/windows.h" | |||||
#include "lldb/Utility/Log.h" | |||||
#include "lldb/Utility/RegisterValue.h" | |||||
#include "llvm/ADT/STLExtras.h" | |||||
using namespace lldb; | |||||
using namespace lldb_private; | |||||
#define REG_CONTEXT_SIZE sizeof(::CONTEXT) | |||||
namespace { | |||||
static const uint32_t g_gpr_regnums_x86_64[] = { | |||||
lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, | |||||
lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64, | |||||
lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64, | |||||
lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64, | |||||
lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64, | |||||
lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64, | |||||
LLDB_INVALID_REGNUM // Register sets must be terminated with this flag | |||||
}; | |||||
size_t k_num_gprs = llvm::array_lengthof(g_gpr_regnums_x86_64) - 1; | |||||
static const RegisterSet g_reg_sets_x86_64[] = { | |||||
{"General Purpose Registers", "gpr", | |||||
llvm::array_lengthof(g_gpr_regnums_x86_64) - 1, g_gpr_regnums_x86_64}, | |||||
}; | |||||
size_t k_num_register_sets = llvm::array_lengthof(g_gpr_regnums_x86_64); | |||||
static RegisterInfoInterface * | |||||
CreateRegisterInfoInterface(const ArchSpec &target_arch) { | |||||
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && | |||||
"Register setting path assumes this is a 64-bit host"); | |||||
return new RegisterContextWindows_x86_64(target_arch); | |||||
} | |||||
} // namespace | |||||
std::unique_ptr<NativeRegisterContextWindows> | |||||
NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows( | |||||
const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { | |||||
// Register context for a Wow64 application. | |||||
if (target_arch.GetAddressByteSize() == 4) | |||||
return llvm::make_unique<NativeRegisterContextWindows_wow64>(target_arch, | |||||
native_thread); | |||||
// Register context for a native 64-bit application. | |||||
return llvm::make_unique<NativeRegisterContextWindows_x86_64>(target_arch, | |||||
native_thread); | |||||
} | |||||
NativeRegisterContextWindows_x86_64::NativeRegisterContextWindows_x86_64( | |||||
const ArchSpec &target_arch, NativeThreadProtocol &native_thread) | |||||
: NativeRegisterContextWindows(native_thread, | |||||
CreateRegisterInfoInterface(target_arch)) {} | |||||
bool NativeRegisterContextWindows_x86_64::IsGPR(uint32_t reg_index) const { | |||||
return (reg_index < k_first_alias_x86_64); | |||||
} | |||||
uint32_t NativeRegisterContextWindows_x86_64::GetRegisterSetCount() const { | |||||
return k_num_register_sets; | |||||
} | |||||
const RegisterSet * | |||||
NativeRegisterContextWindows_x86_64::GetRegisterSet(uint32_t set_index) const { | |||||
if (set_index >= k_num_register_sets) | |||||
return nullptr; | |||||
return &g_reg_sets_x86_64[set_index]; | |||||
} | |||||
Status NativeRegisterContextWindows_x86_64::GPRRead(const uint32_t reg, | |||||
RegisterValue ®_value) { | |||||
Status error; | |||||
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); | |||||
::CONTEXT tls_context; | |||||
NativeThreadWindows *wthread = static_cast<NativeThreadWindows *>(&m_thread); | |||||
auto host_thread = wthread->GetHostThread(); | |||||
memset(&tls_context, 0, sizeof(tls_context)); | |||||
tls_context.ContextFlags = | |||||
CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; | |||||
if (!::GetThreadContext(host_thread.GetNativeThread().GetSystemHandle(), | |||||
&tls_context)) { | |||||
LLDB_LOG(log, | |||||
"GetThreadContext failed with error {0} while caching register " | |||||
"values.", | |||||
::GetLastError()); | |||||
return Status("error"); | |||||
} | |||||
LLDB_LOG(log, "successfully updated the register values."); | |||||
switch (reg) { | |||||
case lldb_rax_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rax); | |||||
break; | |||||
case lldb_rbx_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rbx); | |||||
break; | |||||
case lldb_rcx_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rcx); | |||||
break; | |||||
case lldb_rdx_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rdx); | |||||
break; | |||||
case lldb_rdi_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rdi); | |||||
break; | |||||
case lldb_rsi_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rsi); | |||||
break; | |||||
case lldb_rbp_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rbp); | |||||
break; | |||||
case lldb_rsp_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rsp); | |||||
break; | |||||
case lldb_r8_x86_64: | |||||
reg_value.SetUInt64(tls_context.R8); | |||||
break; | |||||
case lldb_r9_x86_64: | |||||
reg_value.SetUInt64(tls_context.R9); | |||||
break; | |||||
case lldb_r10_x86_64: | |||||
reg_value.SetUInt64(tls_context.R10); | |||||
break; | |||||
case lldb_r11_x86_64: | |||||
reg_value.SetUInt64(tls_context.R11); | |||||
break; | |||||
case lldb_r12_x86_64: | |||||
reg_value.SetUInt64(tls_context.R12); | |||||
break; | |||||
case lldb_r13_x86_64: | |||||
reg_value.SetUInt64(tls_context.R13); | |||||
break; | |||||
case lldb_r14_x86_64: | |||||
reg_value.SetUInt64(tls_context.R14); | |||||
break; | |||||
case lldb_r15_x86_64: | |||||
reg_value.SetUInt64(tls_context.R15); | |||||
break; | |||||
case lldb_rip_x86_64: | |||||
reg_value.SetUInt64(tls_context.Rip); | |||||
break; | |||||
case lldb_rflags_x86_64: | |||||
reg_value.SetUInt64(tls_context.EFlags | 0x2); // Bit #1 alwyas 1 | |||||
break; | |||||
case lldb_cs_x86_64: | |||||
reg_value.SetUInt16(tls_context.SegCs); | |||||
break; | |||||
case lldb_fs_x86_64: | |||||
reg_value.SetUInt16(tls_context.SegFs); | |||||
break; | |||||
case lldb_gs_x86_64: | |||||
reg_value.SetUInt16(tls_context.SegGs); | |||||
break; | |||||
case lldb_ss_x86_64: | |||||
reg_value.SetUInt16(tls_context.SegSs); | |||||
break; | |||||
case lldb_ds_x86_64: | |||||
reg_value.SetUInt16(tls_context.SegDs); | |||||
break; | |||||
case lldb_es_x86_64: | |||||
reg_value.SetUInt16(tls_context.SegEs); | |||||
break; | |||||
} | |||||
return error; | |||||
} | |||||
Status | |||||
NativeRegisterContextWindows_x86_64::GPRWrite(const uint32_t reg, | |||||
const RegisterValue ®_value) { | |||||
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); | |||||
Status error; | |||||
::CONTEXT tls_context; | |||||
memset(&tls_context, 0, sizeof(tls_context)); | |||||
NativeThreadWindows *wthread = static_cast<NativeThreadWindows *>(&m_thread); | |||||
auto host_thread = wthread->GetHostThread(); | |||||
tls_context.ContextFlags = | |||||
CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; | |||||
if (!::GetThreadContext(host_thread.GetNativeThread().GetSystemHandle(), | |||||
&tls_context)) { | |||||
LLDB_LOG(log, | |||||
"GetThreadContext failed with error {0} while caching register " | |||||
"values.", | |||||
::GetLastError()); | |||||
return Status("error"); | |||||
} | |||||
LLDB_LOG(log, "successfully updated the register values."); | |||||
switch (reg) { | |||||
case lldb_rax_x86_64: | |||||
tls_context.Rax = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rbx_x86_64: | |||||
tls_context.Rbx = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rcx_x86_64: | |||||
tls_context.Rcx = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rdx_x86_64: | |||||
tls_context.Rdx = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rdi_x86_64: | |||||
tls_context.Rdi = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rsi_x86_64: | |||||
tls_context.Rsi = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rbp_x86_64: | |||||
tls_context.Rbp = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rsp_x86_64: | |||||
tls_context.Rsp = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_r8_x86_64: | |||||
tls_context.R8 = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_r9_x86_64: | |||||
tls_context.R9 = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_r10_x86_64: | |||||
tls_context.R10 = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_r11_x86_64: | |||||
tls_context.R11 = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_r12_x86_64: | |||||
tls_context.R12 = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_r13_x86_64: | |||||
tls_context.R13 = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_r14_x86_64: | |||||
tls_context.R14 = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_r15_x86_64: | |||||
tls_context.R15 = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rip_x86_64: | |||||
tls_context.Rip = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_rflags_x86_64: | |||||
tls_context.EFlags = reg_value.GetAsUInt64(); | |||||
break; | |||||
case lldb_cs_x86_64: | |||||
tls_context.SegCs = reg_value.GetAsUInt16(); | |||||
break; | |||||
case lldb_fs_x86_64: | |||||
tls_context.SegFs = reg_value.GetAsUInt16(); | |||||
break; | |||||
case lldb_gs_x86_64: | |||||
tls_context.SegGs = reg_value.GetAsUInt16(); | |||||
break; | |||||
case lldb_ss_x86_64: | |||||
tls_context.SegSs = reg_value.GetAsUInt16(); | |||||
break; | |||||
case lldb_ds_x86_64: | |||||
tls_context.SegDs = reg_value.GetAsUInt16(); | |||||
break; | |||||
case lldb_es_x86_64: | |||||
tls_context.SegEs = reg_value.GetAsUInt16(); | |||||
break; | |||||
} | |||||
bool success = ::SetThreadContext( | |||||
host_thread.GetNativeThread().GetSystemHandle(), &tls_context); | |||||
if (!success) | |||||
return Status(::GetLastError(), eErrorTypeWin32); | |||||
return error; | |||||
} | |||||
Status | |||||
NativeRegisterContextWindows_x86_64::ReadRegister(const RegisterInfo *reg_info, | |||||
RegisterValue ®_value) { | |||||
Status error; | |||||
if (!reg_info) { | |||||
error.SetErrorString("reg_info NULL"); | |||||
return error; | |||||
} | |||||
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; | |||||
if (reg == LLDB_INVALID_REGNUM) { | |||||
// This is likely an internal register for lldb use only and should not be | |||||
// directly queried. | |||||
error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " | |||||
"register, cannot read directly", | |||||
reg_info->name); | |||||
return error; | |||||
} | |||||
if (IsGPR(reg)) | |||||
return GPRRead(reg, reg_value); | |||||
return Status("unimplemented"); | |||||
} | |||||
Status NativeRegisterContextWindows_x86_64::WriteRegister( | |||||
const RegisterInfo *reg_info, const RegisterValue ®_value) { | |||||
Status error; | |||||
if (!reg_info) { | |||||
error.SetErrorString("reg_info NULL"); | |||||
return error; | |||||
} | |||||
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; | |||||
if (reg == LLDB_INVALID_REGNUM) { | |||||
// This is likely an internal register for lldb use only and should not be | |||||
// directly queried. | |||||
error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " | |||||
"register, cannot read directly", | |||||
reg_info->name); | |||||
return error; | |||||
} | |||||
if (IsGPR(reg)) | |||||
return GPRWrite(reg, reg_value); | |||||
return Status("unimplemented"); | |||||
} | |||||
Status NativeRegisterContextWindows_x86_64::ReadAllRegisterValues( | |||||
lldb::DataBufferSP &data_sp) { | |||||
return NativeRegisterContextWindows::ReadAllRegisterValues(data_sp, | |||||
REG_CONTEXT_SIZE); | |||||
} | |||||
Status NativeRegisterContextWindows_x86_64::WriteAllRegisterValues( | |||||
const lldb::DataBufferSP &data_sp) { | |||||
return NativeRegisterContextWindows::WriteAllRegisterValues(data_sp, | |||||
REG_CONTEXT_SIZE); | |||||
} | |||||
Status NativeRegisterContextWindows_x86_64::IsWatchpointHit(uint32_t wp_index, | |||||
bool &is_hit) { | |||||
return Status("unimplemented"); | |||||
} | |||||
Status NativeRegisterContextWindows_x86_64::GetWatchpointHitIndex( | |||||
uint32_t &wp_index, lldb::addr_t trap_addr) { | |||||
return Status("unimplemented"); | |||||
} | |||||
Status | |||||
NativeRegisterContextWindows_x86_64::IsWatchpointVacant(uint32_t wp_index, | |||||
bool &is_vacant) { | |||||
return Status("unimplemented"); | |||||
} | |||||
Status NativeRegisterContextWindows_x86_64::SetHardwareWatchpointWithIndex( | |||||
lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { | |||||
return Status("unimplemented"); | |||||
} | |||||
bool NativeRegisterContextWindows_x86_64::ClearHardwareWatchpoint( | |||||
uint32_t wp_index) { | |||||
return false; | |||||
} | |||||
Status NativeRegisterContextWindows_x86_64::ClearAllHardwareWatchpoints() { | |||||
return Status("unimplemented"); | |||||
} | |||||
uint32_t NativeRegisterContextWindows_x86_64::SetHardwareWatchpoint( | |||||
lldb::addr_t addr, size_t size, uint32_t watch_flags) { | |||||
return LLDB_INVALID_INDEX32; | |||||
} | |||||
lldb::addr_t | |||||
NativeRegisterContextWindows_x86_64::GetWatchpointAddress(uint32_t wp_index) { | |||||
return LLDB_INVALID_ADDRESS; | |||||
} | |||||
uint32_t | |||||
NativeRegisterContextWindows_x86_64::NumSupportedHardwareWatchpoints() { | |||||
// Not implemented | |||||
return 0; | |||||
} | |||||
#endif // defined(_WIN64) |