forked from OSchip/llvm-project
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.");
|
|
}
|