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