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(__x86_64__) || defined(_M_AMD64) 88 case 8: 89 #endif 90 break; 91 default: 92 return false; 93 } 94 95 if (!CacheAllRegisterValues()) 96 return false; 97 98 unsigned shift = 2 * slot; 99 m_context.Dr7 |= 1ULL << shift; 100 101 (&m_context.Dr0)[slot] = address; 102 103 shift = 18 + 4 * slot; 104 m_context.Dr7 &= ~(3ULL << shift); 105 m_context.Dr7 |= (size == 8 ? 2ULL : size - 1) << shift; 106 107 shift = 16 + 4 * slot; 108 m_context.Dr7 &= ~(3ULL << shift); 109 m_context.Dr7 |= (read ? 3ULL : (write ? 1ULL : 0)) << shift; 110 111 return ApplyAllRegisterValues(); 112 } 113 114 bool RegisterContextWindows::RemoveHardwareBreakpoint(uint32_t slot) { 115 if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS) 116 return false; 117 118 if (!CacheAllRegisterValues()) 119 return false; 120 121 unsigned shift = 2 * slot; 122 m_context.Dr7 &= ~(1ULL << shift); 123 124 return ApplyAllRegisterValues(); 125 } 126 127 uint32_t RegisterContextWindows::GetTriggeredHardwareBreakpointSlotId() { 128 if (!CacheAllRegisterValues()) 129 return LLDB_INVALID_INDEX32; 130 131 for (unsigned i = 0UL; i < NUM_HARDWARE_BREAKPOINT_SLOTS; i++) 132 if (m_context.Dr6 & (1ULL << i)) 133 return i; 134 135 return LLDB_INVALID_INDEX32; 136 } 137 138 bool RegisterContextWindows::CacheAllRegisterValues() { 139 Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 140 if (!m_context_stale) 141 return true; 142 143 TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); 144 uint8_t buffer[2048]; 145 memset(buffer, 0, sizeof(buffer)); 146 PCONTEXT tmpContext = NULL; 147 DWORD contextLength = (DWORD)sizeof(buffer); 148 if (!::InitializeContext(buffer, kWinContextFlags, &tmpContext, 149 &contextLength)) { 150 return false; 151 } 152 memcpy(&m_context, tmpContext, sizeof(m_context)); 153 if (::SuspendThread( 154 wthread.GetHostThread().GetNativeThread().GetSystemHandle()) == 155 (DWORD)-1) { 156 return false; 157 } 158 if (!::GetThreadContext( 159 wthread.GetHostThread().GetNativeThread().GetSystemHandle(), 160 &m_context)) { 161 LLDB_LOG( 162 log, 163 "GetThreadContext failed with error {0} while caching register values.", 164 ::GetLastError()); 165 return false; 166 } 167 if (::ResumeThread( 168 wthread.GetHostThread().GetNativeThread().GetSystemHandle()) == 169 (DWORD)-1) { 170 return false; 171 } 172 LLDB_LOG(log, "successfully updated the register values."); 173 m_context_stale = false; 174 return true; 175 } 176 177 bool RegisterContextWindows::ApplyAllRegisterValues() { 178 TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); 179 return ::SetThreadContext( 180 wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); 181 } 182