1 //===-- NativeThreadWindows.cpp -------------------------------------------===// 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 "NativeThreadWindows.h" 10 #include "NativeProcessWindows.h" 11 12 #include "lldb/Host/HostThread.h" 13 #include "lldb/Host/windows/HostThreadWindows.h" 14 #include "lldb/Host/windows/windows.h" 15 #include "lldb/Target/Process.h" 16 #include "lldb/Utility/LLDBLog.h" 17 #include "lldb/Utility/Log.h" 18 #include "lldb/Utility/State.h" 19 20 #include "lldb/lldb-forward.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 NativeThreadWindows::NativeThreadWindows(NativeProcessWindows &process, 26 const HostThread &thread) 27 : NativeThreadProtocol(process, thread.GetNativeThread().GetThreadId()), 28 m_stop_info(), m_stop_description(), m_host_thread(thread) { 29 m_reg_context_up = 30 (NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows( 31 process.GetArchitecture(), *this)); 32 } 33 34 Status NativeThreadWindows::DoStop() { 35 if (m_state != eStateStopped) { 36 DWORD previous_suspend_count = 37 ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle()); 38 if (previous_suspend_count == (DWORD)-1) 39 return Status(::GetLastError(), eErrorTypeWin32); 40 41 m_state = eStateStopped; 42 } 43 return Status(); 44 } 45 46 Status NativeThreadWindows::DoResume(lldb::StateType resume_state) { 47 StateType current_state = GetState(); 48 if (resume_state == current_state) 49 return Status(); 50 51 if (resume_state == eStateStepping) { 52 Log *log = GetLog(LLDBLog::Thread); 53 54 uint32_t flags_index = 55 GetRegisterContext().ConvertRegisterKindToRegisterNumber( 56 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); 57 uint64_t flags_value = 58 GetRegisterContext().ReadRegisterAsUnsigned(flags_index, 0); 59 NativeProcessProtocol &process = GetProcess(); 60 const ArchSpec &arch = process.GetArchitecture(); 61 switch (arch.GetMachine()) { 62 case llvm::Triple::x86: 63 case llvm::Triple::x86_64: 64 flags_value |= 0x100; // Set the trap flag on the CPU 65 break; 66 case llvm::Triple::aarch64: 67 case llvm::Triple::arm: 68 case llvm::Triple::thumb: 69 flags_value |= 0x200000; // The SS bit in PState 70 break; 71 default: 72 LLDB_LOG(log, "single stepping unsupported on this architecture"); 73 break; 74 } 75 GetRegisterContext().WriteRegisterFromUnsigned(flags_index, flags_value); 76 } 77 78 if (resume_state == eStateStepping || resume_state == eStateRunning) { 79 DWORD previous_suspend_count = 0; 80 HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle(); 81 do { 82 // ResumeThread returns -1 on error, or the thread's *previous* suspend 83 // count on success. This means that the return value is 1 when the thread 84 // was restarted. Note that DWORD is an unsigned int, so we need to 85 // explicitly compare with -1. 86 previous_suspend_count = ::ResumeThread(thread_handle); 87 88 if (previous_suspend_count == (DWORD)-1) 89 return Status(::GetLastError(), eErrorTypeWin32); 90 91 } while (previous_suspend_count > 1); 92 m_state = eStateRunning; 93 } 94 95 return Status(); 96 } 97 98 std::string NativeThreadWindows::GetName() { 99 if (!m_name.empty()) 100 return m_name; 101 102 // Name is not a property of the Windows thread. Create one with the 103 // process's. 104 NativeProcessProtocol &process = GetProcess(); 105 ProcessInstanceInfo process_info; 106 if (Host::GetProcessInfo(process.GetID(), process_info)) { 107 std::string process_name(process_info.GetName()); 108 m_name = process_name; 109 } 110 return m_name; 111 } 112 113 void NativeThreadWindows::SetStopReason(ThreadStopInfo stop_info, 114 std::string description) { 115 m_state = eStateStopped; 116 m_stop_info = stop_info; 117 m_stop_description = description; 118 } 119 120 bool NativeThreadWindows::GetStopReason(ThreadStopInfo &stop_info, 121 std::string &description) { 122 Log *log = GetLog(LLDBLog::Thread); 123 124 switch (m_state) { 125 case eStateStopped: 126 case eStateCrashed: 127 case eStateExited: 128 case eStateSuspended: 129 case eStateUnloaded: 130 stop_info = m_stop_info; 131 description = m_stop_description; 132 return true; 133 134 case eStateInvalid: 135 case eStateConnected: 136 case eStateAttaching: 137 case eStateLaunching: 138 case eStateRunning: 139 case eStateStepping: 140 case eStateDetached: 141 if (log) { 142 log->Printf("NativeThreadWindows::%s tid %" PRIu64 143 " in state %s cannot answer stop reason", 144 __FUNCTION__, GetID(), StateAsCString(m_state)); 145 } 146 return false; 147 } 148 llvm_unreachable("unhandled StateType!"); 149 } 150 151 Status NativeThreadWindows::SetWatchpoint(lldb::addr_t addr, size_t size, 152 uint32_t watch_flags, bool hardware) { 153 if (!hardware) 154 return Status::FromErrorString("not implemented"); 155 if (m_state == eStateLaunching) 156 return Status(); 157 Status error = RemoveWatchpoint(addr); 158 if (error.Fail()) 159 return error; 160 uint32_t wp_index = 161 m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags); 162 if (wp_index == LLDB_INVALID_INDEX32) 163 return Status::FromErrorString("Setting hardware watchpoint failed."); 164 m_watchpoint_index_map.insert({addr, wp_index}); 165 return Status(); 166 } 167 168 Status NativeThreadWindows::RemoveWatchpoint(lldb::addr_t addr) { 169 auto wp = m_watchpoint_index_map.find(addr); 170 if (wp == m_watchpoint_index_map.end()) 171 return Status(); 172 uint32_t wp_index = wp->second; 173 m_watchpoint_index_map.erase(wp); 174 if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) 175 return Status(); 176 return Status::FromErrorString("Clearing hardware watchpoint failed."); 177 } 178 179 Status NativeThreadWindows::SetHardwareBreakpoint(lldb::addr_t addr, 180 size_t size) { 181 return Status::FromErrorString("unimplemented."); 182 } 183 184 Status NativeThreadWindows::RemoveHardwareBreakpoint(lldb::addr_t addr) { 185 return Status::FromErrorString("unimplemented."); 186 } 187