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