180814287SRaphael Isemann //===-- RegisterContextWindows.cpp ----------------------------------------===//
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
RegisterContextWindows(Thread & thread,uint32_t concrete_frame_idx)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 
~RegisterContextWindows()33b9c1b51eSKate Stone RegisterContextWindows::~RegisterContextWindows() {}
3418a9135dSAdrian McCarthy 
InvalidateAllRegisters()35b9c1b51eSKate Stone void RegisterContextWindows::InvalidateAllRegisters() {
3618a9135dSAdrian McCarthy   m_context_stale = true;
3718a9135dSAdrian McCarthy }
3818a9135dSAdrian McCarthy 
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)39b9c1b51eSKate Stone bool RegisterContextWindows::ReadAllRegisterValues(
40*70984dd4SJonas Devlieghere     lldb::WritableDataBufferSP &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 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)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 
ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,uint32_t num)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 
HardwareSingleStep(bool enable)74b9c1b51eSKate Stone bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; }
7518a9135dSAdrian McCarthy 
AddHardwareBreakpoint(uint32_t slot,lldb::addr_t address,uint32_t size,bool read,bool write)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:
8702dddfd2SMartin 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 
9802dddfd2SMartin 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();
11302dddfd2SMartin Storsjo 
11402dddfd2SMartin Storsjo #else
1156730df47SPavel Labath   Log *log = GetLog(WindowsLog::Registers);
11602dddfd2SMartin Storsjo   LLDB_LOG(log, "hardware breakpoints not currently supported on this arch");
11702dddfd2SMartin Storsjo   return false;
11802dddfd2SMartin Storsjo #endif
1196179c0ebSAleksandr Urakov }
1206179c0ebSAleksandr Urakov 
RemoveHardwareBreakpoint(uint32_t slot)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 
12802dddfd2SMartin 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();
13302dddfd2SMartin Storsjo #else
13402dddfd2SMartin Storsjo   return false;
13502dddfd2SMartin Storsjo #endif
1366179c0ebSAleksandr Urakov }
1376179c0ebSAleksandr Urakov 
GetTriggeredHardwareBreakpointSlotId()1386179c0ebSAleksandr Urakov uint32_t RegisterContextWindows::GetTriggeredHardwareBreakpointSlotId() {
1396179c0ebSAleksandr Urakov   if (!CacheAllRegisterValues())
1406179c0ebSAleksandr Urakov     return LLDB_INVALID_INDEX32;
1416179c0ebSAleksandr Urakov 
14202dddfd2SMartin 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;
14602dddfd2SMartin Storsjo #endif
1476179c0ebSAleksandr Urakov 
1486179c0ebSAleksandr Urakov   return LLDB_INVALID_INDEX32;
1496179c0ebSAleksandr Urakov }
1506179c0ebSAleksandr Urakov 
CacheAllRegisterValues()151b9c1b51eSKate Stone bool RegisterContextWindows::CacheAllRegisterValues() {
1526730df47SPavel Labath   Log *log = GetLog(WindowsLog::Registers);
15318a9135dSAdrian McCarthy   if (!m_context_stale)
15418a9135dSAdrian McCarthy     return true;
15518a9135dSAdrian McCarthy 
15618a9135dSAdrian McCarthy   TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
157344bdeb7SMartin Storsjö   memset(&m_context, 0, sizeof(m_context));
158344bdeb7SMartin Storsjö   m_context.ContextFlags = kWinContextFlags;
1595146a9eaSAaron Smith   if (::SuspendThread(
1605146a9eaSAaron Smith           wthread.GetHostThread().GetNativeThread().GetSystemHandle()) ==
1615146a9eaSAaron Smith       (DWORD)-1) {
16209ede9d6SAlex Langford     return false;
16309ede9d6SAlex Langford   }
164b9c1b51eSKate Stone   if (!::GetThreadContext(
165b9c1b51eSKate Stone           wthread.GetHostThread().GetNativeThread().GetSystemHandle(),
166b9c1b51eSKate Stone           &m_context)) {
167a385d2c1SPavel Labath     LLDB_LOG(
168a385d2c1SPavel Labath         log,
169a385d2c1SPavel Labath         "GetThreadContext failed with error {0} while caching register values.",
17018a9135dSAdrian McCarthy         ::GetLastError());
17118a9135dSAdrian McCarthy     return false;
17218a9135dSAdrian McCarthy   }
1735146a9eaSAaron Smith   if (::ResumeThread(
1745146a9eaSAaron Smith           wthread.GetHostThread().GetNativeThread().GetSystemHandle()) ==
1755146a9eaSAaron Smith       (DWORD)-1) {
17609ede9d6SAlex Langford     return false;
17709ede9d6SAlex Langford   }
178a385d2c1SPavel Labath   LLDB_LOG(log, "successfully updated the register values.");
17918a9135dSAdrian McCarthy   m_context_stale = false;
18018a9135dSAdrian McCarthy   return true;
18118a9135dSAdrian McCarthy }
1826179c0ebSAleksandr Urakov 
ApplyAllRegisterValues()1836179c0ebSAleksandr Urakov bool RegisterContextWindows::ApplyAllRegisterValues() {
1846179c0ebSAleksandr Urakov   TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
1856179c0ebSAleksandr Urakov   return ::SetThreadContext(
1866179c0ebSAleksandr Urakov       wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context);
1876179c0ebSAleksandr Urakov }
188