xref: /llvm-project/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp (revision a819b0e55fafab0c6c4b059fc0132620f43ac38a)
1 //===-- TargetThreadWindows.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 "lldb/Host/HostInfo.h"
10 #include "lldb/Target/Unwind.h"
11 #include "lldb/Utility/LLDBLog.h"
12 #include "lldb/Utility/Log.h"
13 
14 #include "ProcessWindows.h"
15 #include "TargetThreadWindows.h"
16 #include "lldb/Host/windows/HostThreadWindows.h"
17 #include <llvm/Support/ConvertUTF.h>
18 
19 #if defined(__x86_64__) || defined(_M_AMD64)
20 #include "x64/RegisterContextWindows_x64.h"
21 #elif defined(__i386__) || defined(_M_IX86)
22 #include "x86/RegisterContextWindows_x86.h"
23 #elif defined(__aarch64__) || defined(_M_ARM64)
24 #include "arm64/RegisterContextWindows_arm64.h"
25 #elif defined(__arm__) || defined(_M_ARM)
26 #include "arm/RegisterContextWindows_arm.h"
27 #endif
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 
32 using GetThreadDescriptionFunctionPtr =
33     HRESULT(WINAPI *)(HANDLE hThread, PWSTR *ppszThreadDescription);
34 
35 TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
36                                          const HostThread &thread)
37     : Thread(process, thread.GetNativeThread().GetThreadId()),
38       m_thread_reg_ctx_sp(), m_host_thread(thread) {}
39 
40 TargetThreadWindows::~TargetThreadWindows() { DestroyThread(); }
41 
42 void TargetThreadWindows::RefreshStateAfterStop() {
43   ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
44   SetState(eStateStopped);
45   GetRegisterContext()->InvalidateIfNeeded(false);
46 }
47 
48 void TargetThreadWindows::WillResume(lldb::StateType resume_state) {}
49 
50 void TargetThreadWindows::DidStop() {}
51 
52 RegisterContextSP TargetThreadWindows::GetRegisterContext() {
53   if (!m_reg_context_sp)
54     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
55 
56   return m_reg_context_sp;
57 }
58 
59 RegisterContextSP
60 TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) {
61   RegisterContextSP reg_ctx_sp;
62   uint32_t concrete_frame_idx = 0;
63   Log *log = GetLog(LLDBLog::Thread);
64 
65   if (frame)
66     concrete_frame_idx = frame->GetConcreteFrameIndex();
67 
68   if (concrete_frame_idx == 0) {
69     if (!m_thread_reg_ctx_sp) {
70       ArchSpec arch = HostInfo::GetArchitecture();
71       switch (arch.GetMachine()) {
72       case llvm::Triple::arm:
73       case llvm::Triple::thumb:
74 #if defined(__arm__) || defined(_M_ARM)
75         m_thread_reg_ctx_sp.reset(
76             new RegisterContextWindows_arm(*this, concrete_frame_idx));
77 #else
78         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
79 #endif
80         break;
81 
82       case llvm::Triple::aarch64:
83 #if defined(__aarch64__) || defined(_M_ARM64)
84         m_thread_reg_ctx_sp.reset(
85             new RegisterContextWindows_arm64(*this, concrete_frame_idx));
86 #else
87         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
88 #endif
89         break;
90 
91       case llvm::Triple::x86:
92 #if defined(__i386__) || defined(_M_IX86)
93         m_thread_reg_ctx_sp.reset(
94             new RegisterContextWindows_x86(*this, concrete_frame_idx));
95 #else
96         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
97 #endif
98         break;
99 
100       case llvm::Triple::x86_64:
101 #if defined(__x86_64__) || defined(_M_AMD64)
102         m_thread_reg_ctx_sp.reset(
103             new RegisterContextWindows_x64(*this, concrete_frame_idx));
104 #else
105         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
106 #endif
107         break;
108 
109       default:
110         break;
111       }
112     }
113     reg_ctx_sp = m_thread_reg_ctx_sp;
114   } else {
115     reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
116   }
117 
118   return reg_ctx_sp;
119 }
120 
121 bool TargetThreadWindows::CalculateStopInfo() {
122   SetStopInfo(m_stop_info_sp);
123   return true;
124 }
125 
126 Status TargetThreadWindows::DoResume() {
127   StateType resume_state = GetTemporaryResumeState();
128   StateType current_state = GetState();
129   if (resume_state == current_state)
130     return Status();
131 
132   if (resume_state == eStateStepping) {
133     Log *log = GetLog(LLDBLog::Thread);
134 
135     uint32_t flags_index =
136         GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
137             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
138     uint64_t flags_value =
139         GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
140     ProcessSP process = GetProcess();
141     const ArchSpec &arch = process->GetTarget().GetArchitecture();
142     switch (arch.GetMachine()) {
143     case llvm::Triple::x86:
144     case llvm::Triple::x86_64:
145       flags_value |= 0x100; // Set the trap flag on the CPU
146       break;
147     case llvm::Triple::aarch64:
148     case llvm::Triple::arm:
149     case llvm::Triple::thumb:
150       flags_value |= 0x200000; // The SS bit in PState
151       break;
152     default:
153       LLDB_LOG(log, "single stepping unsupported on this architecture");
154       break;
155     }
156     GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
157   }
158 
159   if (resume_state == eStateStepping || resume_state == eStateRunning) {
160     DWORD previous_suspend_count = 0;
161     HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
162     do {
163       // ResumeThread returns -1 on error, or the thread's *previous* suspend
164       // count on success. This means that the return value is 1 when the thread
165       // was restarted. Note that DWORD is an unsigned int, so we need to
166       // explicitly compare with -1.
167       previous_suspend_count = ::ResumeThread(thread_handle);
168 
169       if (previous_suspend_count == (DWORD)-1)
170         return Status(::GetLastError(), eErrorTypeWin32);
171 
172     } while (previous_suspend_count > 1);
173   }
174 
175   return Status();
176 }
177 
178 const char *TargetThreadWindows::GetName() {
179   Log *log = GetLog(LLDBLog::Thread);
180   static GetThreadDescriptionFunctionPtr GetThreadDescription = []() {
181     HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll");
182     return hModule
183                ? reinterpret_cast<GetThreadDescriptionFunctionPtr>(
184                      (void *)::GetProcAddress(hModule, "GetThreadDescription"))
185                : nullptr;
186   }();
187   LLDB_LOGF(log, "GetProcAddress: %p",
188             reinterpret_cast<void *>(GetThreadDescription));
189   if (!GetThreadDescription)
190     return m_name.c_str();
191   PWSTR pszThreadName;
192   if (SUCCEEDED(GetThreadDescription(
193           m_host_thread.GetNativeThread().GetSystemHandle(), &pszThreadName))) {
194     LLDB_LOGF(log, "GetThreadDescription: %ls", pszThreadName);
195     llvm::convertUTF16ToUTF8String(
196         llvm::ArrayRef(reinterpret_cast<char *>(pszThreadName),
197                        wcslen(pszThreadName) * sizeof(wchar_t)),
198         m_name);
199     ::LocalFree(pszThreadName);
200   }
201 
202   return m_name.c_str();
203 }
204