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/Host/windows/HostThreadWindows.h"
11 #include "lldb/Host/windows/windows.h"
12 #include "lldb/Utility/DataBufferHeap.h"
13 #include "lldb/Utility/Status.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 
44   if (!CacheAllRegisterValues())
45     return false;
46 
47   data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0));
48   memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context));
49 
50   return true;
51 }
52 
53 bool RegisterContextWindows::WriteAllRegisterValues(
54     const lldb::DataBufferSP &data_sp) {
55   assert(data_sp->GetByteSize() >= sizeof(m_context));
56   memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context));
57 
58   TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
59   if (!::SetThreadContext(
60           wthread.GetHostThread().GetNativeThread().GetSystemHandle(),
61           &m_context))
62     return false;
63 
64   return true;
65 }
66 
67 uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber(
68     lldb::RegisterKind kind, uint32_t num) {
69   const uint32_t num_regs = GetRegisterCount();
70 
71   assert(kind < kNumRegisterKinds);
72   for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
73     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx);
74 
75     if (reg_info->kinds[kind] == num)
76       return reg_idx;
77   }
78 
79   return LLDB_INVALID_REGNUM;
80 }
81 
82 //------------------------------------------------------------------
83 // Subclasses can these functions if desired
84 //------------------------------------------------------------------
85 uint32_t RegisterContextWindows::NumSupportedHardwareBreakpoints() {
86   // Support for hardware breakpoints not yet implemented.
87   return 0;
88 }
89 
90 uint32_t RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr,
91                                                        size_t size) {
92   return 0;
93 }
94 
95 bool RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx) {
96   return false;
97 }
98 
99 uint32_t RegisterContextWindows::NumSupportedHardwareWatchpoints() {
100   // Support for hardware watchpoints not yet implemented.
101   return 0;
102 }
103 
104 uint32_t RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr,
105                                                        size_t size, bool read,
106                                                        bool write) {
107   return 0;
108 }
109 
110 bool RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index) {
111   return false;
112 }
113 
114 bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; }
115 
116 bool RegisterContextWindows::CacheAllRegisterValues() {
117   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS);
118   if (!m_context_stale)
119     return true;
120 
121   TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
122   memset(&m_context, 0, sizeof(m_context));
123   m_context.ContextFlags = kWinContextFlags;
124   if (!::GetThreadContext(
125           wthread.GetHostThread().GetNativeThread().GetSystemHandle(),
126           &m_context)) {
127     LLDB_LOG(
128         log,
129         "GetThreadContext failed with error {0} while caching register values.",
130         ::GetLastError());
131     return false;
132   }
133   LLDB_LOG(log, "successfully updated the register values.");
134   m_context_stale = false;
135   return true;
136 }
137