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