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