161 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- TargetThreadWindows.cpp--------------------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "lldb/Host/HostInfo.h"
 | |
| #include "lldb/Host/HostNativeThreadBase.h"
 | |
| #include "lldb/Host/windows/HostThreadWindows.h"
 | |
| #include "lldb/Host/windows/windows.h"
 | |
| #include "lldb/Target/RegisterContext.h"
 | |
| #include "lldb/Target/Unwind.h"
 | |
| #include "lldb/Utility/Log.h"
 | |
| #include "lldb/Utility/Logging.h"
 | |
| #include "lldb/Utility/State.h"
 | |
| 
 | |
| #include "ProcessWindows.h"
 | |
| #include "ProcessWindowsLog.h"
 | |
| #include "TargetThreadWindows.h"
 | |
| 
 | |
| #if defined(__x86_64__) || defined(_M_AMD64)
 | |
| #include "x64/RegisterContextWindows_x64.h"
 | |
| #elif defined(__i386__) || defined(_M_IX86)
 | |
| #include "x86/RegisterContextWindows_x86.h"
 | |
| #elif defined(__aarch64__) || defined(_M_ARM64)
 | |
| #include "arm64/RegisterContextWindows_arm64.h"
 | |
| #elif defined(__arm__) || defined(_M_ARM)
 | |
| #include "arm/RegisterContextWindows_arm.h"
 | |
| #endif
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| 
 | |
| TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
 | |
|                                          const HostThread &thread)
 | |
|     : Thread(process, thread.GetNativeThread().GetThreadId()),
 | |
|       m_thread_reg_ctx_sp(), m_host_thread(thread) {}
 | |
| 
 | |
| TargetThreadWindows::~TargetThreadWindows() { DestroyThread(); }
 | |
| 
 | |
| void TargetThreadWindows::RefreshStateAfterStop() {
 | |
|   ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
 | |
|   SetState(eStateStopped);
 | |
|   GetRegisterContext()->InvalidateIfNeeded(false);
 | |
| }
 | |
| 
 | |
| void TargetThreadWindows::WillResume(lldb::StateType resume_state) {}
 | |
| 
 | |
| void TargetThreadWindows::DidStop() {}
 | |
| 
 | |
| RegisterContextSP TargetThreadWindows::GetRegisterContext() {
 | |
|   if (!m_reg_context_sp)
 | |
|     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
 | |
| 
 | |
|   return m_reg_context_sp;
 | |
| }
 | |
| 
 | |
| RegisterContextSP
 | |
| TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) {
 | |
|   RegisterContextSP reg_ctx_sp;
 | |
|   uint32_t concrete_frame_idx = 0;
 | |
|   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
 | |
| 
 | |
|   if (frame)
 | |
|     concrete_frame_idx = frame->GetConcreteFrameIndex();
 | |
| 
 | |
|   if (concrete_frame_idx == 0) {
 | |
|     if (!m_thread_reg_ctx_sp) {
 | |
|       ArchSpec arch = HostInfo::GetArchitecture();
 | |
|       switch (arch.GetMachine()) {
 | |
|       case llvm::Triple::arm:
 | |
|       case llvm::Triple::thumb:
 | |
| #if defined(__arm__) || defined(_M_ARM)
 | |
|         m_thread_reg_ctx_sp.reset(
 | |
|             new RegisterContextWindows_arm(*this, concrete_frame_idx));
 | |
| #else
 | |
|         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
 | |
| #endif
 | |
|         break;
 | |
| 
 | |
|       case llvm::Triple::aarch64:
 | |
| #if defined(__aarch64__) || defined(_M_ARM64)
 | |
|         m_thread_reg_ctx_sp.reset(
 | |
|             new RegisterContextWindows_arm64(*this, concrete_frame_idx));
 | |
| #else
 | |
|         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
 | |
| #endif
 | |
|         break;
 | |
| 
 | |
|       case llvm::Triple::x86:
 | |
| #if defined(__i386__) || defined(_M_IX86)
 | |
|         m_thread_reg_ctx_sp.reset(
 | |
|             new RegisterContextWindows_x86(*this, concrete_frame_idx));
 | |
| #else
 | |
|         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
 | |
| #endif
 | |
|         break;
 | |
| 
 | |
|       case llvm::Triple::x86_64:
 | |
| #if defined(__x86_64__) || defined(_M_AMD64)
 | |
|         m_thread_reg_ctx_sp.reset(
 | |
|             new RegisterContextWindows_x64(*this, concrete_frame_idx));
 | |
| #else
 | |
|         LLDB_LOG(log, "debugging foreign targets is currently unsupported");
 | |
| #endif
 | |
|         break;
 | |
| 
 | |
|       default:
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     reg_ctx_sp = m_thread_reg_ctx_sp;
 | |
|   } else {
 | |
|     reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
 | |
|   }
 | |
| 
 | |
|   return reg_ctx_sp;
 | |
| }
 | |
| 
 | |
| bool TargetThreadWindows::CalculateStopInfo() {
 | |
|   SetStopInfo(m_stop_info_sp);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| Status TargetThreadWindows::DoResume() {
 | |
|   StateType resume_state = GetTemporaryResumeState();
 | |
|   StateType current_state = GetState();
 | |
|   if (resume_state == current_state)
 | |
|     return Status();
 | |
| 
 | |
|   if (resume_state == eStateStepping) {
 | |
|     uint32_t flags_index =
 | |
|         GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
 | |
|             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
 | |
|     uint64_t flags_value =
 | |
|         GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
 | |
|     flags_value |= 0x100; // Set the trap flag on the CPU
 | |
|     GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
 | |
|   }
 | |
| 
 | |
|   if (resume_state == eStateStepping || resume_state == eStateRunning) {
 | |
|     DWORD previous_suspend_count = 0;
 | |
|     HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
 | |
|     do {
 | |
|       // ResumeThread returns -1 on error, or the thread's *previous* suspend
 | |
|       // count on success. This means that the return value is 1 when the thread
 | |
|       // was restarted. Note that DWORD is an unsigned int, so we need to
 | |
|       // explicitly compare with -1.
 | |
|       previous_suspend_count = ::ResumeThread(thread_handle);
 | |
| 
 | |
|       if (previous_suspend_count == (DWORD)-1)
 | |
|         return Status(::GetLastError(), eErrorTypeWin32);
 | |
| 
 | |
|     } while (previous_suspend_count > 1);
 | |
|   }
 | |
| 
 | |
|   return Status();
 | |
| }
 |