[Lldb-commits] [lldb] r365592 - Try again to move common functionality from ProcessWindows into ProcessDebugger

Aaron Smith via lldb-commits lldb-commits at lists.llvm.org
Tue Jul 9 20:34:57 PDT 2019


Author: asmith
Date: Tue Jul  9 20:34:57 2019
New Revision: 365592

URL: http://llvm.org/viewvc/llvm-project?rev=365592&view=rev
Log:
Try again to move common functionality from ProcessWindows into ProcessDebugger

This reverts commit ed499a36b67cf46cbf66052cfe374c80a595f1c1 and addresses
a problem causing a Windows build bot to hang.


Added:
    lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
    lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h
Modified:
    lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
    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/ObjectFile/ELF/ELFHeader.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp?rev=365592&r1=365591&r2=365592&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp Tue Jul  9 20:34:57 2019
@@ -180,6 +180,9 @@ unsigned ELFHeader::GetRelocationJumpSlo
   default:
     assert(false && "architecture not supported");
     break;
+  case EM_CASCADE:
+    slot = R_CASCADE_JUMP_SLOT;
+    break;
   case EM_PPC:
     slot = R_PPC_JMP_SLOT;
     break;

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=365592&r1=365591&r2=365592&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/Common/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/Windows/Common/CMakeLists.txt Tue Jul  9 20:34:57 2019
@@ -2,6 +2,7 @@
 add_lldb_library(lldbPluginProcessWindowsCommon PLUGIN
   DebuggerThread.cpp
   LocalDebugDelegate.cpp
+  ProcessDebugger.cpp
   ProcessWindows.cpp
   ProcessWindowsLog.cpp
   RegisterContextWindows.cpp

Added: 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=365592&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp Tue Jul  9 20:34:57 2019
@@ -0,0 +1,582 @@
+//===-- 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(lldb::pid_t pid,
+                                      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>(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.
+
+  return error;
+}
+
+Status ProcessDebugger::DestroyProcess(const lldb::StateType state) {
+  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: state = {0}, but there is no active session.",
+               state);
+      return Status();
+    }
+
+    debugger_thread = m_session_data->m_debugger;
+  }
+
+  Status error;
+  if (state != eStateExited && state != eStateDetached) {
+    LLDB_LOG(
+        log, "Shutting down process {0}.",
+        debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
+    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 {
+    error.SetErrorStringWithFormat("cannot destroy process %" PRIx64
+                                   " while state = %d",
+                                   GetDebuggedProcessId(), state);
+    LLDB_LOG(log, "error: {0}", error);
+  }
+  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

Added: 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=365592&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h (added)
+++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h Tue Jul  9 20:34:57 2019
@@ -0,0 +1,101 @@
+//===-- 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(lldb::pid_t pid, const ProcessAttachInfo &attach_info,
+                       DebugDelegateSP delegate);
+
+  Status DestroyProcess(lldb::StateType process_state);
+
+  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=365592&r1=365591&r2=365592&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp Tue Jul  9 20:34:57 2019
@@ -70,46 +70,10 @@ 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 *) {
@@ -192,159 +156,41 @@ Status ProcessWindows::DisableBreakpoint
 }
 
 Status ProcessWindows::DoDetach(bool keep_stopped) {
-  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
-  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;
+  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
+  StateType private_state = GetPrivateState();
   if (private_state != eStateExited && private_state != eStateDetached) {
-    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()) {
+    error = DetachProcess();
+    if (error.Success())
       SetPrivateState(eStateDetached);
-    }
-
-    // By the time StopDebugging returns, there is no more debugger thread, so
-    // we can be assured that no other thread will race for the session data.
-    m_session_data.reset();
+    else
+      LLDB_LOG(log, "Detaching process error: {0}", error);
   } else {
-    LLDB_LOG(
-        log,
-        "error: process {0} in state = {1}, but cannot destroy in this state.",
-        debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
-        private_state);
+    error.SetErrorStringWithFormat("error: process {0} in state = {1}, but "
+                                   "cannot detach it in this state.",
+                                   GetID(), private_state);
+    LLDB_LOG(log, "error: {0}", error);
   }
