xref: /llvm-project/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp (revision b1f6ba2a2ecdf253c1ee2f2a04156eba78cfe3fa)
1 //===-- TargetThreadWindows.cpp----------------------------------*- C++ -*-===//
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/Host/HostNativeThreadBase.h"
11 #include "lldb/Host/windows/HostThreadWindows.h"
12 #include "lldb/Host/windows/windows.h"
13 #include "lldb/Target/RegisterContext.h"
14 #include "lldb/Utility/Log.h"
15 #include "lldb/Utility/Logging.h"
16 #include "lldb/Utility/State.h"
17 
18 #include "Plugins/Process/Utility/UnwindLLDB.h"
19 #include "ProcessWindows.h"
20 #include "ProcessWindowsLog.h"
21 #include "TargetThreadWindows.h"
22 
23 // TODO support _M_ARM
24 #if defined(__x86_64__) || defined(_M_AMD64)
25 #include "x64/RegisterContextWindows_x64.h"
26 #elif defined(__i386__) || defined(_M_IX86)
27 #include "x86/RegisterContextWindows_x86.h"
28 #elif defined(__aarch64__) || defined(_M_ARM64)
29 #include "arm64/RegisterContextWindows_arm64.h"
30 #endif
31 
32 using namespace lldb;
33 using namespace lldb_private;
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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_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         LLDB_LOG(log, "debugging ARM (NT) targets is currently unsupported");
75         break;
76 
77       case llvm::Triple::aarch64:
78 #if defined(__aarch64__) || defined(_M_ARM64)
79         m_thread_reg_ctx_sp.reset(
80             new RegisterContextWindows_arm64(*this, concrete_frame_idx));
81 #else
82         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
83 #endif
84         break;
85 
86       case llvm::Triple::x86:
87 #if defined(__i386__) || defined(_M_IX86)
88         m_thread_reg_ctx_sp.reset(
89             new RegisterContextWindows_x86(*this, concrete_frame_idx));
90 #else
91         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
92 #endif
93         break;
94 
95       case llvm::Triple::x86_64:
96 #if defined(__x86_64__) || defined(_M_AMD64)
97         m_thread_reg_ctx_sp.reset(
98             new RegisterContextWindows_x64(*this, concrete_frame_idx));
99 #else
100         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
101 #endif
102         break;
103 
104       default:
105         break;
106       }
107     }
108     reg_ctx_sp = m_thread_reg_ctx_sp;
109   } else {
110     Unwind *unwinder = GetUnwinder();
111     if (unwinder != nullptr)
112       reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame);
113   }
114 
115   return reg_ctx_sp;
116 }
117 
118 bool TargetThreadWindows::CalculateStopInfo() {
119   SetStopInfo(m_stop_info_sp);
120   return true;
121 }
122 
123 Unwind *TargetThreadWindows::GetUnwinder() {
124   // FIXME: Implement an unwinder based on the Windows unwinder exposed through
125   // DIA SDK.
126   if (!m_unwinder_up)
127     m_unwinder_up.reset(new UnwindLLDB(*this));
128   return m_unwinder_up.get();
129 }
130 
131 Status TargetThreadWindows::DoResume() {
132   StateType resume_state = GetTemporaryResumeState();
133   StateType current_state = GetState();
134   if (resume_state == current_state)
135     return Status();
136 
137   if (resume_state == eStateStepping) {
138     uint32_t flags_index =
139         GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
140             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
141     uint64_t flags_value =
142         GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
143     flags_value |= 0x100; // Set the trap flag on the CPU
144     GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
145   }
146 
147   if (resume_state == eStateStepping || resume_state == eStateRunning) {
148     DWORD previous_suspend_count = 0;
149     HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
150     do {
151       // ResumeThread returns -1 on error, or the thread's *previous* suspend
152       // count on success. This means that the return value is 1 when the thread
153       // was restarted. Note that DWORD is an unsigned int, so we need to
154       // explicitly compare with -1.
155       previous_suspend_count = ::ResumeThread(thread_handle);
156 
157       if (previous_suspend_count == (DWORD)-1)
158         return Status(::GetLastError(), eErrorTypeWin32);
159 
160     } while (previous_suspend_count > 1);
161   }
162 
163   return Status();
164 }
165