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