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 #include "lldb/Target/Target.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 const DWORD kWinContextFlags = CONTEXT_ALL; 26 27 // Constructors and Destructors 28 RegisterContextWindows::RegisterContextWindows(Thread &thread, 29 uint32_t concrete_frame_idx) 30 : RegisterContext(thread, concrete_frame_idx), m_context(), 31 m_context_stale(true) {} 32 33 RegisterContextWindows::~RegisterContextWindows() {} 34 35 void RegisterContextWindows::InvalidateAllRegisters() { 36 m_context_stale = true; 37 } 38 39 bool RegisterContextWindows::ReadAllRegisterValues( 40 lldb::DataBufferSP &data_sp) { 41 42 if (!CacheAllRegisterValues()) 43 return false; 44 45 data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0)); 46 memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context)); 47 48 return true; 49 } 50 51 bool RegisterContextWindows::WriteAllRegisterValues( 52 const lldb::DataBufferSP &data_sp) { 53 assert(data_sp->GetByteSize() >= sizeof(m_context)); 54 memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context)); 55 56 return ApplyAllRegisterValues(); 57 } 58 59 uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber( 60 lldb::RegisterKind kind, uint32_t num) { 61 const uint32_t num_regs = GetRegisterCount(); 62 63 assert(kind < kNumRegisterKinds); 64 for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { 65 const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); 66 67 if (reg_info->kinds[kind] == num) 68 return reg_idx; 69 } 70 71 return LLDB_INVALID_REGNUM; 72 } 73 74 bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; } 75 76 bool RegisterContextWindows::AddHardwareBreakpoint(uint32_t slot, 77 lldb::addr_t address, 78 uint32_t size, bool read, 79 bool write) { 80 if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS) 81 return false; 82 83 switch (size) { 84 case 1: 85 case 2: 86 case 4: 87 #if defined(_WIN64) 88 case 8: 89 #endif 90 break; 91 default: 92 return false; 93 } 94 95 if (!CacheAllRegisterValues()) 96 return false; 97 98 #if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) 99 unsigned shift = 2 * slot; 100 m_context.Dr7 |= 1ULL << shift; 101 102 (&m_context.Dr0)[slot] = address; 103 104 shift = 18 + 4 * slot; 105 m_context.Dr7 &= ~(3ULL << shift); 106 m_context.Dr7 |= (size == 8 ? 2ULL : size - 1) << shift; 107 108 shift = 16 + 4 * slot; 109 m_context.Dr7 &= ~(3ULL << shift); 110 m_context.Dr7 |= (read ? 3ULL : (write ? 1ULL : 0)) << shift; 111 112 return ApplyAllRegisterValues(); 113 114 #else 115 Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 116 LLDB_LOG(log, "hardware breakpoints not currently supported on this arch"); 117 return false; 118 #endif 119 } 120 121 bool RegisterContextWindows::RemoveHardwareBreakpoint(uint32_t slot) { 122 if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS) 123 return false; 124 125 if (!CacheAllRegisterValues()) 126 return false; 127 128 #if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) 129 unsigned shift = 2 * slot; 130 m_context.Dr7 &= ~(1ULL << shift); 131 132 return ApplyAllRegisterValues(); 133 #else 134 return false; 135 #endif 136 } 137 138 uint32_t RegisterContextWindows::GetTriggeredHardwareBreakpointSlotId() { 139 if (!CacheAllRegisterValues()) 140 return LLDB_INVALID_INDEX32; 141 142 #if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) 143 for (unsigned i = 0UL; i < NUM_HARDWARE_BREAKPOINT_SLOTS; i++) 144 if (m_context.Dr6 & (1ULL << i)) 145 return i; 146 #endif 147 148 return LLDB_INVALID_INDEX32; 149 } 150 151 bool RegisterContextWindows::CacheAllRegisterValues() { 152 Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 153 if (!m_context_stale) 154 return true; 155 156 TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); 157 memset(&m_context, 0, sizeof(m_context)); 158 m_context.ContextFlags = kWinContextFlags; 159 if (::SuspendThread( 160 wthread.GetHostThread().GetNativeThread().GetSystemHandle()) == 161 (DWORD)-1) { 162 return false; 163 } 164 if (!::GetThreadContext( 165 wthread.GetHostThread().GetNativeThread().GetSystemHandle(), 166 &m_context)) { 167 LLDB_LOG( 168 log, 169 "GetThreadContext failed with error {0} while caching register values.", 170 ::GetLastError()); 171 return false; 172 } 173 if (::ResumeThread( 174 wthread.GetHostThread().GetNativeThread().GetSystemHandle()) == 175 (DWORD)-1) { 176 return false; 177 } 178 LLDB_LOG(log, "successfully updated the register values."); 179 m_context_stale = false; 180 return true; 181 } 182 183 bool RegisterContextWindows::ApplyAllRegisterValues() { 184 TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); 185 return ::SetThreadContext( 186 wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); 187 } 188