15146a9eaSAaron Smith //===-- NativeThreadWindows.cpp ---------------------------------*- C++ -*-===//
25146a9eaSAaron Smith //
35146a9eaSAaron Smith // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45146a9eaSAaron Smith // See https://llvm.org/LICENSE.txt for license information.
55146a9eaSAaron Smith // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65146a9eaSAaron Smith //
75146a9eaSAaron Smith //===----------------------------------------------------------------------===//
85146a9eaSAaron Smith 
95146a9eaSAaron Smith #include "NativeThreadWindows.h"
105146a9eaSAaron Smith #include "NativeProcessWindows.h"
115146a9eaSAaron Smith 
125146a9eaSAaron Smith #include "lldb/Host/HostThread.h"
132e8b5755SSaleem Abdulrasool #include "lldb/Host/windows/HostThreadWindows.h"
145146a9eaSAaron Smith #include "lldb/Host/windows/windows.h"
155146a9eaSAaron Smith #include "lldb/Target/Process.h"
165146a9eaSAaron Smith #include "lldb/Utility/Log.h"
175146a9eaSAaron Smith #include "lldb/Utility/State.h"
185146a9eaSAaron Smith 
195146a9eaSAaron Smith #include "lldb/lldb-forward.h"
205146a9eaSAaron Smith 
215146a9eaSAaron Smith using namespace lldb;
225146a9eaSAaron Smith using namespace lldb_private;
235146a9eaSAaron Smith 
245146a9eaSAaron Smith NativeThreadWindows::NativeThreadWindows(NativeProcessWindows &process,
255146a9eaSAaron Smith                                          const HostThread &thread)
265146a9eaSAaron Smith     : NativeThreadProtocol(process, thread.GetNativeThread().GetThreadId()),
275146a9eaSAaron Smith       m_stop_info(), m_stop_description(), m_host_thread(thread) {
285146a9eaSAaron Smith   m_reg_context_up =
295146a9eaSAaron Smith       (NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows(
305146a9eaSAaron Smith           process.GetArchitecture(), *this));
315146a9eaSAaron Smith }
325146a9eaSAaron Smith 
335146a9eaSAaron Smith Status NativeThreadWindows::DoStop() {
345146a9eaSAaron Smith   if (m_state != eStateStopped) {
355146a9eaSAaron Smith     DWORD previous_suspend_count =
365146a9eaSAaron Smith         ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
375146a9eaSAaron Smith     if (previous_suspend_count == (DWORD)-1)
385146a9eaSAaron Smith       return Status(::GetLastError(), eErrorTypeWin32);
395146a9eaSAaron Smith 
405146a9eaSAaron Smith     m_state = eStateStopped;
415146a9eaSAaron Smith   }
425146a9eaSAaron Smith   return Status();
435146a9eaSAaron Smith }
445146a9eaSAaron Smith 
455146a9eaSAaron Smith Status NativeThreadWindows::DoResume(lldb::StateType resume_state) {
465146a9eaSAaron Smith   StateType current_state = GetState();
475146a9eaSAaron Smith   if (resume_state == current_state)
485146a9eaSAaron Smith     return Status();
495146a9eaSAaron Smith 
505146a9eaSAaron Smith   if (resume_state == eStateStepping) {
515146a9eaSAaron Smith     uint32_t flags_index =
525146a9eaSAaron Smith         GetRegisterContext().ConvertRegisterKindToRegisterNumber(
535146a9eaSAaron Smith             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
545146a9eaSAaron Smith     uint64_t flags_value =
555146a9eaSAaron Smith         GetRegisterContext().ReadRegisterAsUnsigned(flags_index, 0);
565146a9eaSAaron Smith     flags_value |= 0x100; // Set the trap flag on the CPU
575146a9eaSAaron Smith     GetRegisterContext().WriteRegisterFromUnsigned(flags_index, flags_value);
585146a9eaSAaron Smith   }
595146a9eaSAaron Smith 
605146a9eaSAaron Smith   if (resume_state == eStateStepping || resume_state == eStateRunning) {
615146a9eaSAaron Smith     DWORD previous_suspend_count = 0;
625146a9eaSAaron Smith     HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
635146a9eaSAaron Smith     do {
645146a9eaSAaron Smith       // ResumeThread returns -1 on error, or the thread's *previous* suspend
655146a9eaSAaron Smith       // count on success. This means that the return value is 1 when the thread
665146a9eaSAaron Smith       // was restarted. Note that DWORD is an unsigned int, so we need to
675146a9eaSAaron Smith       // explicitly compare with -1.
685146a9eaSAaron Smith       previous_suspend_count = ::ResumeThread(thread_handle);
695146a9eaSAaron Smith 
705146a9eaSAaron Smith       if (previous_suspend_count == (DWORD)-1)
715146a9eaSAaron Smith         return Status(::GetLastError(), eErrorTypeWin32);
725146a9eaSAaron Smith 
735146a9eaSAaron Smith     } while (previous_suspend_count > 1);
745146a9eaSAaron Smith     m_state = eStateRunning;
755146a9eaSAaron Smith   }
765146a9eaSAaron Smith 
775146a9eaSAaron Smith   return Status();
785146a9eaSAaron Smith }
795146a9eaSAaron Smith 
805146a9eaSAaron Smith std::string NativeThreadWindows::GetName() {
815146a9eaSAaron Smith   if (!m_name.empty())
825146a9eaSAaron Smith     return m_name;
835146a9eaSAaron Smith 
845146a9eaSAaron Smith   // Name is not a property of the Windows thread. Create one with the
855146a9eaSAaron Smith   // process's.
865146a9eaSAaron Smith   NativeProcessProtocol &process = GetProcess();
875146a9eaSAaron Smith   ProcessInstanceInfo process_info;
885146a9eaSAaron Smith   if (Host::GetProcessInfo(process.GetID(), process_info)) {
895146a9eaSAaron Smith     std::string process_name(process_info.GetName());
905146a9eaSAaron Smith     m_name = process_name;
915146a9eaSAaron Smith   }
925146a9eaSAaron Smith   return m_name;
935146a9eaSAaron Smith }
945146a9eaSAaron Smith 
955146a9eaSAaron Smith void NativeThreadWindows::SetStopReason(ThreadStopInfo stop_info,
965146a9eaSAaron Smith                                         std::string description) {
975146a9eaSAaron Smith   m_state = eStateStopped;
985146a9eaSAaron Smith   m_stop_info = stop_info;
995146a9eaSAaron Smith   m_stop_description = description;
1005146a9eaSAaron Smith }
1015146a9eaSAaron Smith 
1025146a9eaSAaron Smith bool NativeThreadWindows::GetStopReason(ThreadStopInfo &stop_info,
1035146a9eaSAaron Smith                                         std::string &description) {
1045146a9eaSAaron Smith   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
1055146a9eaSAaron Smith 
1065146a9eaSAaron Smith   switch (m_state) {
1075146a9eaSAaron Smith   case eStateStopped:
1085146a9eaSAaron Smith   case eStateCrashed:
1095146a9eaSAaron Smith   case eStateExited:
1105146a9eaSAaron Smith   case eStateSuspended:
1115146a9eaSAaron Smith   case eStateUnloaded:
1125146a9eaSAaron Smith     stop_info = m_stop_info;
1135146a9eaSAaron Smith     description = m_stop_description;
1145146a9eaSAaron Smith     return true;
1155146a9eaSAaron Smith 
1165146a9eaSAaron Smith   case eStateInvalid:
1175146a9eaSAaron Smith   case eStateConnected:
1185146a9eaSAaron Smith   case eStateAttaching:
1195146a9eaSAaron Smith   case eStateLaunching:
1205146a9eaSAaron Smith   case eStateRunning:
1215146a9eaSAaron Smith   case eStateStepping:
1225146a9eaSAaron Smith   case eStateDetached:
1235146a9eaSAaron Smith     if (log) {
1245146a9eaSAaron Smith       log->Printf("NativeThreadWindows::%s tid %" PRIu64
1255146a9eaSAaron Smith                   " in state %s cannot answer stop reason",
1265146a9eaSAaron Smith                   __FUNCTION__, GetID(), StateAsCString(m_state));
1275146a9eaSAaron Smith     }
1285146a9eaSAaron Smith     return false;
1295146a9eaSAaron Smith   }
1305146a9eaSAaron Smith   llvm_unreachable("unhandled StateType!");
1315146a9eaSAaron Smith }
1325146a9eaSAaron Smith 
1335146a9eaSAaron Smith Status NativeThreadWindows::SetWatchpoint(lldb::addr_t addr, size_t size,
1345146a9eaSAaron Smith                                           uint32_t watch_flags, bool hardware) {
135*5b5274eaSAleksandr Urakov   if (!hardware)
136*5b5274eaSAleksandr Urakov     return Status("not implemented");
137*5b5274eaSAleksandr Urakov   if (m_state == eStateLaunching)
138*5b5274eaSAleksandr Urakov     return Status();
139*5b5274eaSAleksandr Urakov   Status error = RemoveWatchpoint(addr);
140*5b5274eaSAleksandr Urakov   if (error.Fail())
141*5b5274eaSAleksandr Urakov     return error;
142*5b5274eaSAleksandr Urakov   uint32_t wp_index =
143*5b5274eaSAleksandr Urakov       m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags);
144*5b5274eaSAleksandr Urakov   if (wp_index == LLDB_INVALID_INDEX32)
145*5b5274eaSAleksandr Urakov     return Status("Setting hardware watchpoint failed.");
146*5b5274eaSAleksandr Urakov   m_watchpoint_index_map.insert({addr, wp_index});
147*5b5274eaSAleksandr Urakov   return Status();
1485146a9eaSAaron Smith }
1495146a9eaSAaron Smith 
1505146a9eaSAaron Smith Status NativeThreadWindows::RemoveWatchpoint(lldb::addr_t addr) {
151*5b5274eaSAleksandr Urakov   auto wp = m_watchpoint_index_map.find(addr);
152*5b5274eaSAleksandr Urakov   if (wp == m_watchpoint_index_map.end())
153*5b5274eaSAleksandr Urakov     return Status();
154*5b5274eaSAleksandr Urakov   uint32_t wp_index = wp->second;
155*5b5274eaSAleksandr Urakov   m_watchpoint_index_map.erase(wp);
156*5b5274eaSAleksandr Urakov   if (m_reg_context_up->ClearHardwareWatchpoint(wp_index))
157*5b5274eaSAleksandr Urakov     return Status();
158*5b5274eaSAleksandr Urakov   return Status("Clearing hardware watchpoint failed.");
1595146a9eaSAaron Smith }
1605146a9eaSAaron Smith 
1615146a9eaSAaron Smith Status NativeThreadWindows::SetHardwareBreakpoint(lldb::addr_t addr,
1625146a9eaSAaron Smith                                                   size_t size) {
1635146a9eaSAaron Smith   return Status("unimplemented.");
1645146a9eaSAaron Smith }
1655146a9eaSAaron Smith 
1665146a9eaSAaron Smith Status NativeThreadWindows::RemoveHardwareBreakpoint(lldb::addr_t addr) {
1675146a9eaSAaron Smith   return Status("unimplemented.");
1685146a9eaSAaron Smith }
169