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_CONTROL | CONTEXT_INTEGER;
25 
26 //------------------------------------------------------------------
27 // Constructors and Destructors
28 //------------------------------------------------------------------
29 RegisterContextWindows::RegisterContextWindows(Thread &thread,
30                                                uint32_t concrete_frame_idx)
31     : RegisterContext(thread, concrete_frame_idx), m_context(),
32       m_context_stale(true) {}
33 
34 RegisterContextWindows::~RegisterContextWindows() {}
35 
36 void RegisterContextWindows::InvalidateAllRegisters() {
37   m_context_stale = true;
38 }
39 
40 bool RegisterContextWindows::ReadAllRegisterValues(
41     lldb::DataBufferSP &data_sp) {
42 
43   if (!CacheAllRegisterValues())
44     return false;
45 
46   data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0));
47   memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context));
48 
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   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS);
117   if (!m_context_stale)
118     return true;
119 
120   TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
121   memset(&m_context, 0, sizeof(m_context));
122   m_context.ContextFlags = kWinContextFlags;
123   if (!::GetThreadContext(
124           wthread.GetHostThread().GetNativeThread().GetSystemHandle(),
125           &m_context)) {
126     LLDB_LOG(
127         log,
128         "GetThreadContext failed with error {0} while caching register values.",
129         ::GetLastError());
130     return false;
131   }
132   LLDB_LOG(log, "successfully updated the register values.");
133   m_context_stale = false;
134   return true;
135 }
136