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