180814287SRaphael Isemann //===-- NativeThreadWindows.cpp -------------------------------------------===//
25146a9eaSAaron Smith //
35146a9eaSAaron Smith // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45146a9eaSAaron Smith // See https://llvm.org/LICENSE.txt for license information.
55146a9eaSAaron Smith // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65146a9eaSAaron Smith //
75146a9eaSAaron Smith //===----------------------------------------------------------------------===//
85146a9eaSAaron Smith 
95146a9eaSAaron Smith #include "NativeThreadWindows.h"
105146a9eaSAaron Smith #include "NativeProcessWindows.h"
115146a9eaSAaron Smith 
125146a9eaSAaron Smith #include "lldb/Host/HostThread.h"
132e8b5755SSaleem Abdulrasool #include "lldb/Host/windows/HostThreadWindows.h"
145146a9eaSAaron Smith #include "lldb/Host/windows/windows.h"
155146a9eaSAaron Smith #include "lldb/Target/Process.h"
165146a9eaSAaron Smith #include "lldb/Utility/Log.h"
175146a9eaSAaron Smith #include "lldb/Utility/State.h"
185146a9eaSAaron Smith 
195146a9eaSAaron Smith #include "lldb/lldb-forward.h"
205146a9eaSAaron Smith 
215146a9eaSAaron Smith using namespace lldb;
225146a9eaSAaron Smith using namespace lldb_private;
235146a9eaSAaron Smith 
245146a9eaSAaron Smith NativeThreadWindows::NativeThreadWindows(NativeProcessWindows &process,
255146a9eaSAaron Smith                                          const HostThread &thread)
265146a9eaSAaron Smith     : NativeThreadProtocol(process, thread.GetNativeThread().GetThreadId()),
275146a9eaSAaron Smith       m_stop_info(), m_stop_description(), m_host_thread(thread) {
285146a9eaSAaron Smith   m_reg_context_up =
295146a9eaSAaron Smith       (NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows(
305146a9eaSAaron Smith           process.GetArchitecture(), *this));
315146a9eaSAaron Smith }
325146a9eaSAaron Smith 
335146a9eaSAaron Smith Status NativeThreadWindows::DoStop() {
345146a9eaSAaron Smith   if (m_state != eStateStopped) {
355146a9eaSAaron Smith     DWORD previous_suspend_count =
365146a9eaSAaron Smith         ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
375146a9eaSAaron Smith     if (previous_suspend_count == (DWORD)-1)
385146a9eaSAaron Smith       return Status(::GetLastError(), eErrorTypeWin32);
395146a9eaSAaron Smith 
405146a9eaSAaron Smith     m_state = eStateStopped;
415146a9eaSAaron Smith   }
425146a9eaSAaron Smith   return Status();
435146a9eaSAaron Smith }
445146a9eaSAaron Smith 
455146a9eaSAaron Smith Status NativeThreadWindows::DoResume(lldb::StateType resume_state) {
465146a9eaSAaron Smith   StateType current_state = GetState();
475146a9eaSAaron Smith   if (resume_state == current_state)
485146a9eaSAaron Smith     return Status();
495146a9eaSAaron Smith 
505146a9eaSAaron Smith   if (resume_state == eStateStepping) {
51*a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Thread);
529f34f75fSMartin Storsjö 
535146a9eaSAaron Smith     uint32_t flags_index =
545146a9eaSAaron Smith         GetRegisterContext().ConvertRegisterKindToRegisterNumber(
555146a9eaSAaron Smith             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
565146a9eaSAaron Smith     uint64_t flags_value =
575146a9eaSAaron Smith         GetRegisterContext().ReadRegisterAsUnsigned(flags_index, 0);
589f34f75fSMartin Storsjö     NativeProcessProtocol &process = GetProcess();
599f34f75fSMartin Storsjö     const ArchSpec &arch = process.GetArchitecture();
609f34f75fSMartin Storsjö     switch (arch.GetMachine()) {
619f34f75fSMartin Storsjö     case llvm::Triple::x86:
629f34f75fSMartin Storsjö     case llvm::Triple::x86_64:
635146a9eaSAaron Smith       flags_value |= 0x100; // Set the trap flag on the CPU
649f34f75fSMartin Storsjö       break;
659f34f75fSMartin Storsjö     case llvm::Triple::aarch64:
669f34f75fSMartin Storsjö     case llvm::Triple::arm:
679f34f75fSMartin Storsjö     case llvm::Triple::thumb:
689f34f75fSMartin Storsjö       flags_value |= 0x200000; // The SS bit in PState
699f34f75fSMartin Storsjö       break;
709f34f75fSMartin Storsjö     default:
719f34f75fSMartin Storsjö       LLDB_LOG(log, "single stepping unsupported on this architecture");
729f34f75fSMartin Storsjö       break;
739f34f75fSMartin Storsjö     }
745146a9eaSAaron Smith     GetRegisterContext().WriteRegisterFromUnsigned(flags_index, flags_value);
755146a9eaSAaron Smith   }
765146a9eaSAaron Smith 
775146a9eaSAaron Smith   if (resume_state == eStateStepping || resume_state == eStateRunning) {
785146a9eaSAaron Smith     DWORD previous_suspend_count = 0;
795146a9eaSAaron Smith     HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
805146a9eaSAaron Smith     do {
815146a9eaSAaron Smith       // ResumeThread returns -1 on error, or the thread's *previous* suspend
825146a9eaSAaron Smith       // count on success. This means that the return value is 1 when the thread
835146a9eaSAaron Smith       // was restarted. Note that DWORD is an unsigned int, so we need to
845146a9eaSAaron Smith       // explicitly compare with -1.
855146a9eaSAaron Smith       previous_suspend_count = ::ResumeThread(thread_handle);
865146a9eaSAaron Smith 
875146a9eaSAaron Smith       if (previous_suspend_count == (DWORD)-1)
885146a9eaSAaron Smith         return Status(::GetLastError(), eErrorTypeWin32);
895146a9eaSAaron Smith 
905146a9eaSAaron Smith     } while (previous_suspend_count > 1);
915146a9eaSAaron Smith     m_state = eStateRunning;
925146a9eaSAaron Smith   }
935146a9eaSAaron Smith 
945146a9eaSAaron Smith   return Status();
955146a9eaSAaron Smith }
965146a9eaSAaron Smith 
975146a9eaSAaron Smith std::string NativeThreadWindows::GetName() {
985146a9eaSAaron Smith   if (!m_name.empty())
995146a9eaSAaron Smith     return m_name;
1005146a9eaSAaron Smith 
1015146a9eaSAaron Smith   // Name is not a property of the Windows thread. Create one with the
1025146a9eaSAaron Smith   // process's.
1035146a9eaSAaron Smith   NativeProcessProtocol &process = GetProcess();
1045146a9eaSAaron Smith   ProcessInstanceInfo process_info;
1055146a9eaSAaron Smith   if (Host::GetProcessInfo(process.GetID(), process_info)) {
1065146a9eaSAaron Smith     std::string process_name(process_info.GetName());
1075146a9eaSAaron Smith     m_name = process_name;
1085146a9eaSAaron Smith   }
1095146a9eaSAaron Smith   return m_name;
1105146a9eaSAaron Smith }
1115146a9eaSAaron Smith 
1125146a9eaSAaron Smith void NativeThreadWindows::SetStopReason(ThreadStopInfo stop_info,
1135146a9eaSAaron Smith                                         std::string description) {
1145146a9eaSAaron Smith   m_state = eStateStopped;
1155146a9eaSAaron Smith   m_stop_info = stop_info;
1165146a9eaSAaron Smith   m_stop_description = description;
1175146a9eaSAaron Smith }
1185146a9eaSAaron Smith 
1195146a9eaSAaron Smith bool NativeThreadWindows::GetStopReason(ThreadStopInfo &stop_info,
1205146a9eaSAaron Smith                                         std::string &description) {
121*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Thread);
1225146a9eaSAaron Smith 
1235146a9eaSAaron Smith   switch (m_state) {
1245146a9eaSAaron Smith   case eStateStopped:
1255146a9eaSAaron Smith   case eStateCrashed:
1265146a9eaSAaron Smith   case eStateExited:
1275146a9eaSAaron Smith   case eStateSuspended:
1285146a9eaSAaron Smith   case eStateUnloaded:
1295146a9eaSAaron Smith     stop_info = m_stop_info;
1305146a9eaSAaron Smith     description = m_stop_description;
1315146a9eaSAaron Smith     return true;
1325146a9eaSAaron Smith 
1335146a9eaSAaron Smith   case eStateInvalid:
1345146a9eaSAaron Smith   case eStateConnected:
1355146a9eaSAaron Smith   case eStateAttaching:
1365146a9eaSAaron Smith   case eStateLaunching:
1375146a9eaSAaron Smith   case eStateRunning:
1385146a9eaSAaron Smith   case eStateStepping:
1395146a9eaSAaron Smith   case eStateDetached:
1405146a9eaSAaron Smith     if (log) {
1415146a9eaSAaron Smith       log->Printf("NativeThreadWindows::%s tid %" PRIu64
1425146a9eaSAaron Smith                   " in state %s cannot answer stop reason",
1435146a9eaSAaron Smith                   __FUNCTION__, GetID(), StateAsCString(m_state));
1445146a9eaSAaron Smith     }
1455146a9eaSAaron Smith     return false;
1465146a9eaSAaron Smith   }
1475146a9eaSAaron Smith   llvm_unreachable("unhandled StateType!");
1485146a9eaSAaron Smith }
1495146a9eaSAaron Smith 
1505146a9eaSAaron Smith Status NativeThreadWindows::SetWatchpoint(lldb::addr_t addr, size_t size,
1515146a9eaSAaron Smith                                           uint32_t watch_flags, bool hardware) {
1525b5274eaSAleksandr Urakov   if (!hardware)
1535b5274eaSAleksandr Urakov     return Status("not implemented");
1545b5274eaSAleksandr Urakov   if (m_state == eStateLaunching)
1555b5274eaSAleksandr Urakov     return Status();
1565b5274eaSAleksandr Urakov   Status error = RemoveWatchpoint(addr);
1575b5274eaSAleksandr Urakov   if (error.Fail())
1585b5274eaSAleksandr Urakov     return error;
1595b5274eaSAleksandr Urakov   uint32_t wp_index =
1605b5274eaSAleksandr Urakov       m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags);
1615b5274eaSAleksandr Urakov   if (wp_index == LLDB_INVALID_INDEX32)
1625b5274eaSAleksandr Urakov     return Status("Setting hardware watchpoint failed.");
1635b5274eaSAleksandr Urakov   m_watchpoint_index_map.insert({addr, wp_index});
1645b5274eaSAleksandr Urakov   return Status();
1655146a9eaSAaron Smith }
1665146a9eaSAaron Smith 
1675146a9eaSAaron Smith Status NativeThreadWindows::RemoveWatchpoint(lldb::addr_t addr) {
1685b5274eaSAleksandr Urakov   auto wp = m_watchpoint_index_map.find(addr);
1695b5274eaSAleksandr Urakov   if (wp == m_watchpoint_index_map.end())
1705b5274eaSAleksandr Urakov     return Status();
1715b5274eaSAleksandr Urakov   uint32_t wp_index = wp->second;
1725b5274eaSAleksandr Urakov   m_watchpoint_index_map.erase(wp);
1735b5274eaSAleksandr Urakov   if (m_reg_context_up->ClearHardwareWatchpoint(wp_index))
1745b5274eaSAleksandr Urakov     return Status();
1755b5274eaSAleksandr Urakov   return Status("Clearing hardware watchpoint failed.");
1765146a9eaSAaron Smith }
1775146a9eaSAaron Smith 
1785146a9eaSAaron Smith Status NativeThreadWindows::SetHardwareBreakpoint(lldb::addr_t addr,
1795146a9eaSAaron Smith                                                   size_t size) {
1805146a9eaSAaron Smith   return Status("unimplemented.");
1815146a9eaSAaron Smith }
1825146a9eaSAaron Smith 
1835146a9eaSAaron Smith Status NativeThreadWindows::RemoveHardwareBreakpoint(lldb::addr_t addr) {
1845146a9eaSAaron Smith   return Status("unimplemented.");
1855146a9eaSAaron Smith }
186