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 and _M_ARM64
24 #if defined(_M_AMD64)
25 #include "x64/RegisterContextWindows_x64.h"
26 #elif defined(_M_IX86)
27 #include "x86/RegisterContextWindows_x86.h"
28 #endif
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
34                                          const HostThread &thread)
35     : Thread(process, thread.GetNativeThread().GetThreadId()),
36       m_thread_reg_ctx_sp(), m_host_thread(thread) {}
37 
38 TargetThreadWindows::~TargetThreadWindows() { DestroyThread(); }
39 
40 void TargetThreadWindows::RefreshStateAfterStop() {
41   ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
42   SetState(eStateStopped);
43   GetRegisterContext()->InvalidateIfNeeded(false);
44 }
45 
46 void TargetThreadWindows::WillResume(lldb::StateType resume_state) {}
47 
48 void TargetThreadWindows::DidStop() {}
49 
50 RegisterContextSP TargetThreadWindows::GetRegisterContext() {
51   if (!m_reg_context_sp)
52     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
53 
54   return m_reg_context_sp;
55 }
56 
57 RegisterContextSP
58 TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) {
59   RegisterContextSP reg_ctx_sp;
60   uint32_t concrete_frame_idx = 0;
61   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
62 
63   if (frame)
64     concrete_frame_idx = frame->GetConcreteFrameIndex();
65 
66   if (concrete_frame_idx == 0) {
67     if (!m_thread_reg_ctx_sp) {
68       ArchSpec arch = HostInfo::GetArchitecture();
69       switch (arch.GetMachine()) {
70       case llvm::Triple::arm:
71       case llvm::Triple::thumb:
72         LLDB_LOG(log, "debugging ARM (NT) targets is currently unsupported");
73         break;
74 
75       case llvm::Triple::aarch64:
76         LLDB_LOG(log, "debugging ARM64 targets is currently unsupported");
77         break;
78 
79       case llvm::Triple::x86:
80 #if defined(_M_IX86)
81         m_thread_reg_ctx_sp.reset(
82             new RegisterContextWindows_x86(*this, concrete_frame_idx));
83 #else
84         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
85 #endif
86         break;
87 
88       case llvm::Triple::x86_64:
89 #if defined(_M_AMD64)
90         m_thread_reg_ctx_sp.reset(
91             new RegisterContextWindows_x64(*this, concrete_frame_idx));
92 #else
93         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
94 #endif
95         break;
96 
97       default:
98         break;
99       }
100     }
101     reg_ctx_sp = m_thread_reg_ctx_sp;
102   } else {
103     Unwind *unwinder = GetUnwinder();
104     if (unwinder != nullptr)
105       reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame);
106   }
107 
108   return reg_ctx_sp;
109 }
110 
111 bool TargetThreadWindows::CalculateStopInfo() {
112   SetStopInfo(m_stop_info_sp);
113   return true;
114 }
115 
116 Unwind *TargetThreadWindows::GetUnwinder() {
117   // FIXME: Implement an unwinder based on the Windows unwinder exposed through
118   // DIA SDK.
119   if (!m_unwinder_up)
120     m_unwinder_up.reset(new UnwindLLDB(*this));
121   return m_unwinder_up.get();
122 }
123 
124 Status TargetThreadWindows::DoResume() {
125   StateType resume_state = GetTemporaryResumeState();
126   StateType current_state = GetState();
127   if (resume_state == current_state)
128     return Status();
129 
130   if (resume_state == eStateStepping) {
131     uint32_t flags_index =
132         GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
133             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
134     uint64_t flags_value =
135         GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
136     flags_value |= 0x100; // Set the trap flag on the CPU
137     GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
138   }
139 
140   if (resume_state == eStateStepping || resume_state == eStateRunning) {
141     DWORD previous_suspend_count = 0;
142     HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
143     do {
144       // ResumeThread returns -1 on error, or the thread's *previous* suspend
145       // count on success. This means that the return value is 1 when the thread
146       // was restarted. Note that DWORD is an unsigned int, so we need to
147       // explicitly compare with -1.
148       previous_suspend_count = ::ResumeThread(thread_handle);
149 
150       if (previous_suspend_count == (DWORD)-1)
151         return Status(::GetLastError(), eErrorTypeWin32);
152 
153     } while (previous_suspend_count > 1);
154   }
155 
156   return Status();
157 }
158