Author: stella.stamenova Date: Mon Jul 8 11:53:32 2019 New Revision: 365371
URL: http://llvm.org/viewvc/llvm-project?rev=365371&view=rev Log: Revert "Move common functionality from processwindows into processdebugger" This reverts commit 9c01eaff6aa3f59d91530f47b85bb470377a7780. The changes in this commit are causing several of the LLDB tests to hang and/or timeout. Removed: lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h Modified: lldb/trunk/source/Plugins/Process/Windows/Common/CMakeLists.txt lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h Modified: lldb/trunk/source/Plugins/Process/Windows/Common/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/Common/CMakeLists.txt?rev=365371&r1=365370&r2=365371&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/CMakeLists.txt (original) +++ lldb/trunk/source/Plugins/Process/Windows/Common/CMakeLists.txt Mon Jul 8 11:53:32 2019 @@ -2,7 +2,6 @@ add_lldb_library(lldbPluginProcessWindowsCommon PLUGIN DebuggerThread.cpp LocalDebugDelegate.cpp - ProcessDebugger.cpp ProcessWindows.cpp ProcessWindowsLog.cpp RegisterContextWindows.cpp Removed: lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp?rev=365370&view=auto ============================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp (original) +++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp (removed) @@ -1,572 +0,0 @@ -//===-- ProcessDebugger.cpp -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "ProcessDebugger.h" - -// Windows includes -#include "lldb/Host/windows/windows.h" -#include <psapi.h> - -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/HostNativeProcessBase.h" -#include "lldb/Host/HostProcess.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Host/ProcessLaunchInfo.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Target/Process.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/Error.h" - -#include "DebuggerThread.h" -#include "ExceptionRecord.h" -#include "ProcessWindowsLog.h" - -using namespace lldb; -using namespace lldb_private; - -static DWORD ConvertLldbToWinApiProtect(uint32_t protect) { - // We also can process a read / write permissions here, but if the debugger - // will make later a write into the allocated memory, it will fail. To get - // around it is possible inside DoWriteMemory to remember memory permissions, - // allow write, write and restore permissions, but for now we process only - // the executable permission. - // - // TODO: Process permissions other than executable - if (protect & ePermissionsExecutable) - return PAGE_EXECUTE_READWRITE; - - return PAGE_READWRITE; -} - -// 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. -static bool IsPageReadable(uint32_t protect) { - return (protect & PAGE_NOACCESS) == 0; -} - -static bool IsPageWritable(uint32_t protect) { - return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | - PAGE_READWRITE | PAGE_WRITECOPY)) != 0; -} - -static bool IsPageExecutable(uint32_t protect) { - return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | - PAGE_EXECUTE_WRITECOPY)) != 0; -} - -namespace lldb_private { - -lldb::pid_t ProcessDebugger::GetDebuggedProcessId() const { - if (m_session_data) - return m_session_data->m_debugger->GetProcess().GetProcessId(); - return LLDB_INVALID_PROCESS_ID; -} - -Status ProcessDebugger::DetachProcess() { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - DebuggerThreadSP debugger_thread; - { - // Acquire the lock only long enough to get the DebuggerThread. - // StopDebugging() will trigger a call back into ProcessDebugger which will - // also acquire the lock. Thus we have to release the lock before calling - // StopDebugging(). - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) { - LLDB_LOG(log, "there is no active session."); - return Status(); - } - - debugger_thread = m_session_data->m_debugger; - } - - Status error; - - LLDB_LOG(log, "detaching from process {0}.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle()); - error = debugger_thread->StopDebugging(false); - - // 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(); - - return error; -} - -Status ProcessDebugger::LaunchProcess(ProcessLaunchInfo &launch_info, - DebugDelegateSP delegate) { - // 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. - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - Status result; - - FileSpec working_dir = launch_info.GetWorkingDirectory(); - namespace fs = llvm::sys::fs; - if (working_dir) { - FileSystem::Instance().Resolve(working_dir); - if (!FileSystem::Instance().IsDirectory(working_dir)) { - result.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return result; - } - } - - if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) { - StreamString stream; - stream.Printf("ProcessDebugger unable to launch '%s'. ProcessDebugger can " - "only be used for debug launches.", - launch_info.GetExecutableFile().GetPath().c_str()); - std::string message = stream.GetString(); - result.SetErrorString(message.c_str()); - - LLDB_LOG(log, "error: {0}", message); - return result; - } - - bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); - m_session_data.reset(new ProcessWindowsData(stop_at_entry)); - 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()) { - LLDB_LOG(log, "failed launching '{0}'. {1}", - launch_info.GetExecutableFile().GetPath(), result); - return result; - } - - HostProcess process; - Status error = WaitForDebuggerConnection(debugger, process); - if (error.Fail()) { - LLDB_LOG(log, "failed launching '{0}'. {1}", - launch_info.GetExecutableFile().GetPath(), error); - return error; - } - - LLDB_LOG(log, "successfully launched '{0}'", - launch_info.GetExecutableFile().GetPath()); - - // 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()); - - return result; -} - -Status ProcessDebugger::AttachProcess(const ProcessAttachInfo &attach_info, - DebugDelegateSP delegate) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - m_session_data.reset( - new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); - DebuggerThreadSP debugger(new DebuggerThread(delegate)); - - m_session_data->m_debugger = debugger; - - DWORD process_id = static_cast<DWORD>(attach_info.GetProcessID()); - Status error = debugger->DebugAttach(process_id, attach_info); - if (error.Fail()) { - LLDB_LOG( - log, - "encountered an error occurred initiating the asynchronous attach. {0}", - error); - return error; - } - - HostProcess process; - error = WaitForDebuggerConnection(debugger, process); - if (error.Fail()) { - LLDB_LOG(log, - "encountered an error waiting for the debugger to connect. {0}", - error); - return error; - } - - LLDB_LOG(log, "successfully attached to process with pid={0}", 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. - - return error; -} - -Status ProcessDebugger::DestroyProcess() { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - DebuggerThreadSP debugger_thread; - { - // Acquire this lock inside an inner scope, only long enough to get the - // DebuggerThread. StopDebugging() will trigger a call back into - // ProcessDebugger which will acquire the lock again, so we need to not - // deadlock. - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) { - LLDB_LOG(log, "warning: there is no active session."); - return Status(); - } - - debugger_thread = m_session_data->m_debugger; - } - - LLDB_LOG(log, "Shutting down process {0}.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle()); - Status 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(); - - return error; -} - -Status ProcessDebugger::HaltProcess(bool &caused_stop) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - Status error; - llvm::sys::ScopedLock lock(m_mutex); - caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess() - .GetNativeProcess() - .GetSystemHandle()); - if (!caused_stop) { - error.SetError(::GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error); - } - - return error; -} - -Status ProcessDebugger::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - size_t &bytes_read) { - Status error; - bytes_read = 0; - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) { - error.SetErrorString( - "cannot read, there is no active debugger connection."); - LLDB_LOG(log, "error: {0}", error); - return error; - } - - LLDB_LOG(log, "attempting to read {0} bytes from address {1:x}", size, - vm_addr); - - HostProcess process = m_session_data->m_debugger->GetProcess(); - void *addr = reinterpret_cast<void *>(vm_addr); - SIZE_T num_of_bytes_read = 0; - if (!::ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, - buf, size, &num_of_bytes_read)) { - // Reading from the process can fail for a number of reasons - set the - // error code and make sure that the number of bytes read is set back to 0 - // because in some scenarios the value of bytes_read returned from the API - // is garbage. - error.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "reading failed with error: {0}", error); - } else { - bytes_read = num_of_bytes_read; - } - return error; -} - -Status ProcessDebugger::WriteMemory(lldb::addr_t vm_addr, const void *buf, - size_t size, size_t &bytes_written) { - Status error; - bytes_written = 0; - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - llvm::sys::ScopedLock lock(m_mutex); - LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size, - vm_addr); - - if (!m_session_data) { - error.SetErrorString( - "cannot write, there is no active debugger connection."); - LLDB_LOG(log, "error: {0}", error); - return error; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - void *addr = reinterpret_cast<void *>(vm_addr); - SIZE_T num_of_bytes_written = 0; - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (::WriteProcessMemory(handle, addr, buf, size, &num_of_bytes_written)) { - FlushInstructionCache(handle, addr, num_of_bytes_written); - bytes_written = num_of_bytes_written; - } else { - error.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "writing failed with error: {0}", error); - } - return error; -} - -Status ProcessDebugger::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) { - Status error; - addr = LLDB_INVALID_ADDRESS; - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - llvm::sys::ScopedLock lock(m_mutex); - LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size, - permissions); - - if (!m_session_data) { - error.SetErrorString( - "cannot allocate, there is no active debugger connection"); - LLDB_LOG(log, "error: {0}", error); - return error; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - auto protect = ConvertLldbToWinApiProtect(permissions); - auto result = ::VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect); - if (!result) { - error.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "allocating failed with error: {0}", error); - } else { - addr = reinterpret_cast<addr_t>(result); - } - return error; -} - -Status ProcessDebugger::DeallocateMemory(lldb::addr_t vm_addr) { - Status result; - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - llvm::sys::ScopedLock lock(m_mutex); - LLDB_LOG(log, "attempting to deallocate bytes at address {0}", vm_addr); - - if (!m_session_data) { - result.SetErrorString( - "cannot deallocate, there is no active debugger connection"); - LLDB_LOG(log, "error: {0}", result); - return result; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (!::VirtualFreeEx(handle, reinterpret_cast<LPVOID>(vm_addr), 0, - MEM_RELEASE)) { - result.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "deallocating failed with error: {0}", result); - } - - return result; -} - -Status ProcessDebugger::GetMemoryRegionInfo(lldb::addr_t vm_addr, - MemoryRegionInfo &info) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - Status error; - llvm::sys::ScopedLock lock(m_mutex); - info.Clear(); - - if (!m_session_data) { - error.SetErrorString( - "GetMemoryRegionInfo called with no debugging session."); - LLDB_LOG(log, "error: {0}", error); - 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."); - LLDB_LOG(log, "error: {0}", error); - return error; - } - - LLDB_LOG(log, "getting info for address {0:x}", 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); - LLDB_LOG(log, - "VirtualQueryEx returned error {0} while getting memory " - "region info for address {1:x}", - error, 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); - LLDB_LOGV(log, - "Memory region info for address {0}: readable={1}, " - "executable={2}, writable={3}", - vm_addr, info.GetReadable(), info.GetExecutable(), - info.GetWritable()); - return error; -} - -void ProcessDebugger::OnExitProcess(uint32_t exit_code) { - // If the process exits before any initial stop then notify the debugger - // of the error otherwise WaitForDebuggerConnection() will be blocked. - // An example of this issue is when a process fails to load a dependent DLL. - if (m_session_data && !m_session_data->m_initial_stop_received) { - Status error(exit_code, eErrorTypeWin32); - OnDebuggerError(error, 0); - } -} - -void ProcessDebugger::OnDebuggerConnected(lldb::addr_t image_base) {} - -ExceptionResult -ProcessDebugger::OnDebugException(bool first_chance, - const ExceptionRecord &record) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION); - 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) { - LLDB_LOG(log, - "Debugger thread reported exception {0:x} at address {1:x}, but " - "there is no session.", - record.GetExceptionCode(), record.GetExceptionAddress()); - return ExceptionResult::SendToApplication; - } - - ExceptionResult result = ExceptionResult::SendToApplication; - if ((record.GetExceptionCode() == EXCEPTION_BREAKPOINT || - record.GetExceptionCode() == - 0x4000001FL /*WOW64 STATUS_WX86_BREAKPOINT*/) && - !m_session_data->m_initial_stop_received) { - // Handle breakpoints at the first chance. - result = ExceptionResult::BreakInDebugger; - LLDB_LOG( - log, - "Hit loader breakpoint at address {0:x}, setting initial stop event.", - record.GetExceptionAddress()); - m_session_data->m_initial_stop_received = true; - ::SetEvent(m_session_data->m_initial_stop_event); - } - return result; -} - -void ProcessDebugger::OnCreateThread(const HostThread &thread) { - // Do nothing by default -} - -void ProcessDebugger::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { - // Do nothing by default -} - -void ProcessDebugger::OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) { - // Do nothing by default -} - -void ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr) { - // Do nothing by default -} - -void ProcessDebugger::OnDebugString(const std::string &string) {} - -void ProcessDebugger::OnDebuggerError(const Status &error, uint32_t type) { - llvm::sys::ScopedLock lock(m_mutex); - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - - 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? - LLDB_LOG(log, - "Error {0} occurred during debugging. Unexpected behavior " - "may result. {1}", - error.GetError(), error); - } 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); - LLDB_LOG(log, - "Error {0} occurred launching the process before the initial " - "stop. {1}", - error.GetError(), error); - return; - } -} - -Status ProcessDebugger::WaitForDebuggerConnection(DebuggerThreadSP debugger, - HostProcess &process) { - Status result; - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS | - WINDOWS_LOG_BREAKPOINTS); - LLDB_LOG(log, "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) { - LLDB_LOG(log, "hit loader breakpoint, returning."); - - process = debugger->GetProcess(); - return m_session_data->m_launch_error; - } else - return Status(::GetLastError(), eErrorTypeWin32); -} - -} // namespace lldb_private Removed: lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h?rev=365370&view=auto ============================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h (original) +++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h (removed) @@ -1,101 +0,0 @@ -//===-- ProcessDebugger.h ---------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessDebugger_h_ -#define liblldb_ProcessDebugger_h_ - -#include "lldb/Host/windows/windows.h" - -#include "lldb/Utility/Status.h" -#include "lldb/lldb-forward.h" -#include "lldb/lldb-types.h" -#include "llvm/Support/Mutex.h" - -#include "ForwardDecl.h" -#include <map> -#include <set> - -namespace lldb_private { - -class HostProcess; -class HostThread; -class ProcessLaunchInfo; -class ProcessAttachInfo; - -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); } - - Status 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; -}; - -class ProcessDebugger { - -public: - virtual void OnExitProcess(uint32_t exit_code); - virtual void OnDebuggerConnected(lldb::addr_t image_base); - virtual ExceptionResult OnDebugException(bool first_chance, - const ExceptionRecord &record); - virtual void OnCreateThread(const HostThread &thread); - virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code); - virtual void OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr); - virtual void OnUnloadDll(lldb::addr_t module_addr); - virtual void OnDebugString(const std::string &string); - virtual void OnDebuggerError(const Status &error, uint32_t type); - -protected: - Status DetachProcess(); - - Status LaunchProcess(ProcessLaunchInfo &launch_info, - DebugDelegateSP delegate); - - Status AttachProcess(const ProcessAttachInfo &attach_info, - DebugDelegateSP delegate); - - Status DestroyProcess(); - - Status HaltProcess(bool &caused_stop); - - Status GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info); - - Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read); - - Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, - size_t &bytes_written); - - Status AllocateMemory(size_t size, uint32_t permissions, lldb::addr_t &addr); - - Status DeallocateMemory(lldb::addr_t addr); - - lldb::pid_t GetDebuggedProcessId() const; - - Status WaitForDebuggerConnection(DebuggerThreadSP debugger, - HostProcess &process); - -protected: - llvm::sys::Mutex m_mutex; - std::unique_ptr<ProcessWindowsData> m_session_data; -}; - -} // namespace lldb_private - -#endif // #ifndef liblldb_ProcessDebugger_h_ Modified: lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp?rev=365371&r1=365370&r2=365371&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp (original) +++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp Mon Jul 8 11:53:32 2019 @@ -70,10 +70,46 @@ std::string GetProcessExecutableName(DWO } return file_name; } + +DWORD ConvertLldbToWinApiProtect(uint32_t protect) { + // We also can process a read / write permissions here, but if the debugger + // will make later a write into the allocated memory, it will fail. To get + // around it is possible inside DoWriteMemory to remember memory permissions, + // allow write, write and restore permissions, but for now we process only + // the executable permission. + // + // TODO: Process permissions other than executable + if (protect & ePermissionsExecutable) + return PAGE_EXECUTE_READWRITE; + + return PAGE_READWRITE; +} + } // 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); } + + Status 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 *) { @@ -156,41 +192,159 @@ Status ProcessWindows::DisableBreakpoint } Status ProcessWindows::DoDetach(bool keep_stopped) { - Status error; Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - StateType private_state = GetPrivateState(); + 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) { + LLDB_LOG(log, "state = {0}, but there is no active session.", + private_state); + return Status(); + } + + debugger_thread = m_session_data->m_debugger; + } + + Status error; if (private_state != eStateExited && private_state != eStateDetached) { - error = DetachProcess(); - if (error.Success()) + LLDB_LOG(log, "detaching from process {0} while state = {1}.", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), + private_state); + error = debugger_thread->StopDebugging(false); + if (error.Success()) { SetPrivateState(eStateDetached); - else - LLDB_LOG(log, "Detaching process error: {0}", error); + } + + // 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 { - error.SetErrorStringWithFormat("error: process {0} in state = {1}, but " - "cannot detach it in this state.", - GetID(), private_state); - LLDB_LOG(log, "error: {0}", error); + LLDB_LOG( + log, + "error: process {0} in state = {1}, but cannot destroy in this state.", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), + private_state); } + return error; } Status ProcessWindows::DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) { - Status error; + // 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. + + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); + Status result; + + FileSpec working_dir = launch_info.GetWorkingDirectory(); + namespace fs = llvm::sys::fs; + if (working_dir) { + FileSystem::Instance().Resolve(working_dir); + if (!FileSystem::Instance().IsDirectory(working_dir)) { + result.SetErrorStringWithFormat("No such file or directory: %s", + working_dir.GetCString()); + return 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()); + + LLDB_LOG(log, "error: {0}", message); + return result; + } + + bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); + m_session_data.reset(new ProcessWindowsData(stop_at_entry)); + DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - error = LaunchProcess(launch_info, delegate); - if (error.Success()) - SetID(launch_info.GetProcessID()); - return error; + 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()) { + LLDB_LOG(log, "failed launching '{0}'. {1}", + launch_info.GetExecutableFile().GetPath(), result); + return result; + } + + HostProcess process; + Status error = WaitForDebuggerConnection(debugger, process); + if (error.Fail()) { + LLDB_LOG(log, "failed launching '{0}'. {1}", + launch_info.GetExecutableFile().GetPath(), error); + return error; + } + + LLDB_LOG(log, "successfully launched '{0}'", + launch_info.GetExecutableFile().GetPath()); + + // 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; } Status ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid, const ProcessAttachInfo &attach_info) { + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); + m_session_data.reset( + new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); + DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - Status error = AttachProcess(attach_info, delegate); - if (error.Success()) - SetID(GetDebuggedProcessId()); + DebuggerThreadSP debugger(new DebuggerThread(delegate)); + + m_session_data->m_debugger = debugger; + + DWORD process_id = static_cast<DWORD>(pid); + Status error = debugger->DebugAttach(process_id, attach_info); + if (error.Fail()) { + LLDB_LOG( + log, + "encountered an error occurred initiating the asynchronous attach. {0}", + error); + return error; + } + + HostProcess process; + error = WaitForDebuggerConnection(debugger, process); + if (error.Fail()) { + LLDB_LOG(log, + "encountered an error waiting for the debugger to connect. {0}", + error); + return error; + } + + LLDB_LOG(log, "successfully attached to process with pid={0}", 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; } @@ -246,25 +400,63 @@ Status ProcessWindows::DoResume() { } Status ProcessWindows::DoDestroy() { - Status error; Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - StateType private_state = GetPrivateState(); - if (private_state != eStateExited && private_state != eStateDetached) - return DestroyProcess(); - else { - error.SetErrorStringWithFormat( - "cannot destroy process {0} while state = {1}", GetID(), private_state); - LLDB_LOG(log, "error: {0}", error); + 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) { + LLDB_LOG(log, "warning: state = {0}, but there is no active session.", + private_state); + return Status(); + } + + debugger_thread = m_session_data->m_debugger; } + + Status error; + if (private_state != eStateExited && private_state != eStateDetached) { + LLDB_LOG(log, "Shutting down process {0} while state = {1}.", + 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 { + LLDB_LOG(log, "cannot destroy process {0} while state = {1}", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), + private_state); + } + return error; } Status ProcessWindows::DoHalt(bool &caused_stop) { + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); + Status error; StateType state = GetPrivateState(); - if (state != eStateStopped) - return HaltProcess(caused_stop); - caused_stop = false; - return Status(); + 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); + LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error); + } + } + return error; } void ProcessWindows::DidLaunch() { @@ -537,32 +729,198 @@ bool ProcessWindows::IsAlive() { size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error) { - size_t bytes_read = 0; - error = ProcessDebugger::ReadMemory(vm_addr, buf, size, bytes_read); + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); + llvm::sys::ScopedLock lock(m_mutex); + + if (!m_session_data) + return 0; + + LLDB_LOG(log, "attempting to read {0} bytes from address {1:x}", 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)) { + // Reading from the process can fail for a number of reasons - set the + // error code and make sure that the number of bytes read is set back to 0 + // because in some scenarios the value of bytes_read returned from the API + // is garbage. + error.SetError(GetLastError(), eErrorTypeWin32); + LLDB_LOG(log, "reading failed with error: {0}", error); + bytes_read = 0; + } return bytes_read; } size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Status &error) { - size_t bytes_written = 0; - error = ProcessDebugger::WriteMemory(vm_addr, buf, size, bytes_written); + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); + llvm::sys::ScopedLock lock(m_mutex); + LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size, + vm_addr); + + if (!m_session_data) { + LLDB_LOG(log, "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); + LLDB_LOG(log, "writing failed with error: {0}", error); + } return bytes_written; } lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions, Status &error) { - lldb::addr_t vm_addr = LLDB_INVALID_ADDRESS; - error = ProcessDebugger::AllocateMemory(size, permissions, vm_addr); - return vm_addr; + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); + llvm::sys::ScopedLock lock(m_mutex); + LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size, + permissions); + + if (!m_session_data) { + LLDB_LOG(log, "cannot allocate, there is no active debugger connection."); + error.SetErrorString( + "cannot allocate, there is no active debugger connection"); + return LLDB_INVALID_ADDRESS; + } + + HostProcess process = m_session_data->m_debugger->GetProcess(); + lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); + auto protect = ConvertLldbToWinApiProtect(permissions); + auto result = VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect); + if (!result) { + error.SetError(GetLastError(), eErrorTypeWin32); + LLDB_LOG(log, "allocating failed with error: {0}", error); + return LLDB_INVALID_ADDRESS; + } + + return reinterpret_cast<addr_t>(result); } Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) { - return ProcessDebugger::DeallocateMemory(ptr); + Status result; + + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); + llvm::sys::ScopedLock lock(m_mutex); + LLDB_LOG(log, "attempting to deallocate bytes at address {0}", ptr); + + if (!m_session_data) { + LLDB_LOG(log, "cannot deallocate, there is no active debugger connection."); + result.SetErrorString( + "cannot deallocate, there is no active debugger connection"); + return result; + } + + HostProcess process = m_session_data->m_debugger->GetProcess(); + lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); + if (!VirtualFreeEx(handle, reinterpret_cast<LPVOID>(ptr), 0, MEM_RELEASE)) { + result.SetError(GetLastError(), eErrorTypeWin32); + LLDB_LOG(log, "deallocating failed with error: {0}", result); + return result; + } + + return result; } Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info) { - return ProcessDebugger::GetMemoryRegionInfo(vm_addr, info); + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); + Status error; + llvm::sys::ScopedLock lock(m_mutex); + info.Clear(); + + if (!m_session_data) { + error.SetErrorString( + "GetMemoryRegionInfo called with no debugging session."); + LLDB_LOG(log, "error: {0}", error); + 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."); + LLDB_LOG(log, "error: {0}", error); + return error; + } + + LLDB_LOG(log, "getting info for address {0:x}", 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); + LLDB_LOG(log, + "VirtualQueryEx returned error {0} while getting memory " + "region info for address {1:x}", + error, 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); + LLDB_LOGV(log, + "Memory region info for address {0}: readable={1}, " + "executable={2}, writable={3}", + vm_addr, info.GetReadable(), info.GetExecutable(), + info.GetWritable()); + return error; } lldb::addr_t ProcessWindows::GetImageInfoAddress() { @@ -777,4 +1135,41 @@ void ProcessWindows::OnDebuggerError(con return; } } + +Status ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger, + HostProcess &process) { + Status result; + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS | + WINDOWS_LOG_BREAKPOINTS); + LLDB_LOG(log, "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) { + LLDB_LOG(log, "hit loader breakpoint, returning."); + + process = debugger->GetProcess(); + return m_session_data->m_launch_error; + } else + return Status(::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. +bool ProcessWindows::IsPageReadable(uint32_t protect) { + return (protect & PAGE_NOACCESS) == 0; +} + +bool ProcessWindows::IsPageWritable(uint32_t protect) { + return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | + PAGE_READWRITE | PAGE_WRITECOPY)) != 0; +} + +bool ProcessWindows::IsPageExecutable(uint32_t protect) { + return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | + PAGE_EXECUTE_WRITECOPY)) != 0; +} + } // namespace lldb_private Modified: lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h?rev=365371&r1=365370&r2=365371&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h (original) +++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h Mon Jul 8 11:53:32 2019 @@ -13,14 +13,17 @@ #include "lldb/Utility/Status.h" #include "lldb/lldb-forward.h" +#include "llvm/Support/Mutex.h" + +#include "IDebugDelegate.h" #include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h" -#include "ProcessDebugger.h" namespace lldb_private { class HostProcess; +class ProcessWindowsData; -class ProcessWindows : public Process, public ProcessDebugger { +class ProcessWindows : public Process, public IDebugDelegate { public: // Static functions. static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, @@ -98,7 +101,19 @@ public: void OnUnloadDll(lldb::addr_t module_addr) override; void OnDebugString(const std::string &string) override; void OnDebuggerError(const Status &error, uint32_t type) override; + +private: + Status 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; }; -} // namespace lldb_private +} #endif // liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_ _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits