diff options
25 files changed, 1230 insertions, 1764 deletions
diff --git a/lldb/cmake/LLDBDependencies.cmake b/lldb/cmake/LLDBDependencies.cmake index f9f61eef071..f78d17729f4 100644 --- a/lldb/cmake/LLDBDependencies.cmake +++ b/lldb/cmake/LLDBDependencies.cmake @@ -90,7 +90,6 @@ set( LLDB_USED_LIBS # Windows-only libraries if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) list(APPEND LLDB_USED_LIBS - lldbPluginProcessWindows lldbPluginProcessWindowsCommon Ws2_32 Rpcrt4 diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp index 3a57daf6919..4ebbc55494c 100644 --- a/lldb/source/API/SystemInitializerFull.cpp +++ b/lldb/source/API/SystemInitializerFull.cpp @@ -108,7 +108,7 @@ #endif #if defined(_MSC_VER) -#include "Plugins/Process/Windows/Live/ProcessWindowsLive.h" +#include "Plugins/Process/Windows/Common/ProcessWindows.h" #include "lldb/Host/windows/windows.h" #endif @@ -333,7 +333,7 @@ void SystemInitializerFull::Initialize() { OCamlLanguage::Initialize(); #if defined(_MSC_VER) - ProcessWindowsLive::Initialize(); + ProcessWindows::Initialize(); #endif #if defined(__FreeBSD__) ProcessFreeBSD::Initialize(); diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index 2a01e527f7c..defa493088b 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -7,7 +7,6 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") - add_subdirectory(Windows/Live) add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_subdirectory(MacOSX-Kernel) diff --git a/lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt b/lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt index 5a53c3c3300..9386ed8a0e4 100644 --- a/lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt @@ -2,9 +2,11 @@ include_directories(.) include_directories(../../Utility) set(PROC_WINDOWS_COMMON_SOURCES - RegisterContextWindows.cpp + DebuggerThread.cpp + LocalDebugDelegate.cpp ProcessWindows.cpp ProcessWindowsLog.cpp + RegisterContextWindows.cpp TargetThreadWindows.cpp ) diff --git a/lldb/source/Plugins/Process/Windows/Live/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp index 5c985bf868d..faaff8bf2b7 100644 --- a/lldb/source/Plugins/Process/Windows/Live/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -1,5 +1,5 @@ //===-- DebuggerThread.DebuggerThread --------------------------------------*- -//C++ -*-===// +// C++ -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lldb/source/Plugins/Process/Windows/Live/DebuggerThread.h b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h index ef4b47bab8c..ef4b47bab8c 100644 --- a/lldb/source/Plugins/Process/Windows/Live/DebuggerThread.h +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h diff --git a/lldb/source/Plugins/Process/Windows/Live/ForwardDecl.h b/lldb/source/Plugins/Process/Windows/Common/ForwardDecl.h index cfe1b79cee1..cfe1b79cee1 100644 --- a/lldb/source/Plugins/Process/Windows/Live/ForwardDecl.h +++ b/lldb/source/Plugins/Process/Windows/Common/ForwardDecl.h diff --git a/lldb/source/Plugins/Process/Windows/Live/IDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h index e88e0ada053..e88e0ada053 100644 --- a/lldb/source/Plugins/Process/Windows/Live/IDebugDelegate.h +++ b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h diff --git a/lldb/source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp index af18999f431..600aef37250 100644 --- a/lldb/source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "LocalDebugDelegate.h" -#include "ProcessWindowsLive.h" +#include "ProcessWindows.h" using namespace lldb; using namespace lldb_private; @@ -17,57 +17,57 @@ LocalDebugDelegate::LocalDebugDelegate(ProcessWP process) : m_process(process) {} void LocalDebugDelegate::OnExitProcess(uint32_t exit_code) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) process->OnExitProcess(exit_code); } void LocalDebugDelegate::OnDebuggerConnected(lldb::addr_t image_base) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) process->OnDebuggerConnected(image_base); } ExceptionResult LocalDebugDelegate::OnDebugException(bool first_chance, const ExceptionRecord &record) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) return process->OnDebugException(first_chance, record); else return ExceptionResult::MaskException; } void LocalDebugDelegate::OnCreateThread(const HostThread &thread) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) process->OnCreateThread(thread); } void LocalDebugDelegate::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) process->OnExitThread(thread_id, exit_code); } void LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) process->OnLoadDll(module_spec, module_addr); } void LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) process->OnUnloadDll(module_addr); } void LocalDebugDelegate::OnDebugString(const std::string &string) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) process->OnDebugString(string); } void LocalDebugDelegate::OnDebuggerError(const Error &error, uint32_t type) { - if (ProcessWindowsLiveSP process = GetProcessPointer()) + if (ProcessWindowsSP process = GetProcessPointer()) process->OnDebuggerError(error, type); } -ProcessWindowsLiveSP LocalDebugDelegate::GetProcessPointer() { +ProcessWindowsSP LocalDebugDelegate::GetProcessPointer() { ProcessSP process = m_process.lock(); - return std::static_pointer_cast<ProcessWindowsLive>(process); + return std::static_pointer_cast<ProcessWindows>(process); } diff --git a/lldb/source/Plugins/Process/Windows/Live/LocalDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h index 17e760c4453..819854a1e63 100644 --- a/lldb/source/Plugins/Process/Windows/Live/LocalDebugDelegate.h +++ b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h @@ -18,19 +18,17 @@ namespace lldb_private { -class ProcessWindowsLive; -typedef std::shared_ptr<ProcessWindowsLive> ProcessWindowsLiveSP; +class ProcessWindows; +typedef std::shared_ptr<ProcessWindows> ProcessWindowsSP; //---------------------------------------------------------------------- // LocalDebugDelegate // -// LocalDebugDelegate creates a connection between a ProcessWindowsLive and the -// debug driver. This serves to decouple ProcessWindowsLive from the debug -// driver. -// It would be possible to get a similar decoupling by just having -// ProcessWindowsLive implement this interface directly. There are two reasons -// why -// we don't do this: +// LocalDebugDelegate creates a connection between a ProcessWindows and the +// debug driver. This serves to decouple ProcessWindows from the debug +// driver. It would be possible to get a similar decoupling by just having +// ProcessWindows implement this interface directly. There are two reasons +// why we don't do this: // // 1) In the future when we add support for local debugging through LLGS, and we // go through the Native*Protocol interface, it is likely we will need the @@ -60,7 +58,7 @@ public: void OnDebuggerError(const Error &error, uint32_t type) override; private: - ProcessWindowsLiveSP GetProcessPointer(); + ProcessWindowsSP GetProcessPointer(); lldb::ProcessWP m_process; }; diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index 62533651d83..50f787f7849 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -9,22 +9,118 @@ #include "ProcessWindows.h" +// Windows includes +#include "lldb/Host/windows/windows.h" +#include <psapi.h> + // Other libraries and framework includes #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Core/State.h" +#include "lldb/Host/HostNativeProcessBase.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/windows/HostThreadWindows.h" #include "lldb/Host/windows/windows.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +#include "DebuggerThread.h" +#include "ExceptionRecord.h" +#include "ForwardDecl.h" +#include "LocalDebugDelegate.h" +#include "ProcessWindowsLog.h" +#include "TargetThreadWindows.h" + using namespace lldb; using namespace lldb_private; +namespace { +std::string GetProcessExecutableName(HANDLE process_handle) { + std::vector<wchar_t> file_name; + DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit + DWORD copied = 0; + do { + file_name_size *= 2; + file_name.resize(file_name_size); + copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(), + file_name_size); + } while (copied >= file_name_size); + file_name.resize(copied); + std::string result; + llvm::convertWideToUTF8(file_name.data(), result); + return result; +} + +std::string GetProcessExecutableName(DWORD pid) { + std::string file_name; + HANDLE process_handle = + ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + if (process_handle != NULL) { + file_name = GetProcessExecutableName(process_handle); + ::CloseHandle(process_handle); + } + return file_name; +} + +} // anonymous namespace + namespace lldb_private { +// We store a pointer to this class in the ProcessWindows, so that we don't +// expose Windows-specific types and implementation details from a public header +// file. +class ProcessWindowsData { +public: + ProcessWindowsData(bool stop_at_entry) : m_stop_at_entry(stop_at_entry) { + m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); + } + + ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); } + + Error m_launch_error; + DebuggerThreadSP m_debugger; + StopInfoSP m_pending_stop_info; + HANDLE m_initial_stop_event = nullptr; + bool m_initial_stop_received = false; + bool m_stop_at_entry; + std::map<lldb::tid_t, HostThread> m_new_threads; + std::set<lldb::tid_t> m_exited_threads; +}; + +ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *) { + return ProcessSP(new ProcessWindows(target_sp, listener_sp)); +} + +void ProcessWindows::Initialize() { + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +void ProcessWindows::Terminate() {} + +lldb_private::ConstString ProcessWindows::GetPluginNameStatic() { + static ConstString g_name("windows"); + return g_name; +} + +const char *ProcessWindows::GetPluginDescriptionStatic() { + return "Process plugin for Windows"; +} + //------------------------------------------------------------------------------ // Constructors and destructors. @@ -53,6 +149,670 @@ size_t ProcessWindows::PutSTDIN(const char *buf, size_t buf_size, //------------------------------------------------------------------------------ // ProcessInterface protocol. +lldb_private::ConstString ProcessWindows::GetPluginName() { + return GetPluginNameStatic(); +} + +uint32_t ProcessWindows::GetPluginVersion() { return 1; } + +Error ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) { + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, + "EnableBreakpointSite called with bp_site 0x%p " + "(id=%d, addr=0x%llx)", + bp_site, bp_site->GetID(), bp_site->GetLoadAddress()); + + Error error = EnableSoftwareBreakpoint(bp_site); + if (!error.Success()) { + WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "EnableBreakpointSite failed. %s", + error.AsCString()); + } + return error; +} + +Error ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) { + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, + "DisableBreakpointSite called with bp_site 0x%p " + "(id=%d, addr=0x%llx)", + bp_site, bp_site->GetID(), bp_site->GetLoadAddress()); + + Error error = DisableSoftwareBreakpoint(bp_site); + + if (!error.Success()) { + WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "DisableBreakpointSite failed. %s", + error.AsCString()); + } + return error; +} + +Error ProcessWindows::DoDetach(bool keep_stopped) { + DebuggerThreadSP debugger_thread; + StateType private_state; + { + // Acquire the lock only long enough to get the DebuggerThread. + // StopDebugging() will trigger a call back into ProcessWindows which + // will also acquire the lock. Thus we have to release the lock before + // calling StopDebugging(). + llvm::sys::ScopedLock lock(m_mutex); + + private_state = GetPrivateState(); + + if (!m_session_data) { + WINWARN_IFALL( + WINDOWS_LOG_PROCESS, + "DoDetach called while state = %u, but there is no active session.", + private_state); + return Error(); + } + + debugger_thread = m_session_data->m_debugger; + } + + Error error; + if (private_state != eStateExited && private_state != eStateDetached) { + WINLOG_IFALL( + WINDOWS_LOG_PROCESS, + "DoDetach called for process %p while state = %d. Detaching...", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), + private_state); + error = debugger_thread->StopDebugging(false); + if (error.Success()) { + SetPrivateState(eStateDetached); + } + + // By the time StopDebugging returns, there is no more debugger thread, so + // we can be assured that no other thread will race for the session data. + m_session_data.reset(); + } else { + WINERR_IFALL( + WINDOWS_LOG_PROCESS, "DoDetach called for process %p while state = " + "%d, but cannot destroy in this state.", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), + private_state); + } + + return error; +} + +Error ProcessWindows::DoLaunch(Module *exe_module, + ProcessLaunchInfo &launch_info) { + // Even though m_session_data is accessed here, it is before a debugger thread + // has been + // kicked off. So there's no race conditions, and it shouldn't be necessary + // to acquire + // the mutex. + + Error result; + if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) { + StreamString stream; + stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can " + "only be used for debug launches.", + launch_info.GetExecutableFile().GetPath().c_str()); + std::string message = stream.GetString(); + result.SetErrorString(message.c_str()); + + WINERR_IFALL(WINDOWS_LOG_PROCESS, "%s", message.c_str()); + return result; + } + + bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); + m_session_data.reset(new ProcessWindowsData(stop_at_entry)); + + SetPrivateState(eStateLaunching); + DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); + m_session_data->m_debugger.reset(new DebuggerThread(delegate)); + DebuggerThreadSP debugger = m_session_data->m_debugger; + + // Kick off the DebugLaunch asynchronously and wait for it to complete. + result = debugger->DebugLaunch(launch_info); + if (result.Fail()) { + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", + launch_info.GetExecutableFile().GetPath().c_str(), + result.AsCString()); + return result; + } + + HostProcess process; + Error error = WaitForDebuggerConnection(debugger, process); + if (error.Fail()) { + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", + launch_info.GetExecutableFile().GetPath().c_str(), + error.AsCString()); + return error; + } + + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'", + launch_info.GetExecutableFile().GetPath().c_str()); + + // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the + // private state + // should already be set to eStateStopped as a result of hitting the initial + // breakpoint. If + // it was not set, the breakpoint should have already been resumed from and + // the private state + // should already be eStateRunning. + launch_info.SetProcessID(process.GetProcessId()); + SetID(process.GetProcessId()); + + return result; +} + +Error ProcessWindows::DoAttachToProcessWithID( + lldb::pid_t pid, const ProcessAttachInfo &attach_info) { + m_session_data.reset( + new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); + + DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); + DebuggerThreadSP debugger(new DebuggerThread(delegate)); + + m_session_data->m_debugger = debugger; + + DWORD process_id = static_cast<DWORD>(pid); + Error error = debugger->DebugAttach(process_id, attach_info); + if (error.Fail()) { + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID encountered an " + "error occurred initiating the " + "asynchronous attach. %s", + error.AsCString()); + return error; + } + + HostProcess process; + error = WaitForDebuggerConnection(debugger, process); + if (error.Fail()) { + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID encountered an " + "error waiting for the debugger to " + "connect. %s", + error.AsCString()); + return error; + } + + WINLOG_IFALL( + WINDOWS_LOG_PROCESS, + "DoAttachToProcessWithID successfully attached to process with pid=%lu", + process_id); + + // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the + // private state + // should already be set to eStateStopped as a result of hitting the initial + // breakpoint. If + // it was not set, the breakpoint should have already been resumed from and + // the private state + // should already be eStateRunning. + SetID(process.GetProcessId()); + return error; +} + +Error ProcessWindows::DoResume() { + llvm::sys::ScopedLock lock(m_mutex); + Error error; + + StateType private_state = GetPrivateState(); + if (private_state == eStateStopped || private_state == eStateCrashed) { + WINLOG_IFALL( + WINDOWS_LOG_PROCESS, + "DoResume called for process %I64u while state is %u. Resuming...", + m_session_data->m_debugger->GetProcess().GetProcessId(), + GetPrivateState()); + + ExceptionRecordSP active_exception = + m_session_data->m_debugger->GetActiveException().lock(); + if (active_exception) { + // Resume the process and continue processing debug events. Mask + // the exception so that from the process's view, there is no + // indication that anything happened. + m_session_data->m_debugger->ContinueAsyncException( + ExceptionResult::MaskException); + } + + WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_THREAD, + "DoResume resuming %u threads.", m_thread_list.GetSize()); + + for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) { + auto thread = std::static_pointer_cast<TargetThreadWindows>( + m_thread_list.GetThreadAtIndex(i)); + thread->DoResume(); + } + + SetPrivateState(eStateRunning); + } else { + WINERR_IFALL( + WINDOWS_LOG_PROCESS, + "DoResume called for process %I64u but state is %u. Returning...", + m_session_data->m_debugger->GetProcess().GetProcessId(), + GetPrivateState()); + } + return error; +} + +Error ProcessWindows::DoDestroy() { + DebuggerThreadSP debugger_thread; + StateType private_state; + { + // Acquire this lock inside an inner scope, only long enough to get the + // DebuggerThread. + // StopDebugging() will trigger a call back into ProcessWindows which will + // acquire the lock + // again, so we need to not deadlock. + llvm::sys::ScopedLock lock(m_mutex); + + private_state = GetPrivateState(); + + if (!m_session_data) { + WINWARN_IFALL( + WINDOWS_LOG_PROCESS, + "DoDestroy called while state = %u, but there is no active session.", + private_state); + return Error(); + } + + debugger_thread = m_session_data->m_debugger; + } + + Error error; + if (private_state != eStateExited && private_state != eStateDetached) { + WINLOG_IFALL( + WINDOWS_LOG_PROCESS, "DoDestroy called for process %p while state = " + "%u. Shutting down...", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), + private_state); + error = debugger_thread->StopDebugging(true); + + // By the time StopDebugging returns, there is no more debugger thread, so + // we can be assured that no other thread will race for the session data. + m_session_data.reset(); + } else { + WINERR_IFALL( + WINDOWS_LOG_PROCESS, "DoDestroy called for process %p while state = " + "%d, but cannot destroy in this state.", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), + private_state); + } + + return error; +} + +Error ProcessWindows::DoHalt(bool &caused_stop) { + Error error; + StateType state = GetPrivateState(); + if (state == eStateStopped) + caused_stop = false; + else { + llvm::sys::ScopedLock lock(m_mutex); + caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess() + .GetNativeProcess() + .GetSystemHandle()); + if (!caused_stop) { + error.SetError(::GetLastError(), eErrorTypeWin32); + WINERR_IFALL( + WINDOWS_LOG_PROCESS, + "DoHalt called DebugBreakProcess, but it failed with error %u", + error.GetError()); + } + } + return error; +} + +void ProcessWindows::DidLaunch() { + ArchSpec arch_spec; + DidAttach(arch_spec); +} + +void ProcessWindows::DidAttach(ArchSpec &arch_spec) { + llvm::sys::ScopedLock lock(m_mutex); + + // The initial stop won't broadcast the state change event, so account for + // that here. + if (m_session_data && GetPrivateState() == eStateStopped && + m_session_data->m_stop_at_entry) + RefreshStateAfterStop(); +} + +void ProcessWindows::RefreshStateAfterStop() { + llvm::sys::ScopedLock lock(m_mutex); + + if (!m_session_data) { + WINWARN_IFALL( + WINDOWS_LOG_PROCESS, + "RefreshStateAfterStop called with no active session. Returning..."); + return; + } + + m_thread_list.RefreshStateAfterStop(); + + std::weak_ptr<ExceptionRecord> exception_record = + m_session_data->m_debugger->GetActiveException(); + ExceptionRecordSP active_exception = exception_record.lock(); + if (!active_exception) { + WINERR_IFALL( + WINDOWS_LOG_PROCESS, + "RefreshStateAfterStop called for process %I64u but there is no " + "active exception. Why is the process stopped?", + m_session_data->m_debugger->GetProcess().GetProcessId()); + return; + } + + StopInfoSP stop_info; + m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID()); + ThreadSP stop_thread = m_thread_list.GetSelectedThread(); + if (!stop_thread) + return; + + switch (active_exception->GetExceptionCode()) { + case EXCEPTION_SINGLE_STEP: { + RegisterContextSP register_context = stop_thread->GetRegisterContext(); + const uint64_t pc = register_context->GetPC(); + BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); + if (site && site->ValidForThisThread(stop_thread.get())) { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION | + WINDOWS_LOG_STEP, + "Single-stepped onto a breakpoint in process %I64u at " + "address 0x%I64x with breakpoint site %d", + m_session_data->m_debugger->GetProcess().GetProcessId(), pc, + site->GetID()); + stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread, + site->GetID()); + stop_thread->SetStopInfo(stop_info); + } else { + WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, + "RefreshStateAfterStop single stepping thread %llu", + stop_thread->GetID()); + stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); + stop_thread->SetStopInfo(stop_info); + } + return; + } + + case EXCEPTION_BREAKPOINT: { + RegisterContextSP register_context = stop_thread->GetRegisterContext(); + + // The current EIP is AFTER the BP opcode, which is one byte. + uint64_t pc = register_context->GetPC() - 1; + + BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); + if (site) { + WINLOG_IFANY( + WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "RefreshStateAfterStop detected breakpoint in process %I64u at " + "address 0x%I64x with breakpoint site %d", + m_session_data->m_debugger->GetProcess().GetProcessId(), pc, + site->GetID()); + + if (site->ValidForThisThread(stop_thread.get())) { + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "Breakpoint site %d is valid for this thread (0x%I64x), " + "creating stop info.", + site->GetID(), stop_thread->GetID()); + + stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( + *stop_thread, site->GetID()); + register_context->SetPC(pc); + } else { + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "Breakpoint site %d is not valid for this thread, " + "creating empty stop info.", + site->GetID()); + } + stop_thread->SetStopInfo(stop_info); + return; + } else { + // The thread hit a hard-coded breakpoint like an `int 3` or + // `__debugbreak()`. + WINLOG_IFALL( + WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "No breakpoint site matches for this thread. __debugbreak()? " + "Creating stop info with the exception."); + // FALLTHROUGH: We'll treat this as a generic exception record in the + // default case. + } + } + + default: { + std::string desc; + llvm::raw_string_ostream desc_stream(desc); + desc_stream << "Exception " + << llvm::format_hex(active_exception->GetExceptionCode(), 8) + << " encountered at address " + << llvm::format_hex(active_exception->GetExceptionAddress(), 8); + stop_info = StopInfo::CreateStopReasonWithException( + *stop_thread, desc_stream.str().c_str()); + stop_thread->SetStopInfo(stop_info); + WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, "%s", desc_stream.str().c_str()); + return; + } + } +} + +bool ProcessWindows::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + if (plugin_specified_by_name) + return true; + + // For now we are just making sure the file exists for a given module + ModuleSP exe_module_sp(target_sp->GetExecutableModule()); + if (exe_module_sp.get()) + return exe_module_sp->GetFileSpec().Exists(); + // However, if there is no executable module, we return true since we might be + // preparing to attach. + return true; +} + +bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + // Add all the threads that were previously running and for which we did not + // detect a thread exited event. + int new_size = 0; + int continued_threads = 0; + int exited_threads = 0; + int new_threads = 0; + + for (ThreadSP old_thread : old_thread_list.Threads()) { + lldb::tid_t old_thread_id = old_thread->GetID(); + auto exited_thread_iter = + m_session_data->m_exited_threads.find(old_thread_id); + if (exited_thread_iter == m_session_data->m_exited_threads.end()) { + new_thread_list.AddThread(old_thread); + ++new_size; + ++continued_threads; + WINLOGV_IFALL( + WINDOWS_LOG_THREAD, + "UpdateThreadList - Thread %llu was running and is still running.", + old_thread_id); + } else { + WINLOGV_IFALL( + WINDOWS_LOG_THREAD, + "UpdateThreadList - Thread %llu was running and has exited.", + old_thread_id); + ++exited_threads; + } + } + + // Also add all the threads that are new since the last time we broke into the + // debugger. + for (const auto &thread_info : m_session_data->m_new_threads) { + ThreadSP thread(new TargetThreadWindows(*this, thread_info.second)); + thread->SetID(thread_info.first); + new_thread_list.AddThread(thread); + ++new_size; + ++new_threads; + WINLOGV_IFALL(WINDOWS_LOG_THREAD, + "UpdateThreadList - Thread %llu is new since last update.", + thread_info.first); + } + + WINLOG_IFALL( + WINDOWS_LOG_THREAD, + "UpdateThreadList - %d new threads, %d old threads, %d exited threads.", + new_threads, continued_threads, exited_threads); + + m_session_data->m_new_threads.clear(); + m_session_data->m_exited_threads.clear(); + + return new_size > 0; +} + +bool ProcessWindows::IsAlive() { + StateType state = GetPrivateState(); + switch (state) { + case eStateCrashed: + case eStateDetached: + case eStateUnloaded: + case eStateExited: + case eStateInvalid: + return false; + default: + return true; + } +} + +size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf, + size_t size, Error &error) { + llvm::sys::ScopedLock lock(m_mutex); + + if (!m_session_data) + return 0; + + WINLOG_IFALL(WINDOWS_LOG_MEMORY, + "DoReadMemory attempting to read %u bytes from address 0x%I64x", + size, vm_addr); + + HostProcess process = m_session_data->m_debugger->GetProcess(); + void *addr = reinterpret_cast<void *>(vm_addr); + SIZE_T bytes_read = 0; + if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, + buf, size, &bytes_read)) { + error.SetError(GetLastError(), eErrorTypeWin32); + WINERR_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory failed with error code %u", + error.GetError()); + } + return bytes_read; +} + +size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, + size_t size, Error &error) { + llvm::sys::ScopedLock lock(m_mutex); + WINLOG_IFALL( + WINDOWS_LOG_MEMORY, + "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, + vm_addr); + + if (!m_session_data) { + WINERR_IFANY( + WINDOWS_LOG_MEMORY, + "DoWriteMemory cannot write, there is no active debugger connection."); + return 0; + } + + HostProcess process = m_session_data->m_debugger->GetProcess(); + void *addr = reinterpret_cast<void *>(vm_addr); + SIZE_T bytes_written = 0; + lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); + if (WriteProcessMemory(handle, addr, buf, size, &bytes_written)) + FlushInstructionCache(handle, addr, bytes_written); + else { + error.SetError(GetLastError(), eErrorTypeWin32); + WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory failed with error code %u", + error.GetError()); + } + return bytes_written; +} + +#define BOOL_STR(b) ((b) ? "true" : "false") + +Error ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, + MemoryRegionInfo &info) { + Error error; + llvm::sys::ScopedLock lock(m_mutex); + info.Clear(); + + if (!m_session_data) { + error.SetErrorString( + "GetMemoryRegionInfo called with no debugging session."); + WINERR_IFALL(WINDOWS_LOG_MEMORY, "%s", error.AsCString()); + return error; + } + HostProcess process = m_session_data->m_debugger->GetProcess(); + lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); + if (handle == nullptr || handle == LLDB_INVALID_PROCESS) { + error.SetErrorString( + "GetMemoryRegionInfo called with an invalid target process."); + WINERR_IFALL(WINDOWS_LOG_MEMORY, "%s", error.AsCString()); + return error; + } + + WINLOG_IFALL(WINDOWS_LOG_MEMORY, + "GetMemoryRegionInfo getting info for address 0x%I64x", vm_addr); + + void *addr = reinterpret_cast<void *>(vm_addr); + MEMORY_BASIC_INFORMATION mem_info = {}; + SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); + if (result == 0) { + if (::GetLastError() == ERROR_INVALID_PARAMETER) { + // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with an + // address + // past the highest accessible address. We should return a range from the + // vm_addr + // to LLDB_INVALID_ADDRESS + info.GetRange().SetRangeBase(vm_addr); + info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); + info.SetReadable(MemoryRegionInfo::eNo); + info.SetExecutable(MemoryRegionInfo::eNo); + info.SetWritable(MemoryRegionInfo::eNo); + info.SetMapped(MemoryRegionInfo::eNo); + return error; + } else { + error.SetError(::GetLastError(), eErrorTypeWin32); + WINERR_IFALL(WINDOWS_LOG_MEMORY, "VirtualQueryEx returned error %u while " + "getting memory region info for address " + "0x%I64x", + error.GetError(), vm_addr); + return error; + } + } + + // Protect bits are only valid for MEM_COMMIT regions. + if (mem_info.State == MEM_COMMIT) { + const bool readable = IsPageReadable(mem_info.Protect); + const bool executable = IsPageExecutable(mem_info.Protect); + const bool writable = IsPageWritable(mem_info.Protect); + info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); + info.SetExecutable(executable ? MemoryRegionInfo::eYes + : MemoryRegionInfo::eNo); + info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); + } else { + info.SetReadable(MemoryRegionInfo::eNo); + info.SetExecutable(MemoryRegionInfo::eNo); + info.SetWritable(MemoryRegionInfo::eNo); + } + + // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE. + if (mem_info.State != MEM_FREE) { + info.GetRange().SetRangeBase( + reinterpret_cast<addr_t>(mem_info.AllocationBase)); + info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) + + mem_info.RegionSize); + info.SetMapped(MemoryRegionInfo::eYes); + } else { + // In the unmapped case we need to return the distance to the next block of + // memory. + // VirtualQueryEx nearly does that except that it gives the distance from + // the start + // of the page containing vm_addr. + SYSTEM_INFO data; + GetSystemInfo(&data); + DWORD page_offset = vm_addr % data.dwPageSize; + info.GetRange().SetRangeBase(vm_addr); + info.GetRange().SetByteSize(mem_info.RegionSize - page_offset); + info.SetMapped(MemoryRegionInfo::eNo); + } + + error.SetError(::GetLastError(), eErrorTypeWin32); + WINLOGV_IFALL(WINDOWS_LOG_MEMORY, "Memory region info for address %llu: " + "readable=%s, executable=%s, writable=%s", + vm_addr, BOOL_STR(info.GetReadable()), + BOOL_STR(info.GetExecutable()), BOOL_STR(info.GetWritable())); + return error; +} + lldb::addr_t ProcessWindows::GetImageInfoAddress() { Target &target = GetTarget(); ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile(); @@ -63,12 +823,239 @@ lldb::addr_t ProcessWindows::GetImageInfoAddress() { return LLDB_INVALID_ADDRESS; } +void ProcessWindows::OnExitProcess(uint32_t exit_code) { + // No need to acquire the lock since m_session_data isn't accessed. + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Process %llu exited with code %u", GetID(), + exit_code); + + TargetSP target = m_target_sp.lock(); + if (target) { + ModuleSP executable_module = target->GetExecutableModule(); + ModuleList unloaded_modules; + unloaded_modules.Append(executable_module); + target->ModulesDidUnload(unloaded_modules, true); + } + + SetProcessExitStatus(GetID(), true, 0, exit_code); + SetPrivateState(eStateExited); +} + +void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { + DebuggerThreadSP debugger = m_session_data->m_debugger; + + WINLOG_IFALL(WINDOWS_LOG_PROCESS, + "Debugger connected to process %I64u. Image base = 0x%I64x", + debugger->GetProcess().GetProcessId(), image_base); + + ModuleSP module = GetTarget().GetExecutableModule(); + if (!module) { + // During attach, we won't have the executable module, so find it now. + const DWORD pid = debugger->GetProcess().GetProcessId(); + const std::string file_name = GetProcessExecutableName(pid); + if (file_name.empty()) { + return; + } + + FileSpec executable_file(file_name, true); + ModuleSpec module_spec(executable_file); + Error error; + module = GetTarget().GetSharedModule(module_spec, &error); + if (!module) { + return; + } + + GetTarget().SetExecutableModule(module, false); + } + + bool load_addr_changed; + module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed); + + ModuleList loaded_modules; + loaded_modules.Append(module); + GetTarget().ModulesDidLoad(loaded_modules); + + // Add the main executable module to the list of pending module loads. We + // can't call + // GetTarget().ModulesDidLoad() here because we still haven't returned from + // DoLaunch() / DoAttach() yet + // so the target may not have set the process instance to `this` yet. + llvm::sys::ScopedLock lock(m_mutex); + const HostThreadWindows &wmain_thread = + debugger->GetMainThread().GetNativeThread(); + m_session_data->m_new_threads[wmain_thread.GetThreadId()] = + debugger->GetMainThread(); +} + +ExceptionResult +ProcessWindows::OnDebugException(bool first_chance, + const ExceptionRecord &record) { + llvm::sys::ScopedLock lock(m_mutex); + + // FIXME: Without this check, occasionally when running the test suite there + // is + // an issue where m_session_data can be null. It's not clear how this could + // happen + // but it only surfaces while running the test suite. In order to properly + // diagnose + // this, we probably need to first figure allow the test suite to print out + // full + // lldb logs, and then add logging to the process plugin. + if (!m_session_data) { + WINERR_IFANY(WINDOWS_LOG_EXCEPTION, "Debugger thread reported exception " + "0x%lx at address 0x%llu, but there is " + "no session.", + record.GetExceptionCode(), record.GetExceptionAddress()); + return ExceptionResult::SendToApplication; + } + + if (!first_chance) { + // Any second chance exception is an application crash by definition. + SetPrivateState(eStateCrashed); + } + + ExceptionResult result = ExceptionResult::SendToApplication; + switch (record.GetExceptionCode()) { + case EXCEPTION_BREAKPOINT: + // Handle breakpoints at the first chance. + result = ExceptionResult::BreakInDebugger; + + if (!m_session_data->m_initial_stop_received) { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, "Hit loader breakpoint at address " + "0x%I64x, setting initial stop " + "event.", + record.GetExceptionAddress()); + m_session_data->m_initial_stop_received = true; + ::SetEvent(m_session_data->m_initial_stop_event); + } else { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, + "Hit non-loader breakpoint at address 0x%I64x.", + record.GetExceptionAddress()); + } + SetPrivateState(eStateStopped); + break; + case EXCEPTION_SINGLE_STEP: + result = ExceptionResult::BreakInDebugger; + SetPrivateState(eStateStopped); + break; + default: + WINLOG_IFANY(WINDOWS_LOG_EXCEPTION, "Debugger thread reported exception " + "0x%lx at address 0x%llx " + "(first_chance=%s)", + record.GetExceptionCode(), record.GetExceptionAddress(), + BOOL_STR(first_chance)); + // For non-breakpoints, give the application a chance to handle the + // exception first. + if (first_chance) + result = ExceptionResult::SendToApplication; + else + result = ExceptionResult::BreakInDebugger; + } + + return result; +} + +void ProcessWindows::OnCreateThread(const HostThread &new_thread) { + llvm::sys::ScopedLock lock(m_mutex); + const HostThreadWindows &wnew_thread = new_thread.GetNativeThread(); + m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread; +} + +void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { + llvm::sys::ScopedLock lock(m_mutex); + + // On a forced termination, we may get exit thread events after the session + // data has been cleaned up. + if (!m_session_data) + return; + + // A thread may have started and exited before the debugger stopped allowing a + // refresh. + // Just remove it from the new threads list in that case. + auto iter = m_session_data->m_new_threads.find(thread_id); + if (iter != m_session_data->m_new_threads.end()) + m_session_data->m_new_threads.erase(iter); + else + m_session_data->m_exited_threads.insert(thread_id); +} + +void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec, + lldb::addr_t module_addr) { + // Confusingly, there is no Target::AddSharedModule. Instead, calling + // GetSharedModule() with + // a new module will add it to the module list and return a corresponding + // ModuleSP. + Error error; + ModuleSP module = GetTarget().GetSharedModule(module_spec, &error); + bool load_addr_changed = false; + module->SetLoadAddress(GetTarget(), module_addr, false, load_addr_changed); + + ModuleList loaded_modules; + loaded_modules.Append(module); + GetTarget().ModulesDidLoad(loaded_modules); +} + +void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { + Address resolved_addr; + if (GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) { + ModuleSP module = resolved_addr.GetModule(); + if (module) { + ModuleList unloaded_modules; + unloaded_modules.Append(module); + GetTarget().ModulesDidUnload(unloaded_modules, false); + } + } +} + +void ProcessWindows::OnDebugString(const std::string &string) {} + +void ProcessWindows::OnDebuggerError(const Error &error, uint32_t type) { + llvm::sys::ScopedLock lock(m_mutex); + + if (m_session_data->m_initial_stop_received) { + // This happened while debugging. Do we shutdown the debugging session, try + // to continue, + // or do something else? + WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred during debugging. " + "Unexpected behavior may result. %s", + error.GetError(), error.AsCString()); + } else { + // If we haven't actually launched the process yet, this was an error + // launching the + // process. Set the internal error and signal the initial stop event so + // that the DoLaunch + // method wakes up and returns a failure. + m_session_data->m_launch_error = error; + ::SetEvent(m_session_data->m_initial_stop_event); + WINERR_IFALL( + WINDOWS_LOG_PROCESS, + "Error %u occurred launching the process before the initial stop. %s", + error.GetError(), error.AsCString()); + return; + } +} + +Error ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger, + HostProcess &process) { + Error result; + WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_BREAKPOINTS, + "WaitForDebuggerConnection Waiting for loader breakpoint."); + + // Block this function until we receive the initial stop from the process. + if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == + WAIT_OBJECT_0) { + WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_BREAKPOINTS, + "WaitForDebuggerConnection hit loader breakpoint, returning."); + + process = debugger->GetProcess(); + return m_session_data->m_launch_error; + } else + return Error(::GetLastError(), eErrorTypeWin32); +} + // The Windows page protection bits are NOT independent masks that can be -// bitwise-ORed -// together. For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE | PAGE_READ). -// To test for an access type, it's necessary to test for any of the bits that -// provide -// that access type. +// bitwise-ORed together. For example, PAGE_EXECUTE_READ is not +// (PAGE_EXECUTE | PAGE_READ). To test for an access type, it's necessary to +// test for any of the bits that provide that access type. bool ProcessWindows::IsPageReadable(uint32_t protect) { return (protect & PAGE_NOACCESS) == 0; } @@ -82,4 +1069,5 @@ bool ProcessWindows::IsPageExecutable(uint32_t protect) { return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0; } -} + +} // namespace lldb_private diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h index bf96180488c..fac06c46b2b 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -15,33 +15,104 @@ #include "lldb/Target/Process.h" #include "lldb/lldb-forward.h" +#include "llvm/Support/Mutex.h" + +#include "IDebugDelegate.h" + namespace lldb_private { -class ProcessWindows : public lldb_private::Process { +class HostProcess; +class ProcessWindowsData; + +class ProcessWindows : public Process, public IDebugDelegate { public: //------------------------------------------------------------------ + // Static functions. + //------------------------------------------------------------------ + static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *); + + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + //------------------------------------------------------------------ // Constructors and destructors //------------------------------------------------------------------ ProcessWindows(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); ~ProcessWindows(); - size_t GetSTDOUT(char *buf, size_t buf_size, - lldb_private::Error &error) override; - size_t GetSTDERR(char *buf, size_t buf_size, - lldb_private::Error &error) override; - size_t PutSTDIN(const char *buf, size_t buf_size, - lldb_private::Error &error) override; + size_t GetSTDOUT(char *buf, size_t buf_size, Error &error) override; + size_t GetSTDERR(char *buf, size_t buf_size, Error &error) override; + size_t PutSTDIN(const char *buf, size_t buf_size, Error &error) override; + + // lldb_private::Process overrides + ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; + + Error EnableBreakpointSite(BreakpointSite *bp_site) override; + Error DisableBreakpointSite(BreakpointSite *bp_site) override; + + Error DoDetach(bool keep_stopped) override; + Error DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override; + Error DoAttachToProcessWithID( + lldb::pid_t pid, + const lldb_private::ProcessAttachInfo &attach_info) override; + Error DoResume() override; + Error DoDestroy() override; + Error DoHalt(bool &caused_stop) override; + + void DidLaunch() override; + void DidAttach(lldb_private::ArchSpec &arch_spec) override; + + void RefreshStateAfterStop() override; + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + bool DestroyRequiresHalt() override { return false; } + bool UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; + bool IsAlive() override; + + size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Error &error) override; + size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, + Error &error) override; + Error GetMemoryRegionInfo(lldb::addr_t vm_addr, + MemoryRegionInfo &info) override; lldb::addr_t GetImageInfoAddress() override; -protected: + // IDebugDelegate overrides. + void OnExitProcess(uint32_t exit_code) override; + void OnDebuggerConnected(lldb::addr_t image_base) override; + ExceptionResult OnDebugException(bool first_chance, + const ExceptionRecord &record) override; + void OnCreateThread(const HostThread &thread) override; + void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; + void OnLoadDll(const ModuleSpec &module_spec, + lldb::addr_t module_addr) override; + void OnUnloadDll(lldb::addr_t module_addr) override; + void OnDebugString(const std::string &string) override; + void OnDebuggerError(const Error &error, uint32_t type) override; + +private: + Error WaitForDebuggerConnection(DebuggerThreadSP debugger, + HostProcess &process); + // These decode the page protection bits. static bool IsPageReadable(uint32_t protect); - static bool IsPageWritable(uint32_t protect); - static bool IsPageExecutable(uint32_t protect); + + llvm::sys::Mutex m_mutex; + std::unique_ptr<ProcessWindowsData> m_session_data; }; } diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp index fe05f3068bb..60b3987d9cf 100644 --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -21,6 +21,12 @@ #include "TargetThreadWindows.h" #include "UnwindLLDB.h" +#if defined(_WIN64) +#include "x86/RegisterContextWindows_x64.h" +#else +#include "x86/RegisterContextWindows_x86.h" +#endif + using namespace lldb; using namespace lldb_private; @@ -41,6 +47,44 @@ void TargetThreadWindows::WillResume(lldb::StateType resume_state) {} void TargetThreadWindows::DidStop() {} +RegisterContextSP TargetThreadWindows::GetRegisterContext() { + if (!m_reg_context_sp) + m_reg_context_sp = CreateRegisterContextForFrameIndex(0); + + return m_reg_context_sp; +} + +RegisterContextSP +TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) { + return CreateRegisterContextForFrameIndex(frame->GetConcreteFrameIndex()); +} + +RegisterContextSP +TargetThreadWindows::CreateRegisterContextForFrameIndex(uint32_t idx) { + if (!m_reg_context_sp) { + ArchSpec arch = HostInfo::GetArchitecture(); + switch (arch.GetMachine()) { + case llvm::Triple::x86: +#if defined(_WIN64) +// FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64 +#else + m_reg_context_sp.reset(new RegisterContextWindows_x86(*this, idx)); +#endif + break; + case llvm::Triple::x86_64: +#if defined(_WIN64) + m_reg_context_sp.reset(new RegisterContextWindows_x64(*this, idx)); +#else +// LLDB is 32-bit, but the target process is 64-bit. We probably can't debug +// this. +#endif + default: + break; + } + } + return m_reg_context_sp; +} + bool TargetThreadWindows::CalculateStopInfo() { SetStopInfo(m_stop_info_sp); return true; diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h index ea6d636dbab..8b4e3dfdda4 100644 --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h @@ -15,6 +15,8 @@ #include "lldb/Target/Thread.h" #include "lldb/lldb-forward.h" +#include "RegisterContextWindows.h" + namespace lldb_private { class ProcessWindows; class HostThread; @@ -29,6 +31,9 @@ public: void RefreshStateAfterStop() override; void WillResume(lldb::StateType resume_state) override; void DidStop() override; + lldb::RegisterContextSP GetRegisterContext() override; + lldb::RegisterContextSP + CreateRegisterContextForFrame(StackFrame *frame) override; bool CalculateStopInfo() override; Unwind *GetUnwinder() override; @@ -37,6 +42,8 @@ public: HostThread GetHostThread() const { return m_host_thread; } private: + lldb::RegisterContextSP CreateRegisterContextForFrameIndex(uint32_t idx); + HostThread m_host_thread; }; } diff --git a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp index b379322f3d9..2938f77f3c2 100644 --- a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp @@ -16,6 +16,7 @@ #include "ProcessWindowsLog.h" #include "RegisterContextWindows_x86.h" #include "RegisterContext_x86.h" +#include "TargetThreadWindows.h" #include "lldb-x86-register-enums.h" #include "llvm/ADT/STLExtras.h" @@ -208,6 +209,80 @@ bool RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, return false; } +bool RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) { + // Since we cannot only write a single register value to the inferior, we need + // to make sure + // our cached copy of the register values are fresh. Otherwise when writing + // EAX, for example, + // we may also overwrite some other register with a stale value. + if (!CacheAllRegisterValues()) + return false; + + uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + switch (reg) { + case lldb_eax_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EAX", + reg_value.GetAsUInt32()); + m_context.Eax = reg_value.GetAsUInt32(); + break; + case lldb_ebx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBX", + reg_value.GetAsUInt32()); + m_context.Ebx = reg_value.GetAsUInt32(); + break; + case lldb_ecx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ECX", + reg_value.GetAsUInt32()); + m_context.Ecx = reg_value.GetAsUInt32(); + break; + case lldb_edx_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDX", + reg_value.GetAsUInt32()); + m_context.Edx = reg_value.GetAsUInt32(); + break; + case lldb_edi_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDI", + reg_value.GetAsUInt32()); + m_context.Edi = reg_value.GetAsUInt32(); + break; + case lldb_esi_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESI", + reg_value.GetAsUInt32()); + m_context.Esi = reg_value.GetAsUInt32(); + break; + case lldb_ebp_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBP", + reg_value.GetAsUInt32()); + m_context.Ebp = reg_value.GetAsUInt32(); + break; + case lldb_esp_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESP", + reg_value.GetAsUInt32()); + m_context.Esp = reg_value.GetAsUInt32(); + break; + case lldb_eip_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EIP", + reg_value.GetAsUInt32()); + m_context.Eip = reg_value.GetAsUInt32(); + break; + case lldb_eflags_i386: + WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EFLAGS", + reg_value.GetAsUInt32()); + m_context.EFlags = reg_value.GetAsUInt32(); + break; + default: + WINWARN_IFALL(WINDOWS_LOG_REGISTERS, + "Write value 0x%x to unknown register %u", + reg_value.GetAsUInt32(), reg); + } + + // Physically update the registers in the target process. + TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); + return ::SetThreadContext( + wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); +} + bool RegisterContextWindows_x86::ReadRegisterHelper( DWORD flags_required, const char *reg_name, DWORD value, RegisterValue ®_value) const { diff --git a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h index 1e3910b5edd..aae645fdb5a 100644 --- a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h +++ b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h @@ -40,6 +40,9 @@ public: bool ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) override; + bool WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + private: bool ReadRegisterHelper(DWORD flags_required, const char *reg_name, DWORD value, RegisterValue ®_value) const; diff --git a/lldb/source/Plugins/Process/Windows/Live/CMakeLists.txt b/lldb/source/Plugins/Process/Windows/Live/CMakeLists.txt deleted file mode 100644 index bdb680ad0be..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -include_directories(.) -include_directories(../../Utility) -include_directories(../Common) - -set(PROC_WINDOWS_SOURCES - DebuggerThread.cpp - LocalDebugDelegate.cpp - ProcessWindowsLive.cpp - TargetThreadWindowsLive.cpp - ) - -if (CMAKE_SIZEOF_VOID_P EQUAL 4) - set(PROC_WINDOWS_SOURCES ${PROC_WINDOWS_SOURCES} - x86/RegisterContextWindowsLive_x86.cpp - ) -elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) - set(PROC_WINDOWS_SOURCES ${PROC_WINDOWS_SOURCES} - x64/RegisterContextWindowsLive_x64.cpp - ) -endif() - -add_lldb_library(lldbPluginProcessWindows - ${PROC_WINDOWS_SOURCES} - ) diff --git a/lldb/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp b/lldb/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp deleted file mode 100644 index 7ddc5866a5f..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp +++ /dev/null @@ -1,1045 +0,0 @@ -//===-- ProcessWindowsLive.cpp ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// Windows includes -#include "lldb/Host/windows/windows.h" -#include <psapi.h> - -// C++ Includes -#include <list> -#include <mutex> -#include <set> -#include <vector> - -// Other libraries and framework includes -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/Section.h" -#include "lldb/Core/State.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostNativeProcessBase.h" -#include "lldb/Host/HostNativeThreadBase.h" -#include "lldb/Host/HostProcess.h" -#include "lldb/Host/MonitoringProcessLauncher.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/ProcessLauncherWindows.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Target/FileAction.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" - -#include "Plugins/Process/Windows/Common/ProcessWindowsLog.h" - -#include "DebuggerThread.h" -#include "ExceptionRecord.h" -#include "LocalDebugDelegate.h" -#include "ProcessWindowsLive.h" -#include "TargetThreadWindowsLive.h" - -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lldb; -using namespace lldb_private; - -#define BOOL_STR(b) ((b) ? "true" : "false") - -namespace { - -std::string GetProcessExecutableName(HANDLE process_handle) { - std::vector<wchar_t> file_name; - DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit - DWORD copied = 0; - do { - file_name_size *= 2; - file_name.resize(file_name_size); - copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(), - file_name_size); - } while (copied >= file_name_size); - file_name.resize(copied); - std::string result; - llvm::convertWideToUTF8(file_name.data(), result); - return result; -} - -std::string GetProcessExecutableName(DWORD pid) { - std::string file_name; - HANDLE process_handle = - ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); - if (process_handle != NULL) { - file_name = GetProcessExecutableName(process_handle); - ::CloseHandle(process_handle); - } - return file_name; -} - -} // anonymous namespace - -namespace lldb_private { - -// We store a pointer to this class in the ProcessWindows, so that we don't -// expose Windows -// OS specific types and implementation details from a public header file. -class ProcessWindowsData { -public: - ProcessWindowsData(bool stop_at_entry) : m_stop_at_entry(stop_at_entry) { - m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); - } - - ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); } - - lldb_private::Error m_launch_error; - lldb_private::DebuggerThreadSP m_debugger; - StopInfoSP m_pending_stop_info; - HANDLE m_initial_stop_event = nullptr; - bool m_initial_stop_received = false; - bool m_stop_at_entry; - std::map<lldb::tid_t, HostThread> m_new_threads; - std::set<lldb::tid_t> m_exited_threads; -}; -} -//------------------------------------------------------------------------------ -// Static functions. - -ProcessSP ProcessWindowsLive::CreateInstance(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - const FileSpec *) { - return ProcessSP(new ProcessWindowsLive(target_sp, listener_sp)); -} - -void ProcessWindowsLive::Initialize() { - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, []() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), CreateInstance); - }); -} - -//------------------------------------------------------------------------------ -// Constructors and destructors. - -ProcessWindowsLive::ProcessWindowsLive(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp) - : lldb_private::ProcessWindows(target_sp, listener_sp) {} - -ProcessWindowsLive::~ProcessWindowsLive() {} - -void ProcessWindowsLive::Terminate() {} - -lldb_private::ConstString ProcessWindowsLive::GetPluginNameStatic() { - static ConstString g_name("windows"); - return g_name; -} - -const char *ProcessWindowsLive::GetPluginDescriptionStatic() { - return "Process plugin for Windows"; -} - -Error ProcessWindowsLive::EnableBreakpointSite(BreakpointSite *bp_site) { - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, - "EnableBreakpointSite called with bp_site 0x%p " - "(id=%d, addr=0x%llx)", - bp_site, bp_site->GetID(), bp_site->GetLoadAddress()); - - Error error = EnableSoftwareBreakpoint(bp_site); - if (!error.Success()) { - WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "EnableBreakpointSite failed. %s", - error.AsCString()); - } - return error; -} - -Error ProcessWindowsLive::DisableBreakpointSite(BreakpointSite *bp_site) { - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, - "DisableBreakpointSite called with bp_site 0x%p " - "(id=%d, addr=0x%llx)", - bp_site, bp_site->GetID(), bp_site->GetLoadAddress()); - - Error error = DisableSoftwareBreakpoint(bp_site); - - if (!error.Success()) { - WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "DisableBreakpointSite failed. %s", - error.AsCString()); - } - return error; -} - -bool ProcessWindowsLive::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { - // Add all the threads that were previously running and for which we did not - // detect a thread - // exited event. - int new_size = 0; - int continued_threads = 0; - int exited_threads = 0; - int new_threads = 0; - - for (ThreadSP old_thread : old_thread_list.Threads()) { - lldb::tid_t old_thread_id = old_thread->GetID(); - auto exited_thread_iter = - m_session_data->m_exited_threads.find(old_thread_id); - if (exited_thread_iter == m_session_data->m_exited_threads.end()) { - new_thread_list.AddThread(old_thread); - ++new_size; - ++continued_threads; - WINLOGV_IFALL( - WINDOWS_LOG_THREAD, - "UpdateThreadList - Thread %llu was running and is still running.", - old_thread_id); - } else { - WINLOGV_IFALL( - WINDOWS_LOG_THREAD, - "UpdateThreadList - Thread %llu was running and has exited.", - old_thread_id); - ++exited_threads; - } - } - - // Also add all the threads that are new since the last time we broke into the - // debugger. - for (const auto &thread_info : m_session_data->m_new_threads) { - ThreadSP thread(new TargetThreadWindowsLive(*this, thread_info.second)); - thread->SetID(thread_info.first); - new_thread_list.AddThread(thread); - ++new_size; - ++new_threads; - WINLOGV_IFALL(WINDOWS_LOG_THREAD, - "UpdateThreadList - Thread %llu is new since last update.", - thread_info.first); - } - - WINLOG_IFALL( - WINDOWS_LOG_THREAD, - "UpdateThreadList - %d new threads, %d old threads, %d exited threads.", - new_threads, continued_threads, exited_threads); - - m_session_data->m_new_threads.clear(); - m_session_data->m_exited_threads.clear(); - - return new_size > 0; -} - -Error ProcessWindowsLive::DoLaunch(Module *exe_module, - ProcessLaunchInfo &launch_info) { - // Even though m_session_data is accessed here, it is before a debugger thread - // has been - // kicked off. So there's no race conditions, and it shouldn't be necessary - // to acquire - // the mutex. - - Error result; - if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) { - StreamString stream; - stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can " - "only be used for debug launches.", - launch_info.GetExecutableFile().GetPath().c_str()); - std::string message = stream.GetString(); - result.SetErrorString(message.c_str()); - - WINERR_IFALL(WINDOWS_LOG_PROCESS, "%s", message.c_str()); - return result; - } - - bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); - m_session_data.reset(new ProcessWindowsData(stop_at_entry)); - - SetPrivateState(eStateLaunching); - DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - m_session_data->m_debugger.reset(new DebuggerThread(delegate)); - DebuggerThreadSP debugger = m_session_data->m_debugger; - - // Kick off the DebugLaunch asynchronously and wait for it to complete. - result = debugger->DebugLaunch(launch_info); - if (result.Fail()) { - WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", - launch_info.GetExecutableFile().GetPath().c_str(), - result.AsCString()); - return result; - } - - HostProcess process; - Error error = WaitForDebuggerConnection(debugger, process); - if (error.Fail()) { - WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", - launch_info.GetExecutableFile().GetPath().c_str(), - error.AsCString()); - return error; - } - - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'", - launch_info.GetExecutableFile().GetPath().c_str()); - - // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the - // private state - // should already be set to eStateStopped as a result of hitting the initial - // breakpoint. If - // it was not set, the breakpoint should have already been resumed from and - // the private state - // should already be eStateRunning. - launch_info.SetProcessID(process.GetProcessId()); - SetID(process.GetProcessId()); - - return result; -} - -Error ProcessWindowsLive::DoAttachToProcessWithID( - lldb::pid_t pid, const ProcessAttachInfo &attach_info) { - m_session_data.reset( - new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); - - DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - DebuggerThreadSP debugger(new DebuggerThread(delegate)); - - m_session_data->m_debugger = debugger; - - DWORD process_id = static_cast<DWORD>(pid); - Error error = debugger->DebugAttach(process_id, attach_info); - if (error.Fail()) { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID encountered an " - "error occurred initiating the " - "asynchronous attach. %s", - error.AsCString()); - return error; - } - - HostProcess process; - error = WaitForDebuggerConnection(debugger, process); - if (error.Fail()) { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID encountered an " - "error waiting for the debugger to " - "connect. %s", - error.AsCString()); - return error; - } - - WINLOG_IFALL( - WINDOWS_LOG_PROCESS, - "DoAttachToProcessWithID successfully attached to process with pid=%lu", - process_id); - - // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the - // private state - // should already be set to eStateStopped as a result of hitting the initial - // breakpoint. If - // it was not set, the breakpoint should have already been resumed from and - // the private state - // should already be eStateRunning. - SetID(process.GetProcessId()); - return error; -} - -Error ProcessWindowsLive::WaitForDebuggerConnection(DebuggerThreadSP debugger, - HostProcess &process) { - Error result; - WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_BREAKPOINTS, - "WaitForDebuggerConnection Waiting for loader breakpoint."); - - // Block this function until we receive the initial stop from the process. - if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == - WAIT_OBJECT_0) { - WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_BREAKPOINTS, - "WaitForDebuggerConnection hit loader breakpoint, returning."); - - process = debugger->GetProcess(); - return m_session_data->m_launch_error; - } else - return Error(::GetLastError(), eErrorTypeWin32); -} - -Error ProcessWindowsLive::DoResume() { - llvm::sys::ScopedLock lock(m_mutex); - Error error; - - StateType private_state = GetPrivateState(); - if (private_state == eStateStopped || private_state == eStateCrashed) { - WINLOG_IFALL( - WINDOWS_LOG_PROCESS, - "DoResume called for process %I64u while state is %u. Resuming...", - m_session_data->m_debugger->GetProcess().GetProcessId(), - GetPrivateState()); - - ExceptionRecordSP active_exception = - m_session_data->m_debugger->GetActiveException().lock(); - if (active_exception) { - // Resume the process and continue processing debug events. Mask - // the exception so that from the process's view, there is no - // indication that anything happened. - m_session_data->m_debugger->ContinueAsyncException( - ExceptionResult::MaskException); - } - - WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_THREAD, - "DoResume resuming %u threads.", m_thread_list.GetSize()); - - for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) { - auto thread = std::static_pointer_cast<TargetThreadWindowsLive>( - m_thread_list.GetThreadAtIndex(i)); - thread->DoResume(); - } - - SetPrivateState(eStateRunning); - } else { - WINERR_IFALL( - WINDOWS_LOG_PROCESS, - "DoResume called for process %I64u but state is %u. Returning...", - m_session_data->m_debugger->GetProcess().GetProcessId(), - GetPrivateState()); - } - return error; -} - -//------------------------------------------------------------------------------ -// ProcessInterface protocol. - -lldb_private::ConstString ProcessWindowsLive::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t ProcessWindowsLive::GetPluginVersion() { return 1; } - -Error ProcessWindowsLive::DoDetach(bool keep_stopped) { - DebuggerThreadSP debugger_thread; - StateType private_state; - { - // Acquire the lock only long enough to get the DebuggerThread. - // StopDebugging() will trigger a call back into ProcessWindows which - // will also acquire the lock. Thus we have to release the lock before - // calling StopDebugging(). - llvm::sys::ScopedLock lock(m_mutex); - - private_state = GetPrivateState(); - - if (!m_session_data) { - WINWARN_IFALL( - WINDOWS_LOG_PROCESS, - "DoDetach called while state = %u, but there is no active session.", - private_state); - return Error(); - } - - debugger_thread = m_session_data->m_debugger; - } - - Error error; - if (private_state != eStateExited && private_state != eStateDetached) { - WINLOG_IFALL( - WINDOWS_LOG_PROCESS, - "DoDetach called for process %p while state = %d. Detaching...", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), - private_state); - error = debugger_thread->StopDebugging(false); - if (error.Success()) { - SetPrivateState(eStateDetached); - } - - // By the time StopDebugging returns, there is no more debugger thread, so - // we can be assured that no other thread will race for the session data. - m_session_data.reset(); - } else { - WINERR_IFALL( - WINDOWS_LOG_PROCESS, "DoDetach called for process %p while state = " - "%d, but cannot destroy in this state.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), - private_state); - } - - return error; -} - -Error ProcessWindowsLive::DoDestroy() { - DebuggerThreadSP debugger_thread; - StateType private_state; - { - // Acquire this lock inside an inner scope, only long enough to get the - // DebuggerThread. - // StopDebugging() will trigger a call back into ProcessWindows which will - // acquire the lock - // again, so we need to not deadlock. - llvm::sys::ScopedLock lock(m_mutex); - - private_state = GetPrivateState(); - - if (!m_session_data) { - WINWARN_IFALL( - WINDOWS_LOG_PROCESS, - "DoDestroy called while state = %u, but there is no active session.", - private_state); - return Error(); - } - - debugger_thread = m_session_data->m_debugger; - } - - Error error; - if (private_state != eStateExited && private_state != eStateDetached) { - WINLOG_IFALL( - WINDOWS_LOG_PROCESS, "DoDestroy called for process %p while state = " - "%u. Shutting down...", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), - private_state); - error = debugger_thread->StopDebugging(true); - - // By the time StopDebugging returns, there is no more debugger thread, so - // we can be assured that no other thread will race for the session data. - m_session_data.reset(); - } else { - WINERR_IFALL( - WINDOWS_LOG_PROCESS, "DoDestroy called for process %p while state = " - "%d, but cannot destroy in this state.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), - private_state); - } - - return error; -} - -void ProcessWindowsLive::RefreshStateAfterStop() { - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) { - WINWARN_IFALL( - WINDOWS_LOG_PROCESS, - "RefreshStateAfterStop called with no active session. Returning..."); - return; - } - - m_thread_list.RefreshStateAfterStop(); - - std::weak_ptr<ExceptionRecord> exception_record = - m_session_data->m_debugger->GetActiveException(); - ExceptionRecordSP active_exception = exception_record.lock(); - if (!active_exception) { - WINERR_IFALL( - WINDOWS_LOG_PROCESS, - "RefreshStateAfterStop called for process %I64u but there is no " - "active exception. Why is the process stopped?", - m_session_data->m_debugger->GetProcess().GetProcessId()); - return; - } - - StopInfoSP stop_info; - m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID()); - ThreadSP stop_thread = m_thread_list.GetSelectedThread(); - if (!stop_thread) - return; - - switch (active_exception->GetExceptionCode()) { - case EXCEPTION_SINGLE_STEP: { - RegisterContextSP register_context = stop_thread->GetRegisterContext(); - const uint64_t pc = register_context->GetPC(); - BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); - if (site && site->ValidForThisThread(stop_thread.get())) { - WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION | - WINDOWS_LOG_STEP, - "Single-stepped onto a breakpoint in process %I64u at " - "address 0x%I64x with breakpoint site %d", - m_session_data->m_debugger->GetProcess().GetProcessId(), pc, - site->GetID()); - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread, - site->GetID()); - stop_thread->SetStopInfo(stop_info); - } else { - WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, - "RefreshStateAfterStop single stepping thread %llu", - stop_thread->GetID()); - stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); - stop_thread->SetStopInfo(stop_info); - } - return; - } - - case EXCEPTION_BREAKPOINT: { - RegisterContextSP register_context = stop_thread->GetRegisterContext(); - - // The current EIP is AFTER the BP opcode, which is one byte. - uint64_t pc = register_context->GetPC() - 1; - - BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); - if (site) { - WINLOG_IFANY( - WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "RefreshStateAfterStop detected breakpoint in process %I64u at " - "address 0x%I64x with breakpoint site %d", - m_session_data->m_debugger->GetProcess().GetProcessId(), pc, - site->GetID()); - - if (site->ValidForThisThread(stop_thread.get())) { - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "Breakpoint site %d is valid for this thread (0x%I64x), " - "creating stop info.", - site->GetID(), stop_thread->GetID()); - - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( - *stop_thread, site->GetID()); - register_context->SetPC(pc); - } else { - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "Breakpoint site %d is not valid for this thread, " - "creating empty stop info.", - site->GetID()); - } - stop_thread->SetStopInfo(stop_info); - return; - } else { - // The thread hit a hard-coded breakpoint like an `int 3` or - // `__debugbreak()`. - WINLOG_IFALL( - WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "No breakpoint site matches for this thread. __debugbreak()? " - "Creating stop info with the exception."); - // FALLTHROUGH: We'll treat this as a generic exception record in the - // default case. - } - } - - default: { - std::string desc; - llvm::raw_string_ostream desc_stream(desc); - desc_stream << "Exception " - << llvm::format_hex(active_exception->GetExceptionCode(), 8) - << " encountered at address " - << llvm::format_hex(active_exception->GetExceptionAddress(), 8); - stop_info = StopInfo::CreateStopReasonWithException( - *stop_thread, desc_stream.str().c_str()); - stop_thread->SetStopInfo(stop_info); - WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, "%s", desc_stream.str().c_str()); - return; - } - } -} - -bool ProcessWindowsLive::IsAlive() { - StateType state = GetPrivateState(); - switch (state) { - case eStateCrashed: - case eStateDetached: - case eStateUnloaded: - case eStateExited: - case eStateInvalid: - return false; - default: - return true; - } -} - -Error ProcessWindowsLive::DoHalt(bool &caused_stop) { - Error error; - StateType state = GetPrivateState(); - if (state == eStateStopped) - caused_stop = false; - else { - llvm::sys::ScopedLock lock(m_mutex); - caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess() - .GetNativeProcess() - .GetSystemHandle()); - if (!caused_stop) { - error.SetError(::GetLastError(), eErrorTypeWin32); - WINERR_IFALL( - WINDOWS_LOG_PROCESS, - "DoHalt called DebugBreakProcess, but it failed with error %u", - error.GetError()); - } - } - return error; -} - -void ProcessWindowsLive::DidLaunch() { - ArchSpec arch_spec; - DidAttach(arch_spec); -} - -void ProcessWindowsLive::DidAttach(ArchSpec &arch_spec) { - llvm::sys::ScopedLock lock(m_mutex); - - // The initial stop won't broadcast the state change event, so account for - // that here. - if (m_session_data && GetPrivateState() == eStateStopped && - m_session_data->m_stop_at_entry) - RefreshStateAfterStop(); -} - -size_t ProcessWindowsLive::DoReadMemory(lldb::addr_t vm_addr, void *buf, - size_t size, Error &error) { - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) - return 0; - - WINLOG_IFALL(WINDOWS_LOG_MEMORY, - "DoReadMemory attempting to read %u bytes from address 0x%I64x", - size, vm_addr); - - HostProcess process = m_session_data->m_debugger->GetProcess(); - void *addr = reinterpret_cast<void *>(vm_addr); - SIZE_T bytes_read = 0; - if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, - buf, size, &bytes_read)) { - error.SetError(GetLastError(), eErrorTypeWin32); - WINERR_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory failed with error code %u", - error.GetError()); - } - return bytes_read; -} - -size_t ProcessWindowsLive::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, - size_t size, Error &error) { - llvm::sys::ScopedLock lock(m_mutex); - WINLOG_IFALL( - WINDOWS_LOG_MEMORY, - "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, - vm_addr); - - if (!m_session_data) { - WINERR_IFANY( - WINDOWS_LOG_MEMORY, - "DoWriteMemory cannot write, there is no active debugger connection."); - return 0; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - void *addr = reinterpret_cast<void *>(vm_addr); - SIZE_T bytes_written = 0; - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (WriteProcessMemory(handle, addr, buf, size, &bytes_written)) - FlushInstructionCache(handle, addr, bytes_written); - else { - error.SetError(GetLastError(), eErrorTypeWin32); - WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory failed with error code %u", - error.GetError()); - } - return bytes_written; -} - -Error ProcessWindowsLive::GetMemoryRegionInfo(lldb::addr_t vm_addr, - MemoryRegionInfo &info) { - Error error; - llvm::sys::ScopedLock lock(m_mutex); - info.Clear(); - - if (!m_session_data) { - error.SetErrorString( - "GetMemoryRegionInfo called with no debugging session."); - WINERR_IFALL(WINDOWS_LOG_MEMORY, "%s", error.AsCString()); - return error; - } - HostProcess process = m_session_data->m_debugger->GetProcess(); - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (handle == nullptr || handle == LLDB_INVALID_PROCESS) { - error.SetErrorString( - "GetMemoryRegionInfo called with an invalid target process."); - WINERR_IFALL(WINDOWS_LOG_MEMORY, "%s", error.AsCString()); - return error; - } - - WINLOG_IFALL(WINDOWS_LOG_MEMORY, - "GetMemoryRegionInfo getting info for address 0x%I64x", vm_addr); - - void *addr = reinterpret_cast<void *>(vm_addr); - MEMORY_BASIC_INFORMATION mem_info = {}; - SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); - if (result == 0) { - if (::GetLastError() == ERROR_INVALID_PARAMETER) { - // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with an - // address - // past the highest accessible address. We should return a range from the - // vm_addr - // to LLDB_INVALID_ADDRESS - info.GetRange().SetRangeBase(vm_addr); - info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); - info.SetReadable(MemoryRegionInfo::eNo); - info.SetExecutable(MemoryRegionInfo::eNo); - info.SetWritable(MemoryRegionInfo::eNo); - info.SetMapped(MemoryRegionInfo::eNo); - return error; - } else { - error.SetError(::GetLastError(), eErrorTypeWin32); - WINERR_IFALL(WINDOWS_LOG_MEMORY, "VirtualQueryEx returned error %u while " - "getting memory region info for address " - "0x%I64x", - error.GetError(), vm_addr); - return error; - } - } - - // Protect bits are only valid for MEM_COMMIT regions. - if (mem_info.State == MEM_COMMIT) { - const bool readable = IsPageReadable(mem_info.Protect); - const bool executable = IsPageExecutable(mem_info.Protect); - const bool writable = IsPageWritable(mem_info.Protect); - info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); - info.SetExecutable(executable ? MemoryRegionInfo::eYes - : MemoryRegionInfo::eNo); - info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); - } else { - info.SetReadable(MemoryRegionInfo::eNo); - info.SetExecutable(MemoryRegionInfo::eNo); - info.SetWritable(MemoryRegionInfo::eNo); - } - - // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE. - if (mem_info.State != MEM_FREE) { - info.GetRange().SetRangeBase( - reinterpret_cast<addr_t>(mem_info.AllocationBase)); - info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) + - mem_info.RegionSize); - info.SetMapped(MemoryRegionInfo::eYes); - } else { - // In the unmapped case we need to return the distance to the next block of - // memory. - // VirtualQueryEx nearly does that except that it gives the distance from - // the start - // of the page containing vm_addr. - SYSTEM_INFO data; - GetSystemInfo(&data); - DWORD page_offset = vm_addr % data.dwPageSize; - info.GetRange().SetRangeBase(vm_addr); - info.GetRange().SetByteSize(mem_info.RegionSize - page_offset); - info.SetMapped(MemoryRegionInfo::eNo); - } - - error.SetError(::GetLastError(), eErrorTypeWin32); - WINLOGV_IFALL(WINDOWS_LOG_MEMORY, "Memory region info for address %llu: " - "readable=%s, executable=%s, writable=%s", - vm_addr, BOOL_STR(info.GetReadable()), - BOOL_STR(info.GetExecutable()), BOOL_STR(info.GetWritable())); - return error; -} - -bool ProcessWindowsLive::CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) { - if (plugin_specified_by_name) - return true; - - // For now we are just making sure the file exists for a given module - ModuleSP exe_module_sp(target_sp->GetExecutableModule()); - if (exe_module_sp.get()) - return exe_module_sp->GetFileSpec().Exists(); - // However, if there is no executable module, we return true since we might be - // preparing to attach. - return true; -} - -void ProcessWindowsLive::OnExitProcess(uint32_t exit_code) { - // No need to acquire the lock since m_session_data isn't accessed. - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Process %llu exited with code %u", GetID(), - exit_code); - - TargetSP target = m_target_sp.lock(); - if (target) { - ModuleSP executable_module = target->GetExecutableModule(); - ModuleList unloaded_modules; - unloaded_modules.Append(executable_module); - target->ModulesDidUnload(unloaded_modules, true); - } - - SetProcessExitStatus(GetID(), true, 0, exit_code); - SetPrivateState(eStateExited); -} - -void ProcessWindowsLive::OnDebuggerConnected(lldb::addr_t image_base) { - DebuggerThreadSP debugger = m_session_data->m_debugger; - - WINLOG_IFALL(WINDOWS_LOG_PROCESS, - "Debugger connected to process %I64u. Image base = 0x%I64x", - debugger->GetProcess().GetProcessId(), image_base); - - ModuleSP module = GetTarget().GetExecutableModule(); - if (!module) { - // During attach, we won't have the executable module, so find it now. - const DWORD pid = debugger->GetProcess().GetProcessId(); - const std::string file_name = GetProcessExecutableName(pid); - if (file_name.empty()) { - return; - } - - FileSpec executable_file(file_name, true); - ModuleSpec module_spec(executable_file); - Error error; - module = GetTarget().GetSharedModule(module_spec, &error); - if (!module) { - return; - } - - GetTarget().SetExecutableModule(module, false); - } - - bool load_addr_changed; - module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed); - - ModuleList loaded_modules; - loaded_modules.Append(module); - GetTarget().ModulesDidLoad(loaded_modules); - - // Add the main executable module to the list of pending module loads. We - // can't call - // GetTarget().ModulesDidLoad() here because we still haven't returned from - // DoLaunch() / DoAttach() yet - // so the target may not have set the process instance to `this` yet. - llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wmain_thread = - debugger->GetMainThread().GetNativeThread(); - m_session_data->m_new_threads[wmain_thread.GetThreadId()] = - debugger->GetMainThread(); -} - -ExceptionResult -ProcessWindowsLive::OnDebugException(bool first_chance, - const ExceptionRecord &record) { - llvm::sys::ScopedLock lock(m_mutex); - - // FIXME: Without this check, occasionally when running the test suite there - // is - // an issue where m_session_data can be null. It's not clear how this could - // happen - // but it only surfaces while running the test suite. In order to properly - // diagnose - // this, we probably need to first figure allow the test suite to print out - // full - // lldb logs, and then add logging to the process plugin. - if (!m_session_data) { - WINERR_IFANY(WINDOWS_LOG_EXCEPTION, "Debugger thread reported exception " - "0x%lx at address 0x%llu, but there is " - "no session.", - record.GetExceptionCode(), record.GetExceptionAddress()); - return ExceptionResult::SendToApplication; - } - - if (!first_chance) { - // Any second chance exception is an application crash by definition. - SetPrivateState(eStateCrashed); - } - - ExceptionResult result = ExceptionResult::SendToApplication; - switch (record.GetExceptionCode()) { - case EXCEPTION_BREAKPOINT: - // Handle breakpoints at the first chance. - result = ExceptionResult::BreakInDebugger; - - if (!m_session_data->m_initial_stop_received) { - WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, "Hit loader breakpoint at address " - "0x%I64x, setting initial stop " - "event.", - record.GetExceptionAddress()); - m_session_data->m_initial_stop_received = true; - ::SetEvent(m_session_data->m_initial_stop_event); - } else { - WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, - "Hit non-loader breakpoint at address 0x%I64x.", - record.GetExceptionAddress()); - } - SetPrivateState(eStateStopped); - break; - case EXCEPTION_SINGLE_STEP: - result = ExceptionResult::BreakInDebugger; - SetPrivateState(eStateStopped); - break; - default: - WINLOG_IFANY(WINDOWS_LOG_EXCEPTION, "Debugger thread reported exception " - "0x%lx at address 0x%llx " - "(first_chance=%s)", - record.GetExceptionCode(), record.GetExceptionAddress(), - BOOL_STR(first_chance)); - // For non-breakpoints, give the application a chance to handle the - // exception first. - if (first_chance) - result = ExceptionResult::SendToApplication; - else - result = ExceptionResult::BreakInDebugger; - } - - return result; -} - -void ProcessWindowsLive::OnCreateThread(const HostThread &new_thread) { - llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wnew_thread = new_thread.GetNativeThread(); - m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread; -} - -void ProcessWindowsLive::OnExitThread(lldb::tid_t thread_id, - uint32_t exit_code) { - llvm::sys::ScopedLock lock(m_mutex); - - // On a forced termination, we may get exit thread events after the session - // data has been cleaned up. - if (!m_session_data) - return; - - // A thread may have started and exited before the debugger stopped allowing a - // refresh. - // Just remove it from the new threads list in that case. - auto iter = m_session_data->m_new_threads.find(thread_id); - if (iter != m_session_data->m_new_threads.end()) - m_session_data->m_new_threads.erase(iter); - else - m_session_data->m_exited_threads.insert(thread_id); -} - -void ProcessWindowsLive::OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) { - // Confusingly, there is no Target::AddSharedModule. Instead, calling - // GetSharedModule() with - // a new module will add it to the module list and return a corresponding - // ModuleSP. - Error error; - ModuleSP module = GetTarget().GetSharedModule(module_spec, &error); - bool load_addr_changed = false; - module->SetLoadAddress(GetTarget(), module_addr, false, load_addr_changed); - - ModuleList loaded_modules; - loaded_modules.Append(module); - GetTarget().ModulesDidLoad(loaded_modules); -} - -void ProcessWindowsLive::OnUnloadDll(lldb::addr_t module_addr) { - Address resolved_addr; - if (GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) { - ModuleSP module = resolved_addr.GetModule(); - if (module) { - ModuleList unloaded_modules; - unloaded_modules.Append(module); - GetTarget().ModulesDidUnload(unloaded_modules, false); - } - } -} - -void ProcessWindowsLive::OnDebugString(const std::string &string) {} - -void ProcessWindowsLive::OnDebuggerError(const Error &error, uint32_t type) { - llvm::sys::ScopedLock lock(m_mutex); - - if (m_session_data->m_initial_stop_received) { - // This happened while debugging. Do we shutdown the debugging session, try - // to continue, - // or do something else? - WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred during debugging. " - "Unexpected behavior may result. %s", - error.GetError(), error.AsCString()); - } else { - // If we haven't actually launched the process yet, this was an error - // launching the - // process. Set the internal error and signal the initial stop event so - // that the DoLaunch - // method wakes up and returns a failure. - m_session_data->m_launch_error = error; - ::SetEvent(m_session_data->m_initial_stop_event); - WINERR_IFALL( - WINDOWS_LOG_PROCESS, - "Error %u occurred launching the process before the initial stop. %s", - error.GetError(), error.AsCString()); - return; - } -} diff --git a/lldb/source/Plugins/Process/Windows/Live/ProcessWindowsLive.h b/lldb/source/Plugins/Process/Windows/Live/ProcessWindowsLive.h deleted file mode 100644 index 0b6f4074d29..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/ProcessWindowsLive.h +++ /dev/null @@ -1,129 +0,0 @@ -//===-- ProcessWindowsLive.h ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_Live_ProcessWindowsLive_H_ -#define liblldb_Plugins_Process_Windows_Live_ProcessWindowsLive_H_ - -// C Includes - -// C++ Includes -#include <memory> -#include <queue> - -// Other libraries and framework includes -#include "ForwardDecl.h" -#include "IDebugDelegate.h" -#include "lldb/Core/Error.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Target/Process.h" -#include "lldb/lldb-forward.h" - -#include "llvm/Support/Mutex.h" - -#include "Plugins/Process/Windows/Common/ProcessWindows.h" - -class ProcessMonitor; - -namespace lldb_private { -class HostProcess; -class ProcessWindowsData; - -class ProcessWindowsLive : public lldb_private::ProcessWindows, - public lldb_private::IDebugDelegate { -public: - //------------------------------------------------------------------ - // Static functions. - //------------------------------------------------------------------ - static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - const lldb_private::FileSpec *); - - static void Initialize(); - - static void Terminate(); - - static lldb_private::ConstString GetPluginNameStatic(); - - static const char *GetPluginDescriptionStatic(); - - //------------------------------------------------------------------ - // Constructors and destructors - //------------------------------------------------------------------ - ProcessWindowsLive(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); - - ~ProcessWindowsLive(); - - // lldb_private::Process overrides - lldb_private::ConstString GetPluginName() override; - uint32_t GetPluginVersion() override; - - lldb_private::Error - EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - lldb_private::Error - DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - - lldb_private::Error DoDetach(bool keep_stopped) override; - lldb_private::Error - DoLaunch(lldb_private::Module *exe_module, - lldb_private::ProcessLaunchInfo &launch_info) override; - lldb_private::Error DoAttachToProcessWithID( - lldb::pid_t pid, - const lldb_private::ProcessAttachInfo &attach_info) override; - lldb_private::Error DoResume() override; - lldb_private::Error DoDestroy() override; - lldb_private::Error DoHalt(bool &caused_stop) override; - - void DidLaunch() override; - void DidAttach(lldb_private::ArchSpec &arch_spec) override; - - void RefreshStateAfterStop() override; - - bool CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) override; - bool DestroyRequiresHalt() override { return false; } - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; - bool IsAlive() override; - - size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - lldb_private::Error &error) override; - size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Error &error) override; - lldb_private::Error - GetMemoryRegionInfo(lldb::addr_t vm_addr, - lldb_private::MemoryRegionInfo &info) override; - - // IDebugDelegate overrides. - void OnExitProcess(uint32_t exit_code) override; - void OnDebuggerConnected(lldb::addr_t image_base) override; - ExceptionResult - OnDebugException(bool first_chance, - const lldb_private::ExceptionRecord &record) override; - void OnCreateThread(const lldb_private::HostThread &thread) override; - void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const lldb_private::ModuleSpec &module_spec, - lldb::addr_t module_addr) override; - void OnUnloadDll(lldb::addr_t module_addr) override; - void OnDebugString(const std::string &string) override; - void OnDebuggerError(const lldb_private::Error &error, - uint32_t type) override; - -private: - lldb_private::Error - WaitForDebuggerConnection(lldb_private::DebuggerThreadSP debugger, - lldb_private::HostProcess &process); - - llvm::sys::Mutex m_mutex; - - // Data for the active debugging session. - std::unique_ptr<lldb_private::ProcessWindowsData> m_session_data; -}; -} - -#endif // liblldb_Plugins_Process_Windows_Live_ProcessWindowsLive_H_ diff --git a/lldb/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp b/lldb/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp deleted file mode 100644 index b965a6cc3dc..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp +++ /dev/null @@ -1,124 +0,0 @@ -//===-- TargetThreadWindowsLive.cpp------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Core/Log.h" -#include "lldb/Core/Logging.h" -#include "lldb/Core/State.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Host/HostNativeThreadBase.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Target/RegisterContext.h" - -#include "ProcessWindows.h" -#include "ProcessWindowsLog.h" -#include "TargetThreadWindowsLive.h" -#include "UnwindLLDB.h" - -#if defined(_WIN64) -#include "x64/RegisterContextWindowsLive_x64.h" -#else -#include "x86/RegisterContextWindowsLive_x86.h" -#endif - -using namespace lldb; -using namespace lldb_private; - -TargetThreadWindowsLive::TargetThreadWindowsLive(ProcessWindows &process, - const HostThread &thread) - : TargetThreadWindows(process, thread), m_host_thread(thread) {} - -TargetThreadWindowsLive::~TargetThreadWindowsLive() { DestroyThread(); } - -void TargetThreadWindowsLive::RefreshStateAfterStop() { - ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle()); - SetState(eStateStopped); - GetRegisterContext()->InvalidateIfNeeded(false); -} - -void TargetThreadWindowsLive::WillResume(lldb::StateType resume_state) {} - -void TargetThreadWindowsLive::DidStop() {} - -RegisterContextSP TargetThreadWindowsLive::GetRegisterContext() { - if (!m_reg_context_sp) - m_reg_context_sp = CreateRegisterContextForFrameIndex(0); - - return m_reg_context_sp; -} - -RegisterContextSP -TargetThreadWindowsLive::CreateRegisterContextForFrame(StackFrame *frame) { - return CreateRegisterContextForFrameIndex(frame->GetConcreteFrameIndex()); -} - -RegisterContextSP -TargetThreadWindowsLive::CreateRegisterContextForFrameIndex(uint32_t idx) { - if (!m_reg_context_sp) { - ArchSpec arch = HostInfo::GetArchitecture(); - switch (arch.GetMachine()) { - case llvm::Triple::x86: -#if defined(_WIN64) -// FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64 -#else - m_reg_context_sp.reset(new RegisterContextWindowsLive_x86(*this, idx)); -#endif - break; - case llvm::Triple::x86_64: -#if defined(_WIN64) - m_reg_context_sp.reset(new RegisterContextWindowsLive_x64(*this, idx)); -#else -// LLDB is 32-bit, but the target process is 64-bit. We probably can't debug -// this. -#endif - default: - break; - } - } - return m_reg_context_sp; -} - -bool TargetThreadWindowsLive::CalculateStopInfo() { - SetStopInfo(m_stop_info_sp); - return true; -} - -Unwind *TargetThreadWindowsLive::GetUnwinder() { - // FIXME: Implement an unwinder based on the Windows unwinder exposed through - // DIA SDK. - if (m_unwinder_ap.get() == NULL) - m_unwinder_ap.reset(new UnwindLLDB(*this)); - return m_unwinder_ap.get(); -} - -bool TargetThreadWindowsLive::DoResume() { - StateType resume_state = GetTemporaryResumeState(); - StateType current_state = GetState(); - if (resume_state == current_state) - return true; - - 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 { - previous_suspend_count = ::ResumeThread(thread_handle); - } while (previous_suspend_count > 0); - } - return true; -} diff --git a/lldb/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h b/lldb/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h deleted file mode 100644 index 47e09247a63..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h +++ /dev/null @@ -1,50 +0,0 @@ -//===-- TargetThreadWindowsLive.h -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_TargetThreadWindowsLive_H_ -#define liblldb_Plugins_Process_Windows_TargetThreadWindowsLive_H_ - -#include "lldb/Host/HostThread.h" -#include "lldb/Target/Thread.h" -#include "lldb/lldb-forward.h" - -#include "Plugins/Process/Windows/Common/TargetThreadWindows.h" - -namespace lldb_private { -class ProcessWindows; -class HostThread; -class StackFrame; - -class TargetThreadWindowsLive : public lldb_private::TargetThreadWindows { -public: - TargetThreadWindowsLive(ProcessWindows &process, const HostThread &thread); - virtual ~TargetThreadWindowsLive(); - - // lldb_private::Thread overrides - void RefreshStateAfterStop() override; - void WillResume(lldb::StateType resume_state) override; - void DidStop() override; - lldb::RegisterContextSP GetRegisterContext() override; - lldb::RegisterContextSP - CreateRegisterContextForFrame(StackFrame *frame) override; - bool CalculateStopInfo() override; - Unwind *GetUnwinder() override; - - bool DoResume(); - - HostThread GetHostThread() const { return m_host_thread; } - -private: - lldb::RegisterContextSP CreateRegisterContextForFrameIndex(uint32_t idx); - - HostThread m_host_thread; -}; -} - -#endif diff --git a/lldb/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.cpp b/lldb/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.cpp deleted file mode 100644 index 33237110991..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//===-- RegisterContextWindowsLive_x64.cpp ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Core/Error.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/lldb-private-types.h" - -#include "RegisterContextWindowsLive_x64.h" -#include "TargetThreadWindows.h" -#include "lldb-x86-register-enums.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; -using namespace lldb_private; - -RegisterContextWindowsLive_x64::RegisterContextWindowsLive_x64( - Thread &thread, uint32_t concrete_frame_idx) - : RegisterContextWindows_x64(thread, concrete_frame_idx) {} - -RegisterContextWindowsLive_x64::~RegisterContextWindowsLive_x64() {} - -bool RegisterContextWindowsLive_x64::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - if (!CacheAllRegisterValues()) - return false; - - switch (reg_info->kinds[eRegisterKindLLDB]) { - case lldb_rax_x86_64: - reg_value.SetUInt64(m_context.Rax); - break; - case lldb_rbx_x86_64: - reg_value.SetUInt64(m_context.Rbx); - break; - case lldb_rcx_x86_64: - reg_value.SetUInt64(m_context.Rcx); - break; - case lldb_rdx_x86_64: - reg_value.SetUInt64(m_context.Rdx); - break; - case lldb_rdi_x86_64: - reg_value.SetUInt64(m_context.Rdi); - break; - case lldb_rsi_x86_64: - reg_value.SetUInt64(m_context.Rsi); - break; - case lldb_r8_x86_64: - reg_value.SetUInt64(m_context.R8); - break; - case lldb_r9_x86_64: - reg_value.SetUInt64(m_context.R9); - break; - case lldb_r10_x86_64: - reg_value.SetUInt64(m_context.R10); - break; - case lldb_r11_x86_64: - reg_value.SetUInt64(m_context.R11); - break; - case lldb_r12_x86_64: - reg_value.SetUInt64(m_context.R12); - break; - case lldb_r13_x86_64: - reg_value.SetUInt64(m_context.R13); - break; - case lldb_r14_x86_64: - reg_value.SetUInt64(m_context.R14); - break; - case lldb_r15_x86_64: - reg_value.SetUInt64(m_context.R15); - break; - case lldb_rbp_x86_64: - reg_value.SetUInt64(m_context.Rbp); - break; - case lldb_rsp_x86_64: - reg_value.SetUInt64(m_context.Rsp); - break; - case lldb_rip_x86_64: - reg_value.SetUInt64(m_context.Rip); - break; - case lldb_rflags_x86_64: - reg_value.SetUInt64(m_context.EFlags); - break; - } - return true; -} - -bool RegisterContextWindowsLive_x64::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - // Since we cannot only write a single register value to the inferior, we need - // to make sure - // our cached copy of the register values are fresh. Otherwise when writing - // EAX, for example, - // we may also overwrite some other register with a stale value. - if (!CacheAllRegisterValues()) - return false; - - switch (reg_info->kinds[eRegisterKindLLDB]) { - case lldb_rax_x86_64: - m_context.Rax = reg_value.GetAsUInt64(); - break; - case lldb_rbx_x86_64: - m_context.Rbx = reg_value.GetAsUInt64(); - break; - case lldb_rcx_x86_64: - m_context.Rcx = reg_value.GetAsUInt64(); - break; - case lldb_rdx_x86_64: - m_context.Rdx = reg_value.GetAsUInt64(); - break; - case lldb_rdi_x86_64: - m_context.Rdi = reg_value.GetAsUInt64(); - break; - case lldb_rsi_x86_64: - m_context.Rsi = reg_value.GetAsUInt64(); - break; - case lldb_r8_x86_64: - m_context.R8 = reg_value.GetAsUInt64(); - break; - case lldb_r9_x86_64: - m_context.R9 = reg_value.GetAsUInt64(); - break; - case lldb_r10_x86_64: - m_context.R10 = reg_value.GetAsUInt64(); - break; - case lldb_r11_x86_64: - m_context.R11 = reg_value.GetAsUInt64(); - break; - case lldb_r12_x86_64: - m_context.R12 = reg_value.GetAsUInt64(); - break; - case lldb_r13_x86_64: - m_context.R13 = reg_value.GetAsUInt64(); - break; - case lldb_r14_x86_64: - m_context.R14 = reg_value.GetAsUInt64(); - break; - case lldb_r15_x86_64: - m_context.R15 = reg_value.GetAsUInt64(); - break; - case lldb_rbp_x86_64: - m_context.Rbp = reg_value.GetAsUInt64(); - break; - case lldb_rsp_x86_64: - m_context.Rsp = reg_value.GetAsUInt64(); - break; - case lldb_rip_x86_64: - m_context.Rip = reg_value.GetAsUInt64(); - break; - case lldb_rflags_x86_64: - m_context.EFlags = reg_value.GetAsUInt64(); - break; - } - - // Physically update the registers in the target process. - TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); - return ::SetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); -} diff --git a/lldb/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.h b/lldb/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.h deleted file mode 100644 index 84425c4fa82..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- RegisterContextWindowsLive_x64.h ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextWindowsLive_x64_H_ -#define liblldb_RegisterContextWindowsLive_x64_H_ - -#include "../../Common/x64/RegisterContextWindows_x64.h" -#include "lldb/lldb-forward.h" - -namespace lldb_private { - -class Thread; - -class RegisterContextWindowsLive_x64 : public RegisterContextWindows_x64 { -public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContextWindowsLive_x64(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindowsLive_x64(); - - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ - bool ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - bool WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; -}; -} - -#endif // #ifndef liblldb_RegisterContextWindowsLive_x64_H_ diff --git a/lldb/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp b/lldb/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp deleted file mode 100644 index 0e7412051ae..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp +++ /dev/null @@ -1,108 +0,0 @@ -//===-- RegisterContextWindowsLive_x86.cpp ------------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Core/Error.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/lldb-private-types.h" - -#include "ProcessWindowsLog.h" -#include "RegisterContextWindowsLive_x86.h" -#include "TargetThreadWindows.h" -#include "lldb-x86-register-enums.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; - -namespace lldb_private { - -RegisterContextWindowsLive_x86::RegisterContextWindowsLive_x86( - Thread &thread, uint32_t concrete_frame_idx) - : RegisterContextWindows_x86(thread, concrete_frame_idx) {} - -RegisterContextWindowsLive_x86::~RegisterContextWindowsLive_x86() {} - -bool RegisterContextWindowsLive_x86::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - // Since we cannot only write a single register value to the inferior, we need - // to make sure - // our cached copy of the register values are fresh. Otherwise when writing - // EAX, for example, - // we may also overwrite some other register with a stale value. - if (!CacheAllRegisterValues()) - return false; - - uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - switch (reg) { - case lldb_eax_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EAX", - reg_value.GetAsUInt32()); - m_context.Eax = reg_value.GetAsUInt32(); - break; - case lldb_ebx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBX", - reg_value.GetAsUInt32()); - m_context.Ebx = reg_value.GetAsUInt32(); - break; - case lldb_ecx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ECX", - reg_value.GetAsUInt32()); - m_context.Ecx = reg_value.GetAsUInt32(); - break; - case lldb_edx_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDX", - reg_value.GetAsUInt32()); - m_context.Edx = reg_value.GetAsUInt32(); - break; - case lldb_edi_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDI", - reg_value.GetAsUInt32()); - m_context.Edi = reg_value.GetAsUInt32(); - break; - case lldb_esi_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESI", - reg_value.GetAsUInt32()); - m_context.Esi = reg_value.GetAsUInt32(); - break; - case lldb_ebp_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBP", - reg_value.GetAsUInt32()); - m_context.Ebp = reg_value.GetAsUInt32(); - break; - case lldb_esp_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESP", - reg_value.GetAsUInt32()); - m_context.Esp = reg_value.GetAsUInt32(); - break; - case lldb_eip_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EIP", - reg_value.GetAsUInt32()); - m_context.Eip = reg_value.GetAsUInt32(); - break; - case lldb_eflags_i386: - WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EFLAGS", - reg_value.GetAsUInt32()); - m_context.EFlags = reg_value.GetAsUInt32(); - break; - default: - WINWARN_IFALL(WINDOWS_LOG_REGISTERS, - "Write value 0x%x to unknown register %u", - reg_value.GetAsUInt32(), reg); - } - - // Physically update the registers in the target process. - TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); - return ::SetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); -} - -} // namespace lldb_private diff --git a/lldb/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h b/lldb/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h deleted file mode 100644 index e9b8ecd58f5..00000000000 --- a/lldb/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h +++ /dev/null @@ -1,34 +0,0 @@ -//===-- RegisterContextWindowsLive_x86.h ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextWindowsLive_x86_H_ -#define liblldb_RegisterContextWindowsLive_x86_H_ - -#include "../../Common/x86/RegisterContextWindows_x86.h" -#include "lldb/lldb-forward.h" - -namespace lldb_private { - -class Thread; - -class RegisterContextWindowsLive_x86 : public RegisterContextWindows_x86 { -public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContextWindowsLive_x86(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindowsLive_x86(); - - bool WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; -}; -} - -#endif // #ifndef liblldb_RegisterContextWindowsLive_x86_H_ |

