forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			603 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			603 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- NativeProcessWindows.cpp ------------------------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "lldb/Host/windows/windows.h"
 | 
						|
#include <psapi.h>
 | 
						|
 | 
						|
#include "NativeProcessWindows.h"
 | 
						|
#include "NativeThreadWindows.h"
 | 
						|
#include "lldb/Host/FileSystem.h"
 | 
						|
#include "lldb/Host/HostNativeProcessBase.h"
 | 
						|
#include "lldb/Host/HostProcess.h"
 | 
						|
#include "lldb/Host/ProcessLaunchInfo.h"
 | 
						|
#include "lldb/Host/windows/AutoHandle.h"
 | 
						|
#include "lldb/Host/windows/HostThreadWindows.h"
 | 
						|
#include "lldb/Host/windows/ProcessLauncherWindows.h"
 | 
						|
#include "lldb/Target/MemoryRegionInfo.h"
 | 
						|
#include "lldb/Target/Process.h"
 | 
						|
#include "lldb/Utility/State.h"
 | 
						|
#include "llvm/Support/ConvertUTF.h"
 | 
						|
#include "llvm/Support/Errc.h"
 | 
						|
#include "llvm/Support/Error.h"
 | 
						|
#include "llvm/Support/Format.h"
 | 
						|
#include "llvm/Support/Threading.h"
 | 
						|
#include "llvm/Support/raw_ostream.h"
 | 
						|
 | 
						|
#include "DebuggerThread.h"
 | 
						|
#include "ExceptionRecord.h"
 | 
						|
#include "ProcessWindowsLog.h"
 | 
						|
 | 
						|
#include <tlhelp32.h>
 | 
						|
 | 
						|
#pragma warning(disable : 4005)
 | 
						|
#include "winternl.h"
 | 
						|
#include <ntstatus.h>
 | 
						|
 | 
						|
using namespace lldb;
 | 
						|
using namespace lldb_private;
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
namespace lldb_private {
 | 
						|
 | 
						|
NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
 | 
						|
                                           NativeDelegate &delegate,
 | 
						|
                                           llvm::Error &E)
 | 
						|
    : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID,
 | 
						|
                            launch_info.GetPTY().ReleaseMasterFileDescriptor(),
 | 
						|
                            delegate),
 | 
						|
      ProcessDebugger(), m_arch(launch_info.GetArchitecture()) {
 | 
						|
  ErrorAsOutParameter EOut(&E);
 | 
						|
  DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));
 | 
						|
  E = LaunchProcess(launch_info, delegate_sp).ToError();
 | 
						|
  if (E)
 | 
						|
    return;
 | 
						|
 | 
						|
  SetID(GetDebuggedProcessId());
 | 
						|
}
 | 
						|
 | 
						|
