118a9135dSAdrian McCarthy //===-- RegisterContextWindows.cpp ------------------------------*- C++ -*-===// 218a9135dSAdrian McCarthy // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 618a9135dSAdrian McCarthy // 718a9135dSAdrian McCarthy //===----------------------------------------------------------------------===// 818a9135dSAdrian McCarthy 918a9135dSAdrian McCarthy #include "lldb/Host/windows/HostThreadWindows.h" 1018a9135dSAdrian McCarthy #include "lldb/Host/windows/windows.h" 11666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h" 1297206d57SZachary Turner #include "lldb/Utility/Status.h" 13b9c1b51eSKate Stone #include "lldb/lldb-private-types.h" 1418a9135dSAdrian McCarthy 1518a9135dSAdrian McCarthy #include "ProcessWindowsLog.h" 1618a9135dSAdrian McCarthy #include "RegisterContextWindows.h" 1718a9135dSAdrian McCarthy #include "TargetThreadWindows.h" 1818a9135dSAdrian McCarthy 1918a9135dSAdrian McCarthy #include "llvm/ADT/STLExtras.h" 206179c0ebSAleksandr Urakov #include "lldb/Target/Target.h" 2118a9135dSAdrian McCarthy 2218a9135dSAdrian McCarthy using namespace lldb; 2318a9135dSAdrian McCarthy using namespace lldb_private; 2418a9135dSAdrian McCarthy 2509ede9d6SAlex Langford const DWORD kWinContextFlags = CONTEXT_ALL; 2618a9135dSAdrian McCarthy 2718a9135dSAdrian McCarthy // Constructors and Destructors 28b9c1b51eSKate Stone RegisterContextWindows::RegisterContextWindows(Thread &thread, 29b9c1b51eSKate Stone uint32_t concrete_frame_idx) 30b9c1b51eSKate Stone : RegisterContext(thread, concrete_frame_idx), m_context(), 31b9c1b51eSKate Stone m_context_stale(true) {} 3218a9135dSAdrian McCarthy 33b9c1b51eSKate Stone RegisterContextWindows::~RegisterContextWindows() {} 3418a9135dSAdrian McCarthy 35b9c1b51eSKate Stone void RegisterContextWindows::InvalidateAllRegisters() { 3618a9135dSAdrian McCarthy m_context_stale = true; 3718a9135dSAdrian McCarthy } 3818a9135dSAdrian McCarthy 39b9c1b51eSKate Stone bool RegisterContextWindows::ReadAllRegisterValues( 40b9c1b51eSKate Stone lldb::DataBufferSP &data_sp) { 41975814a7SStella Stamenova 4218a9135dSAdrian McCarthy if (!CacheAllRegisterValues()) 4318a9135dSAdrian McCarthy return false; 44975814a7SStella Stamenova 4518a9135dSAdrian McCarthy data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0)); 4618a9135dSAdrian McCarthy memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context)); 47975814a7SStella Stamenova 4818a9135dSAdrian McCarthy return true; 4918a9135dSAdrian McCarthy } 5018a9135dSAdrian McCarthy 51b9c1b51eSKate Stone bool RegisterContextWindows::WriteAllRegisterValues( 52b9c1b51eSKate Stone const lldb::DataBufferSP &data_sp) { 5318a9135dSAdrian McCarthy assert(data_sp->GetByteSize() >= sizeof(m_context)); 5418a9135dSAdrian McCarthy memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context)); 5518a9135dSAdrian McCarthy 566179c0ebSAleksandr Urakov return ApplyAllRegisterValues(); 5718a9135dSAdrian McCarthy } 5818a9135dSAdrian McCarthy 59b9c1b51eSKate Stone uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber( 60b9c1b51eSKate Stone lldb::RegisterKind kind, uint32_t num) { 6118a9135dSAdrian McCarthy const uint32_t num_regs = GetRegisterCount(); 6218a9135dSAdrian McCarthy 6318a9135dSAdrian McCarthy assert(kind < kNumRegisterKinds); 64b9c1b51eSKate Stone for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { 6518a9135dSAdrian McCarthy const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); 6618a9135dSAdrian McCarthy 6718a9135dSAdrian McCarthy if (reg_info->kinds[kind] == num) 6818a9135dSAdrian McCarthy return reg_idx; 6918a9135dSAdrian McCarthy } 7018a9135dSAdrian McCarthy 7118a9135dSAdrian McCarthy return LLDB_INVALID_REGNUM; 7218a9135dSAdrian McCarthy } 7318a9135dSAdrian McCarthy 74b9c1b51eSKate Stone bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; } 7518a9135dSAdrian McCarthy 766179c0ebSAleksandr Urakov bool RegisterContextWindows::AddHardwareBreakpoint(uint32_t slot, 776179c0ebSAleksandr Urakov lldb::addr_t address, 786179c0ebSAleksandr Urakov uint32_t size, bool read, 796179c0ebSAleksandr Urakov bool write) { 806179c0ebSAleksandr Urakov if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS) 816179c0ebSAleksandr Urakov return false; 826179c0ebSAleksandr Urakov 836179c0ebSAleksandr Urakov switch (size) { 846179c0ebSAleksandr Urakov case 1: 856179c0ebSAleksandr Urakov case 2: 866179c0ebSAleksandr Urakov case 4: 87*02dddfd2SMartin Storsjo #if defined(_WIN64) 886179c0ebSAleksandr Urakov case 8: 896179c0ebSAleksandr Urakov #endif 906179c0ebSAleksandr Urakov break; 916179c0ebSAleksandr Urakov default: 926179c0ebSAleksandr Urakov return false; 936179c0ebSAleksandr Urakov } 946179c0ebSAleksandr Urakov 956179c0ebSAleksandr Urakov if (!CacheAllRegisterValues()) 966179c0ebSAleksandr Urakov return false; 976179c0ebSAleksandr Urakov 98*02dddfd2SMartin Storsjo #if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) 996179c0ebSAleksandr Urakov unsigned shift = 2 * slot; 1006179c0ebSAleksandr Urakov m_context.Dr7 |= 1ULL << shift; 1016179c0ebSAleksandr Urakov 1026179c0ebSAleksandr Urakov (&m_context.Dr0)[slot] = address; 1036179c0ebSAleksandr Urakov 1046179c0ebSAleksandr Urakov shift = 18 + 4 * slot; 1056179c0ebSAleksandr Urakov m_context.Dr7 &= ~(3ULL << shift); 1066179c0ebSAleksandr Urakov m_context.Dr7 |= (size == 8 ? 2ULL : size - 1) << shift; 1076179c0ebSAleksandr Urakov 1086179c0ebSAleksandr Urakov shift = 16 + 4 * slot; 1096179c0ebSAleksandr Urakov m_context.Dr7 &= ~(3ULL << shift); 1106179c0ebSAleksandr Urakov m_context.Dr7 |= (read ? 3ULL : (write ? 1ULL : 0)) << shift; 1116179c0ebSAleksandr Urakov 1126179c0ebSAleksandr Urakov return ApplyAllRegisterValues(); 113*02dddfd2SMartin Storsjo 114*02dddfd2SMartin Storsjo #else 115*02dddfd2SMartin Storsjo Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 116*02dddfd2SMartin Storsjo LLDB_LOG(log, "hardware breakpoints not currently supported on this arch"); 117*02dddfd2SMartin Storsjo return false; 118*02dddfd2SMartin Storsjo #endif 1196179c0ebSAleksandr Urakov } 1206179c0ebSAleksandr Urakov 1216179c0ebSAleksandr Urakov bool RegisterContextWindows::RemoveHardwareBreakpoint(uint32_t slot) { 1226179c0ebSAleksandr Urakov if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS) 1236179c0ebSAleksandr Urakov return false; 1246179c0ebSAleksandr Urakov 1256179c0ebSAleksandr Urakov if (!CacheAllRegisterValues()) 1266179c0ebSAleksandr Urakov return false; 1276179c0ebSAleksandr Urakov 128*02dddfd2SMartin Storsjo #if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) 1296179c0ebSAleksandr Urakov unsigned shift = 2 * slot; 1306179c0ebSAleksandr Urakov m_context.Dr7 &= ~(1ULL << shift); 1316179c0ebSAleksandr Urakov 1326179c0ebSAleksandr Urakov return ApplyAllRegisterValues(); 133*02dddfd2SMartin Storsjo #else 134*02dddfd2SMartin Storsjo return false; 135*02dddfd2SMartin Storsjo #endif 1366179c0ebSAleksandr Urakov } 1376179c0ebSAleksandr Urakov 1386179c0ebSAleksandr Urakov uint32_t RegisterContextWindows::GetTriggeredHardwareBreakpointSlotId() { 1396179c0ebSAleksandr Urakov if (!CacheAllRegisterValues()) 1406179c0ebSAleksandr Urakov return LLDB_INVALID_INDEX32; 1416179c0ebSAleksandr Urakov 142*02dddfd2SMartin Storsjo #if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) 1436179c0ebSAleksandr Urakov for (unsigned i = 0UL; i < NUM_HARDWARE_BREAKPOINT_SLOTS; i++) 1446179c0ebSAleksandr Urakov if (m_context.Dr6 & (1ULL << i)) 1456179c0ebSAleksandr Urakov return i; 146*02dddfd2SMartin Storsjo #endif 1476179c0ebSAleksandr Urakov 1486179c0ebSAleksandr Urakov return LLDB_INVALID_INDEX32; 1496179c0ebSAleksandr Urakov } 1506179c0ebSAleksandr Urakov 151b9c1b51eSKate Stone bool RegisterContextWindows::CacheAllRegisterValues() { 152a385d2c1SPavel Labath Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); 15318a9135dSAdrian McCarthy if (!m_context_stale) 15418a9135dSAdrian McCarthy return true; 15518a9135dSAdrian McCarthy 15618a9135dSAdrian McCarthy TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); 15709ede9d6SAlex Langford uint8_t buffer[2048]; 15809ede9d6SAlex Langford memset(buffer, 0, sizeof(buffer)); 15909ede9d6SAlex Langford PCONTEXT tmpContext = NULL; 16009ede9d6SAlex Langford DWORD contextLength = (DWORD)sizeof(buffer); 16109ede9d6SAlex Langford if (!::InitializeContext(buffer, kWinContextFlags, &tmpContext, 16209ede9d6SAlex Langford &contextLength)) { 16309ede9d6SAlex Langford return false; 16409ede9d6SAlex Langford } 16509ede9d6SAlex Langford memcpy(&m_context, tmpContext, sizeof(m_context)); 1665146a9eaSAaron Smith if (::SuspendThread( 1675146a9eaSAaron Smith wthread.GetHostThread().GetNativeThread().GetSystemHandle()) == 1685146a9eaSAaron Smith (DWORD)-1) { 16909ede9d6SAlex Langford return false; 17009ede9d6SAlex Langford } 171b9c1b51eSKate Stone if (!::GetThreadContext( 172b9c1b51eSKate Stone wthread.GetHostThread().GetNativeThread().GetSystemHandle(), 173b9c1b51eSKate Stone &m_context)) { 174a385d2c1SPavel Labath LLDB_LOG( 175a385d2c1SPavel Labath log, 176a385d2c1SPavel Labath "GetThreadContext failed with error {0} while caching register values.", 17718a9135dSAdrian McCarthy ::GetLastError()); 17818a9135dSAdrian McCarthy return false; 17918a9135dSAdrian McCarthy } 1805146a9eaSAaron Smith if (::ResumeThread( 1815146a9eaSAaron Smith wthread.GetHostThread().GetNativeThread().GetSystemHandle()) == 1825146a9eaSAaron Smith (DWORD)-1) { 18309ede9d6SAlex Langford return false; 18409ede9d6SAlex Langford } 185a385d2c1SPavel Labath LLDB_LOG(log, "successfully updated the register values."); 18618a9135dSAdrian McCarthy m_context_stale = false; 18718a9135dSAdrian McCarthy return true; 18818a9135dSAdrian McCarthy } 1896179c0ebSAleksandr Urakov 1906179c0ebSAleksandr Urakov bool RegisterContextWindows::ApplyAllRegisterValues() { 1916179c0ebSAleksandr Urakov TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); 1926179c0ebSAleksandr Urakov return ::SetThreadContext( 1936179c0ebSAleksandr Urakov wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); 1946179c0ebSAleksandr Urakov } 195