Revert "Move common functionality from processwindows into processdebugger"
authorStella Stamenova <stilis@microsoft.com>
Mon, 8 Jul 2019 18:53:32 +0000 (18:53 +0000)
committerStella Stamenova <stilis@microsoft.com>
Mon, 8 Jul 2019 18:53:32 +0000 (18:53 +0000)
This reverts commit 9c01eaff6aa3f59d91530f47b85bb470377a7780.

The changes in this commit are causing several of the LLDB tests to hang and/or timeout.

llvm-svn: 365371

lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt
lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp [deleted file]
lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h [deleted file]
lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h

index 68486c1..c63df5f 100644 (file)
@@ -2,7 +2,6 @@
 add_lldb_library(lldbPluginProcessWindowsCommon PLUGIN
   DebuggerThread.cpp
   LocalDebugDelegate.cpp
-  ProcessDebugger.cpp
   ProcessWindows.cpp
   ProcessWindowsLog.cpp
   RegisterContextWindows.cpp
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
deleted file mode 100644 (file)
index a79250b..0000000
+++ /dev/null
@@ -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
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h
deleted file mode 100644 (file)
index b291ab5..0000000
+++ /dev/null
@@ -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_
index f9b58a1..f18cdfb 100644 (file)
@@ -70,10 +70,46 @@ std::string GetProcessExecutableName(DWORD pid) {
   }
   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::DisableBreakpointSite(BreakpointSite *bp_site) {
 }
 
 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(const Status &error, uint32_t type) {
     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
index 8d5134a..1b1f173 100644 (file)
 #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_