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