| //===-- RegisterContextWindows.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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lldb/Host/windows/HostThreadWindows.h" |
| #include "lldb/Host/windows/windows.h" |
| #include "lldb/Utility/DataBufferHeap.h" |
| #include "lldb/Utility/Status.h" |
| #include "lldb/lldb-private-types.h" |
| |
| #include "ProcessWindowsLog.h" |
| #include "RegisterContextWindows.h" |
| #include "TargetThreadWindows.h" |
| |
| #include "llvm/ADT/STLExtras.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| const DWORD kWinContextFlags = CONTEXT_ALL; |
| |
| // Constructors and Destructors |
| RegisterContextWindows::RegisterContextWindows(Thread &thread, |
| uint32_t concrete_frame_idx) |
| : RegisterContext(thread, concrete_frame_idx), m_context(), |
| m_context_stale(true) {} |
| |
| RegisterContextWindows::~RegisterContextWindows() {} |
| |
| void RegisterContextWindows::InvalidateAllRegisters() { |
| m_context_stale = true; |
| } |
| |
| bool RegisterContextWindows::ReadAllRegisterValues( |
| lldb::DataBufferSP &data_sp) { |
| |
| if (!CacheAllRegisterValues()) |
| return false; |
| |
| data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0)); |
| memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context)); |
| |
| return true; |
| } |
| |
| bool RegisterContextWindows::WriteAllRegisterValues( |
| const lldb::DataBufferSP &data_sp) { |
| assert(data_sp->GetByteSize() >= sizeof(m_context)); |
| memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context)); |
| |
| TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); |
| if (!::SetThreadContext( |
| wthread.GetHostThread().GetNativeThread().GetSystemHandle(), |
| &m_context)) |
| return false; |
| |
| return true; |
| } |
| |
| uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber( |
| lldb::RegisterKind kind, uint32_t num) { |
| const uint32_t num_regs = GetRegisterCount(); |
| |
| assert(kind < kNumRegisterKinds); |
| for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { |
| const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); |
| |
| if (reg_info->kinds[kind] == num) |
| return reg_idx; |
| } |
| |
| return LLDB_INVALID_REGNUM; |
| } |
| |
| // Subclasses can these functions if desired |
| uint32_t RegisterContextWindows::NumSupportedHardwareBreakpoints() { |
| // Support for hardware breakpoints not yet implemented. |
| return 0; |
| } |
| |
| uint32_t RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr, |
| size_t size) { |
| return 0; |
| } |
| |
| bool RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx) { |
| return false; |
| } |
| |
| uint32_t RegisterContextWindows::NumSupportedHardwareWatchpoints() { |
| // Support for hardware watchpoints not yet implemented. |
| return 0; |
| } |
| |
| uint32_t RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr, |
| size_t size, bool read, |
| bool write) { |
| return 0; |
| } |
| |
| bool RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index) { |
| return false; |
| } |
| |
| bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; } |
| |
| bool RegisterContextWindows::CacheAllRegisterValues() { |
| Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); |
| if (!m_context_stale) |
| return true; |
| |
| TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); |
| uint8_t buffer[2048]; |
| memset(buffer, 0, sizeof(buffer)); |
| PCONTEXT tmpContext = NULL; |
| DWORD contextLength = (DWORD)sizeof(buffer); |
| if (!::InitializeContext(buffer, kWinContextFlags, &tmpContext, |
| &contextLength)) { |
| return false; |
| } |
| memcpy(&m_context, tmpContext, sizeof(m_context)); |
| if (!::SuspendThread(wthread.GetHostThread().GetNativeThread().GetSystemHandle())) { |
| return false; |
| } |
| if (!::GetThreadContext( |
| wthread.GetHostThread().GetNativeThread().GetSystemHandle(), |
| &m_context)) { |
| LLDB_LOG( |
| log, |
| "GetThreadContext failed with error {0} while caching register values.", |
| ::GetLastError()); |
| return false; |
| } |
| if (!::ResumeThread(wthread.GetHostThread().GetNativeThread().GetSystemHandle())) { |
| return false; |
| } |
| LLDB_LOG(log, "successfully updated the register values."); |
| m_context_stale = false; |
| return true; |
| } |