1*5146a9eaSAaron Smith //===-- NativeThreadWindows.cpp ---------------------------------*- C++ -*-===//
2*5146a9eaSAaron Smith //
3*5146a9eaSAaron Smith // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5146a9eaSAaron Smith // See https://llvm.org/LICENSE.txt for license information.
5*5146a9eaSAaron Smith // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5146a9eaSAaron Smith //
7*5146a9eaSAaron Smith //===----------------------------------------------------------------------===//
8*5146a9eaSAaron Smith 
9*5146a9eaSAaron Smith #include "NativeThreadWindows.h"
10*5146a9eaSAaron Smith #include "NativeProcessWindows.h"
11*5146a9eaSAaron Smith 
12*5146a9eaSAaron Smith #include "lldb/Host/HostThread.h"
13*5146a9eaSAaron Smith #include "lldb/Host/Windows/HostThreadWindows.h"
14*5146a9eaSAaron Smith #include "lldb/Host/windows/windows.h"
15*5146a9eaSAaron Smith #include "lldb/Target/Process.h"
16*5146a9eaSAaron Smith #include "lldb/Utility/Log.h"
17*5146a9eaSAaron Smith #include "lldb/Utility/State.h"
18*5146a9eaSAaron Smith 
19*5146a9eaSAaron Smith #include "lldb/lldb-forward.h"
20*5146a9eaSAaron Smith 
21*5146a9eaSAaron Smith using namespace lldb;
22*5146a9eaSAaron Smith using namespace lldb_private;
23*5146a9eaSAaron Smith 
24*5146a9eaSAaron Smith NativeThreadWindows::NativeThreadWindows(NativeProcessWindows &process,
25*5146a9eaSAaron Smith                                          const HostThread &thread)
26*5146a9eaSAaron Smith     : NativeThreadProtocol(process, thread.GetNativeThread().GetThreadId()),
27*5146a9eaSAaron Smith       m_stop_info(), m_stop_description(), m_host_thread(thread) {
28*5146a9eaSAaron Smith   m_reg_context_up =
29*5146a9eaSAaron Smith       (NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows(
30*5146a9eaSAaron Smith           process.GetArchitecture(), *this));
31*5146a9eaSAaron Smith }
32*5146a9eaSAaron Smith 
33*5146a9eaSAaron Smith Status NativeThreadWindows::DoStop() {
34*5146a9eaSAaron Smith   if (m_state != eStateStopped) {
35*5146a9eaSAaron Smith     DWORD previous_suspend_count =
36*5146a9eaSAaron Smith         ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
37*5146a9eaSAaron Smith     if (previous_suspend_count == (DWORD)-1)
38*5146a9eaSAaron Smith       return Status(::GetLastError(), eErrorTypeWin32);
39*5146a9eaSAaron Smith 
40*5146a9eaSAaron Smith     m_state = eStateStopped;
41*5146a9eaSAaron Smith   }
42*5146a9eaSAaron Smith   return Status();
43*5146a9eaSAaron Smith }
44*5146a9eaSAaron Smith 
45*5146a9eaSAaron Smith Status NativeThreadWindows::DoResume(lldb::StateType resume_state) {
46*5146a9eaSAaron Smith   StateType current_state = GetState();
47*5146a9eaSAaron Smith   if (resume_state == current_state)
48*5146a9eaSAaron Smith     return Status();
49*5146a9eaSAaron Smith 
50*5146a9eaSAaron Smith   if (resume_state == eStateStepping) {
51*5146a9eaSAaron Smith     uint32_t flags_index =
52*5146a9eaSAaron Smith         GetRegisterContext().ConvertRegisterKindToRegisterNumber(
53*5146a9eaSAaron Smith             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
54*5146a9eaSAaron Smith     uint64_t flags_value =
55*5146a9eaSAaron Smith         GetRegisterContext().ReadRegisterAsUnsigned(flags_index, 0);
56*5146a9eaSAaron Smith     flags_value |= 0x100; // Set the trap flag on the CPU
57*5146a9eaSAaron Smith     GetRegisterContext().WriteRegisterFromUnsigned(flags_index, flags_value);
58*5146a9eaSAaron Smith   }
59*5146a9eaSAaron Smith 
60*5146a9eaSAaron Smith   if (resume_state == eStateStepping || resume_state == eStateRunning) {
61*5146a9eaSAaron Smith     DWORD previous_suspend_count = 0;
62*5146a9eaSAaron Smith     HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
63*5146a9eaSAaron Smith     do {
64*5146a9eaSAaron Smith       // ResumeThread returns -1 on error, or the thread's *previous* suspend
65*5146a9eaSAaron Smith       // count on success. This means that the return value is 1 when the thread
66*5146a9eaSAaron Smith       // was restarted. Note that DWORD is an unsigned int, so we need to
67*5146a9eaSAaron Smith       // explicitly compare with -1.
68*5146a9eaSAaron Smith       previous_suspend_count = ::ResumeThread(thread_handle);
69*5146a9eaSAaron Smith 
70*5146a9eaSAaron Smith       if (previous_suspend_count == (DWORD)-1)
71*5146a9eaSAaron Smith         return Status(::GetLastError(), eErrorTypeWin32);
72*5146a9eaSAaron Smith 
73*5146a9eaSAaron Smith     } while (previous_suspend_count > 1);
74*5146a9eaSAaron Smith     m_state = eStateRunning;
75*5146a9eaSAaron Smith   }
76*5146a9eaSAaron Smith 
77*5146a9eaSAaron Smith   return Status();
78*5146a9eaSAaron Smith }
79*5146a9eaSAaron Smith 
80*5146a9eaSAaron Smith std::string NativeThreadWindows::GetName() {
81*5146a9eaSAaron Smith   if (!m_name.empty())
82*5146a9eaSAaron Smith     return m_name;
83*5146a9eaSAaron Smith 
84*5146a9eaSAaron Smith   // Name is not a property of the Windows thread. Create one with the
85*5146a9eaSAaron Smith   // process's.
86*5146a9eaSAaron Smith   NativeProcessProtocol &process = GetProcess();
87*5146a9eaSAaron Smith   ProcessInstanceInfo process_info;
88*5146a9eaSAaron Smith   if (Host::GetProcessInfo(process.GetID(), process_info)) {
89*5146a9eaSAaron Smith     std::string process_name(process_info.GetName());
90*5146a9eaSAaron Smith     m_name = process_name;
91*5146a9eaSAaron Smith   }
92*5146a9eaSAaron Smith   return m_name;
93*5146a9eaSAaron Smith }
94*5146a9eaSAaron Smith 
95*5146a9eaSAaron Smith void NativeThreadWindows::SetStopReason(ThreadStopInfo stop_info,
96*5146a9eaSAaron Smith                                         std::string description) {
97*5146a9eaSAaron Smith   m_state = eStateStopped;
98*5146a9eaSAaron Smith   m_stop_info = stop_info;
99*5146a9eaSAaron Smith   m_stop_description = description;
100*5146a9eaSAaron Smith }
101*5146a9eaSAaron Smith 
102*5146a9eaSAaron Smith bool NativeThreadWindows::GetStopReason(ThreadStopInfo &stop_info,
103*5146a9eaSAaron Smith                                         std::string &description) {
104*5146a9eaSAaron Smith   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
105*5146a9eaSAaron Smith 
106*5146a9eaSAaron Smith   switch (m_state) {
107*5146a9eaSAaron Smith   case eStateStopped:
108*5146a9eaSAaron Smith   case eStateCrashed:
109*5146a9eaSAaron Smith   case eStateExited:
110*5146a9eaSAaron Smith   case eStateSuspended:
111*5146a9eaSAaron Smith   case eStateUnloaded:
112*5146a9eaSAaron Smith     stop_info = m_stop_info;
113*5146a9eaSAaron Smith     description = m_stop_description;
114*5146a9eaSAaron Smith     return true;
115*5146a9eaSAaron Smith 
116*5146a9eaSAaron Smith   case eStateInvalid:
117*5146a9eaSAaron Smith   case eStateConnected:
118*5146a9eaSAaron Smith   case eStateAttaching:
119*5146a9eaSAaron Smith   case eStateLaunching:
120*5146a9eaSAaron Smith   case eStateRunning:
121*5146a9eaSAaron Smith   case eStateStepping:
122*5146a9eaSAaron Smith   case eStateDetached:
123*5146a9eaSAaron Smith     if (log) {
124*5146a9eaSAaron Smith       log->Printf("NativeThreadWindows::%s tid %" PRIu64
125*5146a9eaSAaron Smith                   " in state %s cannot answer stop reason",
126*5146a9eaSAaron Smith                   __FUNCTION__, GetID(), StateAsCString(m_state));
127*5146a9eaSAaron Smith     }
128*5146a9eaSAaron Smith     return false;
129*5146a9eaSAaron Smith   }
130*5146a9eaSAaron Smith   llvm_unreachable("unhandled StateType!");
131*5146a9eaSAaron Smith }
132*5146a9eaSAaron Smith 
133*5146a9eaSAaron Smith Status NativeThreadWindows::SetWatchpoint(lldb::addr_t addr, size_t size,
134*5146a9eaSAaron Smith                                           uint32_t watch_flags, bool hardware) {
135*5146a9eaSAaron Smith   return Status("unimplemented.");
136*5146a9eaSAaron Smith }
137*5146a9eaSAaron Smith 
138*5146a9eaSAaron Smith Status NativeThreadWindows::RemoveWatchpoint(lldb::addr_t addr) {
139*5146a9eaSAaron Smith   return Status("unimplemented");
140*5146a9eaSAaron Smith }
141*5146a9eaSAaron Smith 
142*5146a9eaSAaron Smith Status NativeThreadWindows::SetHardwareBreakpoint(lldb::addr_t addr,
143*5146a9eaSAaron Smith                                                   size_t size) {
144*5146a9eaSAaron Smith   return Status("unimplemented.");
145*5146a9eaSAaron Smith }
146*5146a9eaSAaron Smith 
147*5146a9eaSAaron Smith Status NativeThreadWindows::RemoveHardwareBreakpoint(lldb::addr_t addr) {
148*5146a9eaSAaron Smith   return Status("unimplemented.");
149*5146a9eaSAaron Smith }
150