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
29using namespace lldb;
30using namespace lldb_private;
31
32using GetThreadDescriptionFunctionPtr =
33 HRESULT(WINAPI *)(HANDLE hThread, PWSTR *ppszThreadDescription);
34
35TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
36 const HostThread &thread)
37 : Thread(process, thread.GetNativeThread().GetThreadId()),
38 m_thread_reg_ctx_sp(), m_host_thread(thread) {}
39
40TargetThreadWindows::~TargetThreadWindows() { DestroyThread(); }
41
42void TargetThreadWindows::RefreshStateAfterStop() {
43 ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
44 SetState(eStateStopped);
45 GetRegisterContext()->InvalidateIfNeeded(force: false);
46}
47
48void TargetThreadWindows::WillResume(lldb::StateType resume_state) {}
49
50void TargetThreadWindows::DidStop() {}
51
52RegisterContextSP TargetThreadWindows::GetRegisterContext() {
53 if (!m_reg_context_sp)
54 m_reg_context_sp = CreateRegisterContextForFrame(frame: nullptr);
55
56 return m_reg_context_sp;
57}
58
59RegisterContextSP
60TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) {
61 RegisterContextSP reg_ctx_sp;
62 uint32_t concrete_frame_idx = 0;
63 Log *log = GetLog(mask: 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
121bool TargetThreadWindows::CalculateStopInfo() {
122 SetStopInfo(m_stop_info_sp);
123 return true;
124}
125
126Status 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(mask: LLDBLog::Thread);
134
135 uint32_t flags_index =
136 GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
137 kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
138 uint64_t flags_value =
139 GetRegisterContext()->ReadRegisterAsUnsigned(reg: flags_index, fail_value: 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(reg: flags_index, uval: 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
178const char *TargetThreadWindows::GetName() {
179 Log *log = GetLog(mask: LLDBLog::Thread);
180 static GetThreadDescriptionFunctionPtr GetThreadDescription = []() {
181 HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll");
182 return hModule ? reinterpret_cast<GetThreadDescriptionFunctionPtr>(
183 ::GetProcAddress(hModule, "GetThreadDescription"))
184 : nullptr;
185 }();
186 LLDB_LOGF(log, "GetProcAddress: %p",
187 reinterpret_cast<void *>(GetThreadDescription));
188 if (!GetThreadDescription)
189 return m_name.c_str();
190 PWSTR pszThreadName;
191 if (SUCCEEDED(GetThreadDescription(
192 m_host_thread.GetNativeThread().GetSystemHandle(), &pszThreadName))) {
193 LLDB_LOGF(log, "GetThreadDescription: %ls", pszThreadName);
194 llvm::convertUTF16ToUTF8String(
195 llvm::ArrayRef(reinterpret_cast<char *>(pszThreadName),
196 wcslen(pszThreadName) * sizeof(wchar_t)),
197 m_name);
198 ::LocalFree(pszThreadName);
199 }
200
201 return m_name.c_str();
202}
203

source code of lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp