| //===-- RegisterContextWindows.cpp ------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lldb/lldb-private-types.h" |
| #include "lldb/Core/DataBufferHeap.h" |
| #include "lldb/Core/Error.h" |
| #include "lldb/Host/windows/HostThreadWindows.h" |
| #include "lldb/Host/windows/windows.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_CONTROL | CONTEXT_INTEGER; |
| |
| //------------------------------------------------------------------ |
| // 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; |
| if (data_sp->GetByteSize() < sizeof(m_context)) |
| { |
| 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() |
| { |
| if (!m_context_stale) |
| return true; |
| |
| TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); |
| memset(&m_context, 0, sizeof(m_context)); |
| m_context.ContextFlags = kWinContextFlags; |
| if (!::GetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context)) |
| { |
| WINERR_IFALL(WINDOWS_LOG_REGISTERS, "GetThreadContext failed with error %u while caching register values.", |
| ::GetLastError()); |
| return false; |
| } |
| WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "GetThreadContext successfully updated the register values.", ::GetLastError()); |
| m_context_stale = false; |
| return true; |
| } |