28#include "llvm/ADT/STLExtras.h" 
   29#include "llvm/Support/ConvertUTF.h" 
   30#include "llvm/Support/Threading.h" 
   31#include "llvm/Support/raw_ostream.h" 
   36#ifndef STATUS_WX86_BREAKPOINT 
   37#define STATUS_WX86_BREAKPOINT 0x4000001FL  
   57      "lldb.plugin.process-windows.secondary[?]",
 
   59  if (!secondary_thread) {
 
   61    LLDB_LOG(log, 
"couldn't launch debugger thread. {0}", result);
 
 
   70  LLDB_LOG(log, 
"attaching to '{0}'", pid);
 
   74      "lldb.plugin.process-windows.secondary[?]", [
this, pid, attach_info] {
 
   77  if (!secondary_thread) {
 
   79    LLDB_LOG(log, 
"couldn't attach to process '{0}'. {1}", pid, result);
 
 
   89  std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
 
   92  LLDB_LOG(log, 
"preparing to launch '{0}' on background thread.",
 
 
  116  std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
 
  119  LLDB_LOG(log, 
"preparing to attach to process '{0}' on background thread.",
 
  122  if (!DebugActiveProcess((DWORD)pid)) {
 
 
  142  LLDB_LOG(log, 
"terminate = {0}, inferior={1}.", terminate, pid);
 
  146  bool expected = 
false;
 
  161      BOOL terminate_suceeded = TerminateProcess(handle, 0);
 
  163               "calling TerminateProcess({0}, 0) (inferior={1}), success={2}",
 
  164               handle, pid, terminate_suceeded);
 
  167               "NOT calling TerminateProcess because the inferior is not valid " 
  168               "({0}, 0) (inferior={1})",
 
  178    LLDB_LOG(log, 
"masking active exception");
 
  188    if (!::DebugBreakProcess(
 
  189            GetProcess().GetNativeProcess().GetSystemHandle())) {
 
  194  LLDB_LOG(log, 
"waiting for detach from process {0} to complete.", pid);
 
  197  if (wait_result != WAIT_OBJECT_0) {
 
  199    LLDB_LOG(log, 
"error: WaitForSingleObject({0}, 5000) returned {1}",
 
  202    LLDB_LOG(log, 
"detach from process {0} completed successfully.", pid);
 
  204  if (!
error.Success()) {
 
  205    LLDB_LOG(log, 
"encountered an error while trying to stop process {0}. {1}",
 
 
  216  LLDB_LOG(log, 
"broadcasting for inferior process {0}.",
 
 
  234  DEBUG_EVENT dbe = {};
 
  235  bool should_debug = 
true;
 
  236  LLDB_LOGV(log, 
"Entering WaitForDebugEvent loop");
 
  237  while (should_debug) {
 
  238    LLDB_LOGV(log, 
"Calling WaitForDebugEvent");
 
  239    BOOL wait_result = WaitForDebugEvent(&dbe, INFINITE);
 
  241      DWORD continue_status = DBG_CONTINUE;
 
  243      switch (dbe.dwDebugEventCode) {
 
  245        llvm_unreachable(
"Unhandle debug event code!");
 
  246      case EXCEPTION_DEBUG_EVENT: {
 
  248            dbe.u.Exception, dbe.dwThreadId, shutting_down);
 
  251          continue_status = DBG_CONTINUE;
 
  253          continue_status = DBG_EXCEPTION_NOT_HANDLED;
 
  257      case CREATE_THREAD_DEBUG_EVENT:
 
  261      case CREATE_PROCESS_DEBUG_EVENT:
 
  265      case EXIT_THREAD_DEBUG_EVENT:
 
  269      case EXIT_PROCESS_DEBUG_EVENT:
 
  272        should_debug = 
false;
 
  274      case LOAD_DLL_DEBUG_EVENT:
 
  277      case UNLOAD_DLL_DEBUG_EVENT:
 
  280      case OUTPUT_DEBUG_STRING_EVENT:
 
  281        continue_status = 
HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId);
 
  285        if (dbe.u.RipInfo.dwType == SLE_ERROR)
 
  286          should_debug = 
false;
 
  290      LLDB_LOGV(log, 
"calling ContinueDebugEvent({0}, {1}, {2}) on thread {3}.",
 
  291                dbe.dwProcessId, dbe.dwThreadId, continue_status,
 
  292                ::GetCurrentThreadId());
 
  294      ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status);
 
  303            (dbe.u.Exception.ExceptionRecord.ExceptionCode ==
 
  304                 EXCEPTION_BREAKPOINT ||
 
  305             dbe.u.Exception.ExceptionRecord.ExceptionCode ==
 
  308                   "Breakpoint exception is cue to detach from process {0:x}",
 
  316          while (WaitForDebugEvent(&dbe, 0)) {
 
  317            continue_status = DBG_CONTINUE;
 
  318            if (dbe.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
 
  319                !(dbe.u.Exception.ExceptionRecord.ExceptionCode ==
 
  320                      EXCEPTION_BREAKPOINT ||
 
  321                  dbe.u.Exception.ExceptionRecord.ExceptionCode ==
 
  323                  dbe.u.Exception.ExceptionRecord.ExceptionCode ==
 
  324                      EXCEPTION_SINGLE_STEP))
 
  325              continue_status = DBG_EXCEPTION_NOT_HANDLED;
 
  326            ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId,
 
  336        should_debug = 
false;
 
  339      LLDB_LOG(log, 
"returned FALSE from WaitForDebugEvent.  Error = {0}",
 
  342      should_debug = 
false;
 
  347  LLDB_LOG(log, 
"WaitForDebugEvent loop completed, exiting.");
 
 
  353                                     DWORD thread_id, 
bool shutting_down) {
 
  357        (info.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT ||
 
  367  bool first_chance = (info.dwFirstChance != 0);
 
  371  LLDB_LOG(log, 
"encountered {0} chance exception {1:x} on thread {2:x}",
 
  372           first_chance ? 
"first" : 
"second",
 
  373           info.ExceptionRecord.ExceptionCode, thread_id);
 
  379  LLDB_LOG(log, 
"waiting for ExceptionPred != BreakInDebugger");
 
 
  391  LLDB_LOG(log, 
"Thread {0} spawned in process {1}", thread_id,
 
  394  thread.GetNativeThread().SetOwnsHandle(
false);
 
 
  403  uint32_t process_id = ::GetProcessId(info.hProcess);
 
  405  LLDB_LOG(log, 
"process {0} spawned", process_id);
 
  407  std::string thread_name;
 
  408  llvm::raw_string_ostream name_stream(thread_name);
 
  409  name_stream << 
"lldb.plugin.process-windows.secondary[" << process_id << 
"]";
 
  410  llvm::set_thread_name(thread_name);
 
 
  430  LLDB_LOG(log, 
"Thread {0} exited with code {1} in process {2}", thread_id,
 
  431           info.dwExitCode, 
m_process.GetProcessId());
 
 
  450  DWORD dwFileSizeHi = 0;
 
  451  DWORD dwFileSizeLo = ::GetFileSize(hFile, &dwFileSizeHi);
 
  452  if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
 
  456      ::CreateFileMappingW(hFile, 
nullptr, PAGE_READONLY, 0, 1, NULL), 
nullptr);
 
  460  auto view_deleter = [](
void *pMem) { ::UnmapViewOfFile(pMem); };
 
  461  std::unique_ptr<void, 
decltype(view_deleter)> pMem(
 
  462      ::MapViewOfFile(filemap.
get(), FILE_MAP_READ, 0, 0, 1), view_deleter);
 
  466  std::array<wchar_t, MAX_PATH + 1> mapped_filename;
 
  467  if (!::GetMappedFileNameW(::GetCurrentProcess(), pMem.get(),
 
  468                            mapped_filename.data(), mapped_filename.size()))
 
  472  std::array<wchar_t, 512> drive_strings;
 
  473  drive_strings[0] = L
'\0';
 
  474  if (!::GetLogicalDriveStringsW(drive_strings.size(), drive_strings.data()))
 
  477  std::array<wchar_t, 3> drive = {L
"_:"};
 
  478  for (
const wchar_t *it = drive_strings.data(); *it != L
'\0';
 
  479       it += wcslen(it) + 1) {
 
  482    std::array<wchar_t, MAX_PATH> device_name;
 
  483    if (::QueryDosDeviceW(drive.data(), device_name.data(),
 
  484                          device_name.size())) {
 
  485      size_t device_name_len = wcslen(device_name.data());
 
  486      if (device_name_len < mapped_filename.size()) {
 
  487        bool match = _wcsnicmp(mapped_filename.data(), device_name.data(),
 
  488                               device_name_len) == 0;
 
  489        if (match && mapped_filename[device_name_len] == L
'\\') {
 
  491          std::wstring rebuilt_path(drive.data());
 
  492          rebuilt_path.append(&mapped_filename[device_name_len]);
 
  493          std::string path_utf8;
 
  494          llvm::convertWideToUTF8(rebuilt_path, path_utf8);
 
 
  507  if (info.hFile == 
nullptr) {
 
  509    LLDB_LOG(log, 
"Warning: Inferior {0} has a NULL file handle, returning...",
 
  514  auto on_load_dll = [&](llvm::StringRef path) {
 
  519    LLDB_LOG(log, 
"Inferior {0} - DLL '{1}' loaded at address {2:x}...",
 
  520             m_process.GetProcessId(), path, info.lpBaseOfDll);
 
  525  std::vector<wchar_t> buffer(1);
 
  526  DWORD required_size =
 
  527      GetFinalPathNameByHandleW(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS);
 
  528  if (required_size > 0) {
 
  529    buffer.resize(required_size + 1);
 
  530    required_size = GetFinalPathNameByHandleW(info.hFile, &buffer[0],
 
  531                                              required_size, VOLUME_NAME_DOS);
 
  532    std::string path_str_utf8;
 
  533    llvm::convertWideToUTF8(buffer.data(), path_str_utf8);
 
  534    llvm::StringRef path_str = path_str_utf8;
 
  535    const char *path = path_str.data();
 
  536    if (path_str.starts_with(
"\\\\?\\"))
 
  540  } 
else if (std::optional<std::string> path =
 
  546        "Inferior {0} - Error {1} occurred calling GetFinalPathNameByHandle",
 
  547        m_process.GetProcessId(), ::GetLastError());
 
  550  ::CloseHandle(info.hFile);
 
 
  558  LLDB_LOG(log, 
"process {0} unloading DLL at addr {1:x}.",
 
  559           m_process.GetProcessId(), info.lpBaseOfDll);
 
 
  575  LLDB_LOG(log, 
"encountered error {0} (type={1}) in process {2} thread {3}",
 
  576           info.dwError, info.dwType, 
m_process.GetProcessId(), thread_id);
 
 
static llvm::raw_ostream & error(Stream &strm)
static std::optional< std::string > GetFileNameFromHandleFallback(HANDLE hFile)
#define STATUS_WX86_BREAKPOINT
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOGV(log,...)
std::atomic< bool > m_is_shutting_down
std::atomic< DWORD > m_pid_to_detach
DWORD HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id)
DWORD HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id)
DWORD HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
DWORD HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id)
Status StopDebugging(bool terminate)
DWORD HandleRipEvent(const RIP_INFO &info, DWORD thread_id)
void ContinueAsyncException(ExceptionResult result)
HostProcess GetProcess() const
lldb::thread_result_t DebuggerThreadAttachRoutine(lldb::pid_t pid, const ProcessAttachInfo &launch_info)
DebuggerThread(DebugDelegateSP debug_delegate)
void FreeProcessHandles()
virtual ~DebuggerThread()
DWORD HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id)
ExceptionResult HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id, bool shutting_down)
Status DebugAttach(lldb::pid_t pid, const ProcessAttachInfo &attach_info)
lldb::thread_result_t DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info)
ExceptionRecordSP m_active_exception
Predicate< ExceptionResult > m_exception_pred
HANDLE m_debugging_ended_event
Status DebugLaunch(const ProcessLaunchInfo &launch_info)
DWORD HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
DebugDelegateSP m_debug_delegate
DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id)
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
lldb::pid_t GetProcessId() const
FileSpec & GetExecutableFile()
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Status &error) override
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
static llvm::Expected< HostThread > LaunchThread(llvm::StringRef name, std::function< lldb::thread_result_t()> thread_function, size_t min_stack_byte_size=0)
#define LLDB_INVALID_PROCESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
@ eBroadcastNever
No broadcast will be sent when the value is modified.
@ eBroadcastAlways
Always send a broadcast when the value is modified.
std::shared_ptr< IDebugDelegate > DebugDelegateSP
@ eErrorTypeWin32
Standard Win32 error codes.