1 //===-- RegisterContextWindows.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Core/DataBufferHeap.h"
11 #include "lldb/Core/Error.h"
12 #include "lldb/Host/windows/HostThreadWindows.h"
13 #include "lldb/Host/windows/windows.h"
14 #include "lldb/lldb-private-types.h"
15 
16 #include "ProcessWindowsLog.h"
17 #include "RegisterContextWindows.h"
18 #include "TargetThreadWindows.h"
19 
20 #include "llvm/ADT/STLExtras.h"
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 
25 const DWORD kWinContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
26 
27 //------------------------------------------------------------------
28 // Constructors and Destructors
29 //------------------------------------------------------------------
30 RegisterContextWindows::RegisterContextWindows(Thread &thread,
31                                                uint32_t concrete_frame_idx)
32     : RegisterContext(thread, concrete_frame_idx), m_context(),
33       m_context_stale(true) {}
34 
35 RegisterContextWindows::~RegisterContextWindows() {}
36 
37 void RegisterContextWindows::InvalidateAllRegisters() {
38   m_context_stale = true;
39 }
40 
41 bool RegisterContextWindows::ReadAllRegisterValues(
42     lldb::DataBufferSP &data_sp) {
43   if (!CacheAllRegisterValues())
44     return false;
45   if (data_sp->GetByteSize() < sizeof(m_context)) {
46     data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0));
47   }
48   memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context));
49   return true;
50 }
51 
52 bool RegisterContextWindows::WriteAllRegisterValues(
53     const lldb::DataBufferSP &data_sp) {
54   assert(data_sp->GetByteSize() >= sizeof(m_context));
55   memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context));
56 
57   TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
58   if (!::SetThreadContext(
59           wthread.GetHostThread().GetNativeThread().GetSystemHandle(),
60           &m_context))
61     return false;
62 
63   return true;
64 }
65 
66 uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber(
67     lldb::RegisterKind kind, uint32_t num) {
68   const uint32_t num_regs = GetRegisterCount();
69 
70   assert(kind < kNumRegisterKinds);
71   for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
72     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx);
73 
74     if (reg_info->kinds[kind] == num)
75       return reg_idx;
76   }
77 
78   return LLDB_INVALID_REGNUM;
79 }
80 
81 //------------------------------------------------------------------
82 // Subclasses can these functions if desired
83 //------------------------------------------------------------------
84 uint32_t RegisterContextWindows::NumSupportedHardwareBreakpoints() {
85   // Support for hardware breakpoints not yet implemented.
86   return 0;
87 }
88 
89 uint32_t RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr,
90                                                        size_t size) {
91   return 0;
92 }
93 
94 bool RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx) {
95   return false;
96 }
97 
98 uint32_t RegisterContextWindows::NumSupportedHardwareWatchpoints() {
99   // Support for hardware watchpoints not yet implemented.
100   return 0;
101 }
102 
103 uint32_t RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr,
104                                                        size_t size, bool read,
105                                                        bool write) {
106   return 0;
107 }
108 
109 bool RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index) {
110   return false;
111 }
112 
113 bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; }
114 
115 bool RegisterContextWindows::CacheAllRegisterValues() {
116   if (!m_context_stale)
117     return true;
118 
119   TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
120   memset(&m_context, 0, sizeof(m_context));
121   m_context.ContextFlags = kWinContextFlags;
122   if (!::GetThreadContext(
123           wthread.GetHostThread().GetNativeThread().GetSystemHandle(),
124           &m_context)) {
125     WINERR_IFALL(
126         WINDOWS_LOG_REGISTERS,
127         "GetThreadContext failed with error %lu while caching register values.",
128         ::GetLastError());
129     return false;
130   }
131   WINLOG_IFALL(WINDOWS_LOG_REGISTERS,
132                "GetThreadContext successfully updated the register values.");
133   m_context_stale = false;
134   return true;
135 }
136