-
   return error;
 }
 
 Status ProcessWindows::DoLaunch(Module *exe_module,
                                 ProcessLaunchInfo &launch_info) {
-  // Even though m_session_data is accessed here, it is before a debugger
-  // thread has been kicked off.  So there's no race conditions, and it
-  // shouldn't be necessary to acquire the mutex.
-
-  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));
-
+  Status error;
   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
-  m_session_data->m_debugger.reset(new DebuggerThread(delegate));
-  DebuggerThreadSP debugger = m_session_data->m_debugger;
-
-  // Kick off the DebugLaunch asynchronously and wait for it to complete.
-  result = debugger->DebugLaunch(launch_info);
-  if (result.Fail()) {
-    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;
+  error = LaunchProcess(launch_info, delegate);
+  if (error.Success())
+    SetID(launch_info.GetProcessID());
+  return error;
 }
 
 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()));
-  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());
+  Status error = AttachProcess(pid, attach_info, delegate);
+  if (error.Success())
+    SetID(GetDebuggedProcessId());
   return error;
 }
 
@@ -400,63 +246,16 @@ Status ProcessWindows::DoResume() {
 }
 
 Status ProcessWindows::DoDestroy() {
-  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
-  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;
+  StateType private_state = GetPrivateState();
+  return DestroyProcess(private_state);
 }
 
 Status ProcessWindows::DoHalt(bool &caused_stop) {
-  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
-  Status error;
   StateType state = GetPrivateState();
-  if (state == eStateStopped)
-    caused_stop = false;
-  else {
-    llvm::sys::ScopedLock lock(m_mutex);
-    caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess()
-                                          .GetNativeProcess()
-                                          .GetSystemHandle());
-    if (!caused_stop) {
-      error.SetError(::GetLastError(), eErrorTypeWin32);
-      LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error);
-    }
-  }
-  return error;
+  if (state != eStateStopped)
+    return HaltProcess(caused_stop);
+  caused_stop = false;
+  return Status();
 }
 
 void ProcessWindows::DidLaunch() {
@@ -729,198 +528,32 @@ bool ProcessWindows::IsAlive() {
 
 size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf,
                                     size_t size, Status &error) {
-  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;
-  }
+  size_t bytes_read = 0;
+  error = ProcessDebugger::ReadMemory(vm_addr, buf, size, bytes_read);
   return bytes_read;
 }
 
 size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
                                      size_t size, Status &error) {
-  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);
-  }
+  size_t bytes_written = 0;
+  error = ProcessDebugger::WriteMemory(vm_addr, buf, size, bytes_written);
   return bytes_written;
 }
 
 lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions,
                                               Status &error) {
-  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);
+  lldb::addr_t vm_addr = LLDB_INVALID_ADDRESS;
+  error = ProcessDebugger::AllocateMemory(size, permissions, vm_addr);
+  return vm_addr;
 }
 
 Status ProcessWindows::DoDeallocateMemory(lldb::addr_t 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;
+  return ProcessDebugger::DeallocateMemory(ptr);
 }
 
 Status ProcessWindows::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;
+  return ProcessDebugger::GetMemoryRegionInfo(vm_addr, info);
 }
 
 lldb::addr_t ProcessWindows::GetImageInfoAddress() {
@@ -963,6 +596,9 @@ void ProcessWindows::OnExitProcess(uint3
     Status error(exit_code, eErrorTypeWin32);
     OnDebuggerError(error, 0);
   }
+
+  // Reset the session.
+  m_session_data.reset();
 }
 
 void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
@@ -1135,41 +771,4 @@ 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=365592&r1=365591&r2=365592&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h (original)
+++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h Tue Jul  9 20:34:57 2019
@@ -13,17 +13,14 @@
 #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 IDebugDelegate {
+class ProcessWindows : public Process, public ProcessDebugger {
 public:
   // Static functions.
   static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
@@ -101,19 +98,7 @@ 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_




More information about the lldb-commits mailing list