NativeProcessWindows::NativeProcessWindows(lldb::pid_t pid, int terminal_fd,
 | 
						|
                                           NativeDelegate &delegate,
 | 
						|
                                           llvm::Error &E)
 | 
						|
    : NativeProcessProtocol(pid, terminal_fd, delegate), ProcessDebugger() {
 | 
						|
  ErrorAsOutParameter EOut(&E);
 | 
						|
  DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));
 | 
						|
  ProcessAttachInfo attach_info;
 | 
						|
  attach_info.SetProcessID(pid);
 | 
						|
  E = AttachProcess(pid, attach_info, delegate_sp).ToError();
 | 
						|
  if (E)
 | 
						|
    return;
 | 
						|
 | 
						|
  SetID(GetDebuggedProcessId());
 | 
						|
 | 
						|
  ProcessInstanceInfo info;
 | 
						|
  if (!Host::GetProcessInfo(pid, info)) {
 | 
						|
    E = createStringError(inconvertibleErrorCode(),
 | 
						|
                          "Cannot get process information");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  m_arch = info.GetArchitecture();
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) {
 | 
						|
  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
 | 
						|
  Status error;
 | 
						|
  llvm::sys::ScopedLock lock(m_mutex);
 | 
						|
 | 
						|
  StateType state = GetState();
 | 
						|
  if (state == eStateStopped || state == eStateCrashed) {
 | 
						|
    LLDB_LOG(log, "process {0} is in state {1}.  Resuming...",
 | 
						|
             GetDebuggedProcessId(), state);
 | 
						|
    LLDB_LOG(log, "resuming {0} threads.", m_threads.size());
 | 
						|
 | 
						|
    bool failed = false;
 | 
						|
    for (uint32_t i = 0; i < m_threads.size(); ++i) {
 | 
						|
      auto thread = static_cast<NativeThreadWindows *>(m_threads[i].get());
 | 
						|
      const ResumeAction *const action =
 | 
						|
          resume_actions.GetActionForThread(thread->GetID(), true);
 | 
						|
      if (action == nullptr)
 | 
						|
        continue;
 | 
						|
 | 
						|
      switch (action->state) {
 | 
						|
      case eStateRunning:
 | 
						|
      case eStateStepping: {
 | 
						|
        Status result = thread->DoResume(action->state);
 | 
						|
        if (result.Fail()) {
 | 
						|
          failed = true;
 | 
						|
          LLDB_LOG(log,
 | 
						|
                   "Trying to resume thread at index {0}, but failed with "
 | 
						|
                   "error {1}.",
 | 
						|
                   i, result);
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      case eStateSuspended:
 | 
						|
      case eStateStopped:
 | 
						|
        llvm_unreachable("Unexpected state");
 | 
						|
 | 
						|
      default:
 | 
						|
        return Status(
 | 
						|
            "NativeProcessWindows::%s (): unexpected state %s specified "
 | 
						|
            "for pid %" PRIu64 ", tid %" PRIu64,
 | 
						|
            __FUNCTION__, StateAsCString(action->state), GetID(),
 | 
						|
            thread->GetID());
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (failed) {
 | 
						|
      error.SetErrorString("NativeProcessWindows::DoResume failed");
 | 
						|
    } else {
 | 
						|
      SetState(eStateRunning);
 | 
						|
    }
 | 
						|
 | 
						|
    // Resume the debug loop.
 | 
						|
    ExceptionRecordSP active_exception =
 | 
						|
        m_session_data->m_debugger->GetActiveException().lock();
 | 
						|
    if (active_exception) {
 | 
						|
      // Resume the process and continue processing debug events.  Mask the
 | 
						|
      // exception so that from the process's view, there is no indication that
 | 
						|
      // anything happened.
 | 
						|
      m_session_data->m_debugger->ContinueAsyncException(
 | 
						|
          ExceptionResult::MaskException);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    LLDB_LOG(log, "error: process {0} is in state {1}.  Returning...",
 | 
						|
             GetDebuggedProcessId(), GetState());
 | 
						|
  }
 | 
						|
 | 
						|
  return error;
 | 
						|
}
 | 
						|
 | 
						|
NativeThreadWindows *
 | 
						|
NativeProcessWindows::GetThreadByID(lldb::tid_t thread_id) {
 | 
						|
  return static_cast<NativeThreadWindows *>(
 | 
						|
      NativeProcessProtocol::GetThreadByID(thread_id));
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::Halt() {
 | 
						|
  bool caused_stop = false;
 | 
						|
  StateType state = GetState();
 | 
						|
  if (state != eStateStopped)
 | 
						|
    return HaltProcess(caused_stop);
 | 
						|
  return Status();
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::Detach() {
 | 
						|
  Status error;
 | 
						|
  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
 | 
						|
  StateType state = GetState();
 | 
						|
  if (state != eStateExited && state != eStateDetached) {
 | 
						|
    error = DetachProcess();
 | 
						|
    if (error.Success())
 | 
						|
      SetState(eStateDetached);
 | 
						|
    else
 | 
						|
      LLDB_LOG(log, "Detaching process error: {0}", error);
 | 
						|
  } else {
 | 
						|
    error.SetErrorStringWithFormatv("error: process {0} in state = {1}, but "
 | 
						|
                                    "cannot detach it in this state.",
 | 
						|
                                    GetID(), state);
 | 
						|
    LLDB_LOG(log, "error: {0}", error);
 | 
						|
  }
 | 
						|
  return error;
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::Signal(int signo) {
 | 
						|
  Status error;
 | 
						|
  error.SetErrorString("Windows does not support sending signals to processes");
 | 
						|
  return error;
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::Interrupt() { return Halt(); }
 | 
						|
 | 
						|
Status NativeProcessWindows::Kill() {
 | 
						|
  StateType state = GetState();
 | 
						|
  return DestroyProcess(state);
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::IgnoreSignals(llvm::ArrayRef<int> signals) {
 | 
						|
  return Status();
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::GetMemoryRegionInfo(lldb::addr_t load_addr,
 | 
						|
                                                 MemoryRegionInfo &range_info) {
 | 
						|
  return ProcessDebugger::GetMemoryRegionInfo(load_addr, range_info);
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::ReadMemory(lldb::addr_t addr, void *buf,
 | 
						|
                                        size_t size, size_t &bytes_read) {
 | 
						|
  return ProcessDebugger::ReadMemory(addr, buf, size, bytes_read);
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::WriteMemory(lldb::addr_t addr, const void *buf,
 | 
						|
                                         size_t size, size_t &bytes_written) {
 | 
						|
  return ProcessDebugger::WriteMemory(addr, buf, size, bytes_written);
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions,
 | 
						|
                                            lldb::addr_t &addr) {
 | 
						|
  return ProcessDebugger::AllocateMemory(size, permissions, addr);
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) {
 | 
						|
  return ProcessDebugger::DeallocateMemory(addr);
 | 
						|
}
 | 
						|
 | 
						|
lldb::addr_t NativeProcessWindows::GetSharedLibraryInfoAddress() { return 0; }
 | 
						|
 | 
						|
bool NativeProcessWindows::IsAlive() const {
 | 
						|
  StateType state = GetState();
 | 
						|
  switch (state) {
 | 
						|
  case eStateCrashed:
 | 
						|
  case eStateDetached:
 | 
						|
  case eStateExited:
 | 
						|
  case eStateInvalid:
 | 
						|
  case eStateUnloaded:
 | 
						|
    return false;
 | 
						|
  default:
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void NativeProcessWindows::SetStopReasonForThread(NativeThreadWindows &thread,
 | 
						|
                                                  lldb::StopReason reason,
 | 
						|
                                                  std::string description) {
 | 
						|
  SetCurrentThreadID(thread.GetID());
 | 
						|
 | 
						|
  ThreadStopInfo stop_info;
 | 
						|
  stop_info.reason = reason;
 | 
						|
 | 
						|
  // No signal support on Windows but required to provide a 'valid' signum.
 | 
						|
  if (reason == StopReason::eStopReasonException) {
 | 
						|
    stop_info.details.exception.type = 0;
 | 
						|
    stop_info.details.exception.data_count = 0;
 | 
						|
  } else {
 | 
						|
    stop_info.details.signal.signo = SIGTRAP;
 | 
						|
  }
 | 
						|
 | 
						|
  thread.SetStopReason(stop_info, description);
 | 
						|
}
 | 
						|
 | 
						|
void NativeProcessWindows::StopThread(lldb::tid_t thread_id,
 | 
						|
                                      lldb::StopReason reason,
 | 
						|
                                      std::string description) {
 | 
						|
  NativeThreadWindows *thread = GetThreadByID(thread_id);
 | 
						|
  if (!thread)
 | 
						|
    return;
 | 
						|
 | 
						|
  for (uint32_t i = 0; i < m_threads.size(); ++i) {
 | 
						|
    auto t = static_cast<NativeThreadWindows *>(m_threads[i].get());
 | 
						|
    Status error = t->DoStop();
 | 
						|
    if (error.Fail())
 | 
						|
      exit(1);
 | 
						|
  }
 | 
						|
  SetStopReasonForThread(*thread, reason, description);
 | 
						|
}
 | 
						|
 | 
						|
size_t NativeProcessWindows::UpdateThreads() { return m_threads.size(); }
 | 
						|
 | 
						|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
 | 
						|
NativeProcessWindows::GetAuxvData() const {
 | 
						|
  // Not available on this target.
 | 
						|
  return llvm::errc::not_supported;
 | 
						|
}
 | 
						|
 | 
						|
bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) {
 | 
						|
  auto it = m_software_breakpoints.find(addr);
 | 
						|
  if (it == m_software_breakpoints.end())
 | 
						|
    return false;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::SetBreakpoint(lldb::addr_t addr, uint32_t size,
 | 
						|
                                           bool hardware) {
 | 
						|
  if (hardware)
 | 
						|
    return SetHardwareBreakpoint(addr, size);
 | 
						|
  return SetSoftwareBreakpoint(addr, size);
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::RemoveBreakpoint(lldb::addr_t addr,
 | 
						|
                                              bool hardware) {
 | 
						|
  if (hardware)
 | 
						|
    return RemoveHardwareBreakpoint(addr);
 | 
						|
  return RemoveSoftwareBreakpoint(addr);
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::CacheLoadedModules() {
 | 
						|
  Status error;
 | 
						|
  if (!m_loaded_modules.empty())
 | 
						|
    return Status();
 | 
						|
 | 
						|
  // Retrieve loaded modules by a Target/Module free implemenation.
 | 
						|
  AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID()));
 | 
						|
  if (snapshot.IsValid()) {
 | 
						|
    MODULEENTRY32W me;
 | 
						|
    me.dwSize = sizeof(MODULEENTRY32W);
 | 
						|
    if (Module32FirstW(snapshot.get(), &me)) {
 | 
						|
      do {
 | 
						|
        std::string path;
 | 
						|
        if (!llvm::convertWideToUTF8(me.szExePath, path))
 | 
						|
          continue;
 | 
						|
 | 
						|
        FileSpec file_spec(path);
 | 
						|
        FileSystem::Instance().Resolve(file_spec);
 | 
						|
        m_loaded_modules[file_spec] = (addr_t)me.modBaseAddr;
 | 
						|
      } while (Module32Next(snapshot.get(), &me));
 | 
						|
    }
 | 
						|
 | 
						|
    if (!m_loaded_modules.empty())
 | 
						|
      return Status();
 | 
						|
  }
 | 
						|
 | 
						|
  error.SetError(::GetLastError(), lldb::ErrorType::eErrorTypeWin32);
 | 
						|
  return error;
 | 
						|
}
 | 
						|
 | 
						|
Status NativeProcessWindows::GetLoadedModuleFileSpec(const char *module_path,
 | 
						|
                                                     FileSpec &file_spec) {
 | 
						|
  Status error = CacheLoadedModules();
 | 
						|
  if (error.Fail())
 | 
						|
    return error;
 | 
						|
 | 
						|
  FileSpec module_file_spec(module_path);
 | 
						|
  FileSystem::Instance().Resolve(module_file_spec);
 | 
						|
  for (auto &it : m_loaded_modules) {
 | 
						|
    if (it.first == module_file_spec) {
 | 
						|
      file_spec = it.first;
 | 
						|
      return Status();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return Status("Module (%s) not found in process %" PRIu64 "!",
 | 
						|
                module_file_spec.GetCString(), GetID());
 | 
						|
}
 | 
						|
 | 
						|
Status
 | 
						|
NativeProcessWindows::GetFileLoadAddress(const llvm::StringRef &file_name,
 | 
						|
                                         lldb::addr_t &load_addr) {
 | 
						|
  Status error = CacheLoadedModules();
 | 
						|
  if (error.Fail())
 | 
						|
    return error;
 | 
						|
 | 
						|
  load_addr = LLDB_INVALID_ADDRESS;
 | 
						|
  FileSpec file_spec(file_name);
 | 
						|
  FileSystem::Instance().Resolve(file_spec);
 | 
						|
  for (auto &it : m_loaded_modules) {
 | 
						|
    if (it.first == file_spec) {
 | 
						|
      load_addr = it.second;
 | 
						|
      return Status();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return Status("Can't get loaded address of file (%s) in process %" PRIu64 "!",
 | 
						|
                file_spec.GetCString(), GetID());
 | 
						|
}
 | 
						|
 | 
						|
void NativeProcessWindows::OnExitProcess(uint32_t exit_code) {
 | 
						|
  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
 | 
						|
  LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
 | 
						|
 | 
						|
  ProcessDebugger::OnExitProcess(exit_code);
 | 
						|
 | 
						|
  // No signal involved.  It is just an exit event.
 | 
						|
  WaitStatus wait_status(WaitStatus::Exit, exit_code);
 | 
						|
  SetExitStatus(wait_status, true);
 | 
						|
 | 
						|
  // Notify the native delegate.
 | 
						|
  SetState(eStateExited, true);
 | 
						|
}
 | 
						|
 | 
						|
void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
 | 
						|
  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
 | 
						|
  LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}",
 | 
						|
           GetDebuggedProcessId(), image_base);
 | 
						|
 | 
						|
  // This is the earliest chance we can resolve the process ID and
 | 
						|
  // architecutre if we don't know them yet.
 | 
						|
  if (GetID() == LLDB_INVALID_PROCESS_ID)
 | 
						|
    SetID(GetDebuggedProcessId());
 | 
						|
 | 
						|
  if (GetArchitecture().GetMachine() == llvm::Triple::UnknownArch) {
 | 
						|
    ProcessInstanceInfo process_info;
 | 
						|
    if (!Host::GetProcessInfo(GetDebuggedProcessId(), process_info)) {
 | 
						|
      LLDB_LOG(log, "Cannot get process information during debugger connecting "
 | 
						|
                    "to process");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    SetArchitecture(process_info.GetArchitecture());
 | 
						|
  }
 | 
						|
 | 
						|
  // The very first one shall always be the main thread.
 | 
						|
  assert(m_threads.empty());
 | 
						|
  m_threads.push_back(std::make_unique<NativeThreadWindows>(
 | 
						|
      *this, m_session_data->m_debugger->GetMainThread()));
 | 
						|
}
 | 
						|
 | 
						|
ExceptionResult
 | 
						|
NativeProcessWindows::OnDebugException(bool first_chance,
 | 
						|
                                       const ExceptionRecord &record) {
 | 
						|
  Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
 | 
						|
  llvm::sys::ScopedLock lock(m_mutex);
 | 
						|
 | 
						|
  // Let the debugger establish the internal status.
 | 
						|
  ProcessDebugger::OnDebugException(first_chance, record);
 | 
						|
 | 
						|
  static bool initial_stop = false;
 | 
						|
  if (!first_chance) {
 | 
						|
    SetState(eStateStopped, false);
 | 
						|
  }
 | 
						|
 | 
						|
  ExceptionResult result = ExceptionResult::SendToApplication;
 | 
						|
  switch (record.GetExceptionCode()) {
 | 
						|
  case DWORD(STATUS_SINGLE_STEP):
 | 
						|
  case STATUS_WX86_SINGLE_STEP: {
 | 
						|
    uint32_t wp_id = LLDB_INVALID_INDEX32;
 | 
						|
    if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID())) {
 | 
						|
      NativeRegisterContextWindows ®_ctx = thread->GetRegisterContext();
 | 
						|
      Status error =
 | 
						|
          reg_ctx.GetWatchpointHitIndex(wp_id, record.GetExceptionAddress());
 | 
						|
      if (error.Fail())
 | 
						|
        LLDB_LOG(log,
 | 
						|
                 "received error while checking for watchpoint hits, pid = "
 | 
						|
                 "{0}, error = {1}",
 | 
						|
                 thread->GetID(), error);
 | 
						|
      if (wp_id != LLDB_INVALID_INDEX32) {
 | 
						|
        addr_t wp_addr = reg_ctx.GetWatchpointAddress(wp_id);
 | 
						|
        addr_t wp_hit_addr = reg_ctx.GetWatchpointHitAddress(wp_id);
 | 
						|
        std::string desc =
 | 
						|
            formatv("{0} {1} {2}", wp_addr, wp_id, wp_hit_addr).str();
 | 
						|
        StopThread(record.GetThreadID(), StopReason::eStopReasonWatchpoint,
 | 
						|
                   desc);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (wp_id == LLDB_INVALID_INDEX32)
 | 
						|
      StopThread(record.GetThreadID(), StopReason::eStopReasonTrace);
 | 
						|
 | 
						|
    SetState(eStateStopped, true);
 | 
						|
 | 
						|
    // Continue the debugger.
 | 
						|
    return ExceptionResult::MaskException;
 | 
						|
  }
 | 
						|
  case DWORD(STATUS_BREAKPOINT):
 | 
						|
  case STATUS_WX86_BREAKPOINT:
 | 
						|
    if (FindSoftwareBreakpoint(record.GetExceptionAddress())) {
 | 
						|
      LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
 | 
						|
               record.GetExceptionAddress());
 | 
						|
 | 
						|
      StopThread(record.GetThreadID(), StopReason::eStopReasonBreakpoint);
 | 
						|
 | 
						|
      if (NativeThreadWindows *stop_thread =
 | 
						|
              GetThreadByID(record.GetThreadID())) {
 | 
						|
        auto ®ister_context = stop_thread->GetRegisterContext();
 | 
						|
        // The current EIP is AFTER the BP opcode, which is one byte '0xCC'
 | 
						|
        uint64_t pc = register_context.GetPC() - 1;
 | 
						|
        register_context.SetPC(pc);
 | 
						|
      }
 | 
						|
 | 
						|
      SetState(eStateStopped, true);
 | 
						|
      return ExceptionResult::MaskException;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!initial_stop) {
 | 
						|
      initial_stop = true;
 | 
						|
      LLDB_LOG(log,
 | 
						|
               "Hit loader breakpoint at address {0:x}, setting initial stop "
 | 
						|
               "event.",
 | 
						|
               record.GetExceptionAddress());
 | 
						|
 | 
						|
      // We are required to report the reason for the first stop after
 | 
						|
      // launching or being attached.
 | 
						|
      if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID()))
 | 
						|
        SetStopReasonForThread(*thread, StopReason::eStopReasonBreakpoint);
 | 
						|
 | 
						|
      // Do not notify the native delegate (e.g. llgs) since at this moment
 | 
						|
      // the program hasn't returned from Factory::Launch() and the delegate
 | 
						|
      // might not have an valid native process to operate on.
 | 
						|
      SetState(eStateStopped, false);
 | 
						|
 | 
						|
      // Hit the initial stop. Continue the application.
 | 
						|
      return ExceptionResult::BreakInDebugger;
 | 
						|
    }
 | 
						|
 | 
						|
    LLVM_FALLTHROUGH;
 | 
						|
  default:
 | 
						|
    LLDB_LOG(log,
 | 
						|
             "Debugger thread reported exception {0:x} at address {1:x} "
 | 
						|
             "(first_chance={2})",
 | 
						|
             record.GetExceptionCode(), record.GetExceptionAddress(),
 | 
						|
             first_chance);
 | 
						|
 | 
						|
    {
 | 
						|
      std::string desc;
 | 
						|
      llvm::raw_string_ostream desc_stream(desc);
 | 
						|
      desc_stream << "Exception "
 | 
						|
                  << llvm::format_hex(record.GetExceptionCode(), 8)
 | 
						|
                  << " encountered at address "
 | 
						|
                  << llvm::format_hex(record.GetExceptionAddress(), 8);
 | 
						|
      StopThread(record.GetThreadID(), StopReason::eStopReasonException,
 | 
						|
                 desc_stream.str().c_str());
 | 
						|
 | 
						|
      SetState(eStateStopped, true);
 | 
						|
    }
 | 
						|
 | 
						|
    // For non-breakpoints, give the application a chance to handle the
 | 
						|
    // exception first.
 | 
						|
    if (first_chance)
 | 
						|
      result = ExceptionResult::SendToApplication;
 | 
						|
    else
 | 
						|
      result = ExceptionResult::BreakInDebugger;
 | 
						|
  }
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) {
 | 
						|
  llvm::sys::ScopedLock lock(m_mutex);
 | 
						|
 | 
						|
  auto thread = std::make_unique<NativeThreadWindows>(*this, new_thread);
 | 
						|
  thread->GetRegisterContext().ClearAllHardwareWatchpoints();
 | 
						|
  for (const auto &pair : GetWatchpointMap()) {
 | 
						|
    const NativeWatchpoint &wp = pair.second;
 | 
						|
    thread->SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags,
 | 
						|
                          wp.m_hardware);
 | 
						|
  }
 | 
						|
 | 
						|
  m_threads.push_back(std::move(thread));
 | 
						|
}
 | 
						|
 | 
						|
void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id,
 | 
						|
                                        uint32_t exit_code) {
 | 
						|
  llvm::sys::ScopedLock lock(m_mutex);
 | 
						|
  NativeThreadWindows *thread = GetThreadByID(thread_id);
 | 
						|
  if (!thread)
 | 
						|
    return;
 | 
						|
 | 
						|
  for (auto t = m_threads.begin(); t != m_threads.end();) {
 | 
						|
    if ((*t)->GetID() == thread_id) {
 | 
						|
      t = m_threads.erase(t);
 | 
						|
    } else {
 | 
						|
      ++t;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
 | 
						|
                                     lldb::addr_t module_addr) {
 | 
						|
  // Simply invalidate the cached loaded modules.
 | 
						|
  if (!m_loaded_modules.empty())
 | 
						|
    m_loaded_modules.clear();
 | 
						|
}
 | 
						|
 | 
						|
void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
 | 
						|
  if (!m_loaded_modules.empty())
 | 
						|
    m_loaded_modules.clear();
 | 
						|
}
 | 
						|
 | 
						|
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
 | 
						|
NativeProcessWindows::Factory::Launch(
 | 
						|
    ProcessLaunchInfo &launch_info,
 | 
						|
    NativeProcessProtocol::NativeDelegate &native_delegate,
 | 
						|
    MainLoop &mainloop) const {
 | 
						|
  Error E = Error::success();
 | 
						|
  auto process_up = std::unique_ptr<NativeProcessWindows>(
 | 
						|
      new NativeProcessWindows(launch_info, native_delegate, E));
 | 
						|
  if (E)
 | 
						|
    return std::move(E);
 | 
						|
  return std::move(process_up);
 | 
						|
}
 | 
						|
 | 
						|
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
 | 
						|
NativeProcessWindows::Factory::Attach(
 | 
						|
    lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
 | 
						|
    MainLoop &mainloop) const {
 | 
						|
  Error E = Error::success();
 | 
						|
  // Set pty master fd invalid since it is not available.
 | 
						|
  auto process_up = std::unique_ptr<NativeProcessWindows>(
 | 
						|
      new NativeProcessWindows(pid, -1, native_delegate, E));
 | 
						|
  if (E)
 | 
						|
    return std::move(E);
 | 
						|
  return std::move(process_up);
 | 
						|
}
 | 
						|
} // namespace lldb_private
 |