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