169 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- NativeThreadWindows.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 "NativeThreadWindows.h"
 | |
| #include "NativeProcessWindows.h"
 | |
| 
 | |
| #include "lldb/Host/HostThread.h"
 | |
| #include "lldb/Host/windows/HostThreadWindows.h"
 | |
| #include "lldb/Host/windows/windows.h"
 | |
| #include "lldb/Target/Process.h"
 | |
| #include "lldb/Utility/Log.h"
 | |
| #include "lldb/Utility/State.h"
 | |
| 
 | |
| #include "lldb/lldb-forward.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| 
 | |
| NativeThreadWindows::NativeThreadWindows(NativeProcessWindows &process,
 | |
|                                          const HostThread &thread)
 | |
|     : NativeThreadProtocol(process, thread.GetNativeThread().GetThreadId()),
 | |
|       m_stop_info(), m_stop_description(), m_host_thread(thread) {
 | |
|   m_reg_context_up =
 | |
|       (NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows(
 | |
|           process.GetArchitecture(), *this));
 | |
| }
 | |
| 
 | |
| Status NativeThreadWindows::DoStop() {
 | |
|   if (m_state != eStateStopped) {
 | |
|     DWORD previous_suspend_count =
 | |
|         ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
 | |
|     if (previous_suspend_count == (DWORD)-1)
 | |
|       return Status(::GetLastError(), eErrorTypeWin32);
 | |
| 
 | |
|     m_state = eStateStopped;
 | |
|   }
 | |
|   return Status();
 | |
| }
 | |
| 
 | |
| Status NativeThreadWindows::DoResume(lldb::StateType resume_state) {
 | |
|   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);
 | |
|     m_state = eStateRunning;
 | |
|   }
 | |
| 
 | |
|   return Status();
 | |
| }
 | |
| 
 | |
| std::string NativeThreadWindows::GetName() {
 | |
|   if (!m_name.empty())
 | |
|     return m_name;
 | |
| 
 | |
|   // Name is not a property of the Windows thread. Create one with the
 | |
|   // process's.
 | |
|   NativeProcessProtocol &process = GetProcess();
 | |
|   ProcessInstanceInfo process_info;
 | |
|   if (Host::GetProcessInfo(process.GetID(), process_info)) {
 | |
|     std::string process_name(process_info.GetName());
 | |
|     m_name = process_name;
 | |
|   }
 | |
|   return m_name;
 | |
| }
 | |
| 
 | |
| void NativeThreadWindows::SetStopReason(ThreadStopInfo stop_info,
 | |
|                                         std::string description) {
 | |
|   m_state = eStateStopped;
 | |
|   m_stop_info = stop_info;
 | |
|   m_stop_description = description;
 | |
| }
 | |
| 
 | |
| bool NativeThreadWindows::GetStopReason(ThreadStopInfo &stop_info,
 | |
|                                         std::string &description) {
 | |
|   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
 | |
| 
 | |
|   switch (m_state) {
 | |
|   case eStateStopped:
 | |
|   case eStateCrashed:
 | |
|   case eStateExited:
 | |
|   case eStateSuspended:
 | |
|   case eStateUnloaded:
 | |
|     stop_info = m_stop_info;
 | |
|     description = m_stop_description;
 | |
|     return true;
 | |
| 
 | |
|   case eStateInvalid:
 | |
|   case eStateConnected:
 | |
|   case eStateAttaching:
 | |
|   case eStateLaunching:
 | |
|   case eStateRunning:
 | |
|   case eStateStepping:
 | |
|   case eStateDetached:
 | |
|     if (log) {
 | |
|       log->Printf("NativeThreadWindows::%s tid %" PRIu64
 | |
|                   " in state %s cannot answer stop reason",
 | |
|                   __FUNCTION__, GetID(), StateAsCString(m_state));
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   llvm_unreachable("unhandled StateType!");
 | |
| }
 | |
| 
 | |
| Status NativeThreadWindows::SetWatchpoint(lldb::addr_t addr, size_t size,
 | |
|                                           uint32_t watch_flags, bool hardware) {
 | |
|   if (!hardware)
 | |
|     return Status("not implemented");
 | |
|   if (m_state == eStateLaunching)
 | |
|     return Status();
 | |
|   Status error = RemoveWatchpoint(addr);
 | |
|   if (error.Fail())
 | |
|     return error;
 | |
|   uint32_t wp_index =
 | |
|       m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags);
 | |
|   if (wp_index == LLDB_INVALID_INDEX32)
 | |
|     return Status("Setting hardware watchpoint failed.");
 | |
|   m_watchpoint_index_map.insert({addr, wp_index});
 | |
|   return Status();
 | |
| }
 | |
| 
 | |
| Status NativeThreadWindows::RemoveWatchpoint(lldb::addr_t addr) {
 | |
|   auto wp = m_watchpoint_index_map.find(addr);
 | |
|   if (wp == m_watchpoint_index_map.end())
 | |
|     return Status();
 | |
|   uint32_t wp_index = wp->second;
 | |
|   m_watchpoint_index_map.erase(wp);
 | |
|   if (m_reg_context_up->ClearHardwareWatchpoint(wp_index))
 | |
|     return Status();
 | |
|   return Status("Clearing hardware watchpoint failed.");
 | |
| }
 | |
| 
 | |
| Status NativeThreadWindows::SetHardwareBreakpoint(lldb::addr_t addr,
 | |
|                                                   size_t size) {
 | |
|   return Status("unimplemented.");
 | |
| }
 | |
| 
 | |
| Status NativeThreadWindows::RemoveHardwareBreakpoint(lldb::addr_t addr) {
 | |
|   return Status("unimplemented.");
 | |
| }
 |