| //===-- 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/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_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() { |
| Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); |
| 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)) { |
| LLDB_LOG( |
| log, |
| "GetThreadContext failed with error {0} while caching register values.", |
| ::GetLastError()); |
| return false; |
| } |
| LLDB_LOG(log, "successfully updated the register values."); |
| m_context_stale = false; |
| return true; |
| } |