180814287SRaphael Isemann //===-- NativeThreadWindows.cpp -------------------------------------------===// 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) { 51*9f34f75fSMartin Storsjö Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 52*9f34f75fSMartin Storsjö 535146a9eaSAaron Smith uint32_t flags_index = 545146a9eaSAaron Smith GetRegisterContext().ConvertRegisterKindToRegisterNumber( 555146a9eaSAaron Smith eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); 565146a9eaSAaron Smith uint64_t flags_value = 575146a9eaSAaron Smith GetRegisterContext().ReadRegisterAsUnsigned(flags_index, 0); 58*9f34f75fSMartin Storsjö NativeProcessProtocol &process = GetProcess(); 59*9f34f75fSMartin Storsjö const ArchSpec &arch = process.GetArchitecture(); 60*9f34f75fSMartin Storsjö switch (arch.GetMachine()) { 61*9f34f75fSMartin Storsjö case llvm::Triple::x86: 62*9f34f75fSMartin Storsjö case llvm::Triple::x86_64: 635146a9eaSAaron Smith flags_value |= 0x100; // Set the trap flag on the CPU 64*9f34f75fSMartin Storsjö break; 65*9f34f75fSMartin Storsjö case llvm::Triple::aarch64: 66*9f34f75fSMartin Storsjö case llvm::Triple::arm: 67*9f34f75fSMartin Storsjö case llvm::Triple::thumb: 68*9f34f75fSMartin Storsjö flags_value |= 0x200000; // The SS bit in PState 69*9f34f75fSMartin Storsjö break; 70*9f34f75fSMartin Storsjö default: 71*9f34f75fSMartin Storsjö LLDB_LOG(log, "single stepping unsupported on this architecture"); 72*9f34f75fSMartin Storsjö break; 73*9f34f75fSMartin Storsjö } 745146a9eaSAaron Smith GetRegisterContext().WriteRegisterFromUnsigned(flags_index, flags_value); 755146a9eaSAaron Smith } 765146a9eaSAaron Smith 775146a9eaSAaron Smith if (resume_state == eStateStepping || resume_state == eStateRunning) { 785146a9eaSAaron Smith DWORD previous_suspend_count = 0; 795146a9eaSAaron Smith HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle(); 805146a9eaSAaron Smith do { 815146a9eaSAaron Smith // ResumeThread returns -1 on error, or the thread's *previous* suspend 825146a9eaSAaron Smith // count on success. This means that the return value is 1 when the thread 835146a9eaSAaron Smith // was restarted. Note that DWORD is an unsigned int, so we need to 845146a9eaSAaron Smith // explicitly compare with -1. 855146a9eaSAaron Smith previous_suspend_count = ::ResumeThread(thread_handle); 865146a9eaSAaron Smith 875146a9eaSAaron Smith if (previous_suspend_count == (DWORD)-1) 885146a9eaSAaron Smith return Status(::GetLastError(), eErrorTypeWin32); 895146a9eaSAaron Smith 905146a9eaSAaron Smith } while (previous_suspend_count > 1); 915146a9eaSAaron Smith m_state = eStateRunning; 925146a9eaSAaron Smith } 935146a9eaSAaron Smith 945146a9eaSAaron Smith return Status(); 955146a9eaSAaron Smith } 965146a9eaSAaron Smith 975146a9eaSAaron Smith std::string NativeThreadWindows::GetName() { 985146a9eaSAaron Smith if (!m_name.empty()) 995146a9eaSAaron Smith return m_name; 1005146a9eaSAaron Smith 1015146a9eaSAaron Smith // Name is not a property of the Windows thread. Create one with the 1025146a9eaSAaron Smith // process's. 1035146a9eaSAaron Smith NativeProcessProtocol &process = GetProcess(); 1045146a9eaSAaron Smith ProcessInstanceInfo process_info; 1055146a9eaSAaron Smith if (Host::GetProcessInfo(process.GetID(), process_info)) { 1065146a9eaSAaron Smith std::string process_name(process_info.GetName()); 1075146a9eaSAaron Smith m_name = process_name; 1085146a9eaSAaron Smith } 1095146a9eaSAaron Smith return m_name; 1105146a9eaSAaron Smith } 1115146a9eaSAaron Smith 1125146a9eaSAaron Smith void NativeThreadWindows::SetStopReason(ThreadStopInfo stop_info, 1135146a9eaSAaron Smith std::string description) { 1145146a9eaSAaron Smith m_state = eStateStopped; 1155146a9eaSAaron Smith m_stop_info = stop_info; 1165146a9eaSAaron Smith m_stop_description = description; 1175146a9eaSAaron Smith } 1185146a9eaSAaron Smith 1195146a9eaSAaron Smith bool NativeThreadWindows::GetStopReason(ThreadStopInfo &stop_info, 1205146a9eaSAaron Smith std::string &description) { 1215146a9eaSAaron Smith Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 1225146a9eaSAaron Smith 1235146a9eaSAaron Smith switch (m_state) { 1245146a9eaSAaron Smith case eStateStopped: 1255146a9eaSAaron Smith case eStateCrashed: 1265146a9eaSAaron Smith case eStateExited: 1275146a9eaSAaron Smith case eStateSuspended: 1285146a9eaSAaron Smith case eStateUnloaded: 1295146a9eaSAaron Smith stop_info = m_stop_info; 1305146a9eaSAaron Smith description = m_stop_description; 1315146a9eaSAaron Smith return true; 1325146a9eaSAaron Smith 1335146a9eaSAaron Smith case eStateInvalid: 1345146a9eaSAaron Smith case eStateConnected: 1355146a9eaSAaron Smith case eStateAttaching: 1365146a9eaSAaron Smith case eStateLaunching: 1375146a9eaSAaron Smith case eStateRunning: 1385146a9eaSAaron Smith case eStateStepping: 1395146a9eaSAaron Smith case eStateDetached: 1405146a9eaSAaron Smith if (log) { 1415146a9eaSAaron Smith log->Printf("NativeThreadWindows::%s tid %" PRIu64 1425146a9eaSAaron Smith " in state %s cannot answer stop reason", 1435146a9eaSAaron Smith __FUNCTION__, GetID(), StateAsCString(m_state)); 1445146a9eaSAaron Smith } 1455146a9eaSAaron Smith return false; 1465146a9eaSAaron Smith } 1475146a9eaSAaron Smith llvm_unreachable("unhandled StateType!"); 1485146a9eaSAaron Smith } 1495146a9eaSAaron Smith 1505146a9eaSAaron Smith Status NativeThreadWindows::SetWatchpoint(lldb::addr_t addr, size_t size, 1515146a9eaSAaron Smith uint32_t watch_flags, bool hardware) { 1525b5274eaSAleksandr Urakov if (!hardware) 1535b5274eaSAleksandr Urakov return Status("not implemented"); 1545b5274eaSAleksandr Urakov if (m_state == eStateLaunching) 1555b5274eaSAleksandr Urakov return Status(); 1565b5274eaSAleksandr Urakov Status error = RemoveWatchpoint(addr); 1575b5274eaSAleksandr Urakov if (error.Fail()) 1585b5274eaSAleksandr Urakov return error; 1595b5274eaSAleksandr Urakov uint32_t wp_index = 1605b5274eaSAleksandr Urakov m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags); 1615b5274eaSAleksandr Urakov if (wp_index == LLDB_INVALID_INDEX32) 1625b5274eaSAleksandr Urakov return Status("Setting hardware watchpoint failed."); 1635b5274eaSAleksandr Urakov m_watchpoint_index_map.insert({addr, wp_index}); 1645b5274eaSAleksandr Urakov return Status(); 1655146a9eaSAaron Smith } 1665146a9eaSAaron Smith 1675146a9eaSAaron Smith Status NativeThreadWindows::RemoveWatchpoint(lldb::addr_t addr) { 1685b5274eaSAleksandr Urakov auto wp = m_watchpoint_index_map.find(addr); 1695b5274eaSAleksandr Urakov if (wp == m_watchpoint_index_map.end()) 1705b5274eaSAleksandr Urakov return Status(); 1715b5274eaSAleksandr Urakov uint32_t wp_index = wp->second; 1725b5274eaSAleksandr Urakov m_watchpoint_index_map.erase(wp); 1735b5274eaSAleksandr Urakov if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) 1745b5274eaSAleksandr Urakov return Status(); 1755b5274eaSAleksandr Urakov return Status("Clearing hardware watchpoint failed."); 1765146a9eaSAaron Smith } 1775146a9eaSAaron Smith 1785146a9eaSAaron Smith Status NativeThreadWindows::SetHardwareBreakpoint(lldb::addr_t addr, 1795146a9eaSAaron Smith size_t size) { 1805146a9eaSAaron Smith return Status("unimplemented."); 1815146a9eaSAaron Smith } 1825146a9eaSAaron Smith 1835146a9eaSAaron Smith Status NativeThreadWindows::RemoveHardwareBreakpoint(lldb::addr_t addr) { 1845146a9eaSAaron Smith return Status("unimplemented."); 1855146a9eaSAaron Smith } 186