180814287SRaphael Isemann //===-- NativeProcessWindows.cpp ------------------------------------------===//
25146a9eaSAaron Smith //
35146a9eaSAaron Smith // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45146a9eaSAaron Smith // See https://llvm.org/LICENSE.txt for license information.
55146a9eaSAaron Smith // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65146a9eaSAaron Smith //
75146a9eaSAaron Smith //===----------------------------------------------------------------------===//
85146a9eaSAaron Smith 
95146a9eaSAaron Smith #include "lldb/Host/windows/windows.h"
105146a9eaSAaron Smith #include <psapi.h>
115146a9eaSAaron Smith 
125146a9eaSAaron Smith #include "NativeProcessWindows.h"
135146a9eaSAaron Smith #include "NativeThreadWindows.h"
145146a9eaSAaron Smith #include "lldb/Host/FileSystem.h"
155146a9eaSAaron Smith #include "lldb/Host/HostNativeProcessBase.h"
165146a9eaSAaron Smith #include "lldb/Host/HostProcess.h"
175146a9eaSAaron Smith #include "lldb/Host/ProcessLaunchInfo.h"
185146a9eaSAaron Smith #include "lldb/Host/windows/AutoHandle.h"
195146a9eaSAaron Smith #include "lldb/Host/windows/HostThreadWindows.h"
205146a9eaSAaron Smith #include "lldb/Host/windows/ProcessLauncherWindows.h"
215146a9eaSAaron Smith #include "lldb/Target/MemoryRegionInfo.h"
225146a9eaSAaron Smith #include "lldb/Target/Process.h"
235146a9eaSAaron Smith #include "lldb/Utility/State.h"
245146a9eaSAaron Smith #include "llvm/Support/ConvertUTF.h"
255146a9eaSAaron Smith #include "llvm/Support/Errc.h"
265146a9eaSAaron Smith #include "llvm/Support/Error.h"
275146a9eaSAaron Smith #include "llvm/Support/Format.h"
285146a9eaSAaron Smith #include "llvm/Support/Threading.h"
295146a9eaSAaron Smith #include "llvm/Support/raw_ostream.h"
305146a9eaSAaron Smith 
315146a9eaSAaron Smith #include "DebuggerThread.h"
325146a9eaSAaron Smith #include "ExceptionRecord.h"
335146a9eaSAaron Smith #include "ProcessWindowsLog.h"
345146a9eaSAaron Smith 
355146a9eaSAaron Smith #include <tlhelp32.h>
365146a9eaSAaron Smith 
375146a9eaSAaron Smith #pragma warning(disable : 4005)
385146a9eaSAaron Smith #include "winternl.h"
395146a9eaSAaron Smith #include <ntstatus.h>
405146a9eaSAaron Smith 
415146a9eaSAaron Smith using namespace lldb;
425146a9eaSAaron Smith using namespace lldb_private;
435146a9eaSAaron Smith using namespace llvm;
445146a9eaSAaron Smith 
455146a9eaSAaron Smith namespace lldb_private {
465146a9eaSAaron Smith 
NativeProcessWindows(ProcessLaunchInfo & launch_info,NativeDelegate & delegate,llvm::Error & E)475146a9eaSAaron Smith NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
485146a9eaSAaron Smith                                            NativeDelegate &delegate,
495146a9eaSAaron Smith                                            llvm::Error &E)
505146a9eaSAaron Smith     : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID,
5164ec505dSJonas Devlieghere                             launch_info.GetPTY().ReleasePrimaryFileDescriptor(),
525146a9eaSAaron Smith                             delegate),
535146a9eaSAaron Smith       ProcessDebugger(), m_arch(launch_info.GetArchitecture()) {
545146a9eaSAaron Smith   ErrorAsOutParameter EOut(&E);
555146a9eaSAaron Smith   DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));
565146a9eaSAaron Smith   E = LaunchProcess(launch_info, delegate_sp).ToError();
575146a9eaSAaron Smith   if (E)
585146a9eaSAaron Smith     return;
595146a9eaSAaron Smith 
605146a9eaSAaron Smith   SetID(GetDebuggedProcessId());
615146a9eaSAaron Smith }
625146a9eaSAaron Smith 
NativeProcessWindows(lldb::pid_t pid,int terminal_fd,NativeDelegate & delegate,llvm::Error & E)635146a9eaSAaron Smith NativeProcessWindows::NativeProcessWindows(lldb::pid_t pid, int terminal_fd,
645146a9eaSAaron Smith                                            NativeDelegate &delegate,
655146a9eaSAaron Smith                                            llvm::Error &E)
665146a9eaSAaron Smith     : NativeProcessProtocol(pid, terminal_fd, delegate), ProcessDebugger() {
675146a9eaSAaron Smith   ErrorAsOutParameter EOut(&E);
685146a9eaSAaron Smith   DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));
695146a9eaSAaron Smith   ProcessAttachInfo attach_info;
705146a9eaSAaron Smith   attach_info.SetProcessID(pid);
715146a9eaSAaron Smith   E = AttachProcess(pid, attach_info, delegate_sp).ToError();
725146a9eaSAaron Smith   if (E)
735146a9eaSAaron Smith     return;
745146a9eaSAaron Smith 
755146a9eaSAaron Smith   SetID(GetDebuggedProcessId());
765146a9eaSAaron Smith 
775146a9eaSAaron Smith   ProcessInstanceInfo info;
785146a9eaSAaron Smith   if (!Host::GetProcessInfo(pid, info)) {
795146a9eaSAaron Smith     E = createStringError(inconvertibleErrorCode(),
805146a9eaSAaron Smith                           "Cannot get process information");
815146a9eaSAaron Smith     return;
825146a9eaSAaron Smith   }
835146a9eaSAaron Smith   m_arch = info.GetArchitecture();
845146a9eaSAaron Smith }
855146a9eaSAaron Smith 
Resume(const ResumeActionList & resume_actions)865146a9eaSAaron Smith Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) {
876730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
885146a9eaSAaron Smith   Status error;
895146a9eaSAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
905146a9eaSAaron Smith 
915146a9eaSAaron Smith   StateType state = GetState();
925146a9eaSAaron Smith   if (state == eStateStopped || state == eStateCrashed) {
935146a9eaSAaron Smith     LLDB_LOG(log, "process {0} is in state {1}.  Resuming...",
945146a9eaSAaron Smith              GetDebuggedProcessId(), state);
955146a9eaSAaron Smith     LLDB_LOG(log, "resuming {0} threads.", m_threads.size());
965146a9eaSAaron Smith 
975146a9eaSAaron Smith     bool failed = false;
985146a9eaSAaron Smith     for (uint32_t i = 0; i < m_threads.size(); ++i) {
995146a9eaSAaron Smith       auto thread = static_cast<NativeThreadWindows *>(m_threads[i].get());
1005146a9eaSAaron Smith       const ResumeAction *const action =
1015146a9eaSAaron Smith           resume_actions.GetActionForThread(thread->GetID(), true);
1025146a9eaSAaron Smith       if (action == nullptr)
1035146a9eaSAaron Smith         continue;
1045146a9eaSAaron Smith 
1055146a9eaSAaron Smith       switch (action->state) {
1065146a9eaSAaron Smith       case eStateRunning:
1075146a9eaSAaron Smith       case eStateStepping: {
1085146a9eaSAaron Smith         Status result = thread->DoResume(action->state);
1095146a9eaSAaron Smith         if (result.Fail()) {
1105146a9eaSAaron Smith           failed = true;
1115146a9eaSAaron Smith           LLDB_LOG(log,
1125146a9eaSAaron Smith                    "Trying to resume thread at index {0}, but failed with "
1135146a9eaSAaron Smith                    "error {1}.",
1145146a9eaSAaron Smith                    i, result);
1155146a9eaSAaron Smith         }
1165146a9eaSAaron Smith         break;
1175146a9eaSAaron Smith       }
1185146a9eaSAaron Smith       case eStateSuspended:
1195146a9eaSAaron Smith       case eStateStopped:
120*b4f2d7cdSMichał Górny         break;
1215146a9eaSAaron Smith 
1225146a9eaSAaron Smith       default:
1235146a9eaSAaron Smith         return Status(
1245146a9eaSAaron Smith             "NativeProcessWindows::%s (): unexpected state %s specified "
1255146a9eaSAaron Smith             "for pid %" PRIu64 ", tid %" PRIu64,
1265146a9eaSAaron Smith             __FUNCTION__, StateAsCString(action->state), GetID(),
1275146a9eaSAaron Smith             thread->GetID());
1285146a9eaSAaron Smith       }
1295146a9eaSAaron Smith     }
1305146a9eaSAaron Smith 
1315146a9eaSAaron Smith     if (failed) {
1325146a9eaSAaron Smith       error.SetErrorString("NativeProcessWindows::DoResume failed");
1335146a9eaSAaron Smith     } else {
1345146a9eaSAaron Smith       SetState(eStateRunning);
1355146a9eaSAaron Smith     }
1365146a9eaSAaron Smith 
1375146a9eaSAaron Smith     // Resume the debug loop.
1385146a9eaSAaron Smith     ExceptionRecordSP active_exception =
1395146a9eaSAaron Smith         m_session_data->m_debugger->GetActiveException().lock();
1405146a9eaSAaron Smith     if (active_exception) {
1415146a9eaSAaron Smith       // Resume the process and continue processing debug events.  Mask the
1425146a9eaSAaron Smith       // exception so that from the process's view, there is no indication that
1435146a9eaSAaron Smith       // anything happened.
1445146a9eaSAaron Smith       m_session_data->m_debugger->ContinueAsyncException(
1455146a9eaSAaron Smith           ExceptionResult::MaskException);
1465146a9eaSAaron Smith     }
1475146a9eaSAaron Smith   } else {
1485146a9eaSAaron Smith     LLDB_LOG(log, "error: process {0} is in state {1}.  Returning...",
1495146a9eaSAaron Smith              GetDebuggedProcessId(), GetState());
1505146a9eaSAaron Smith   }
1515146a9eaSAaron Smith 
1525146a9eaSAaron Smith   return error;
1535146a9eaSAaron Smith }
1545146a9eaSAaron Smith 
1555146a9eaSAaron Smith NativeThreadWindows *
GetThreadByID(lldb::tid_t thread_id)1565146a9eaSAaron Smith NativeProcessWindows::GetThreadByID(lldb::tid_t thread_id) {
1575146a9eaSAaron Smith   return static_cast<NativeThreadWindows *>(
1585146a9eaSAaron Smith       NativeProcessProtocol::GetThreadByID(thread_id));
1595146a9eaSAaron Smith }
1605146a9eaSAaron Smith 
Halt()1615146a9eaSAaron Smith Status NativeProcessWindows::Halt() {
1625146a9eaSAaron Smith   bool caused_stop = false;
1635146a9eaSAaron Smith   StateType state = GetState();
1645146a9eaSAaron Smith   if (state != eStateStopped)
1655146a9eaSAaron Smith     return HaltProcess(caused_stop);
1665146a9eaSAaron Smith   return Status();
1675146a9eaSAaron Smith }
1685146a9eaSAaron Smith 
Detach()1695146a9eaSAaron Smith Status NativeProcessWindows::Detach() {
1705146a9eaSAaron Smith   Status error;
1716730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
1725146a9eaSAaron Smith   StateType state = GetState();
1735146a9eaSAaron Smith   if (state != eStateExited && state != eStateDetached) {
1745146a9eaSAaron Smith     error = DetachProcess();
1755146a9eaSAaron Smith     if (error.Success())
1765146a9eaSAaron Smith       SetState(eStateDetached);
1775146a9eaSAaron Smith     else
1785146a9eaSAaron Smith       LLDB_LOG(log, "Detaching process error: {0}", error);
1795146a9eaSAaron Smith   } else {
180ed78dc8eSMartin Storsjo     error.SetErrorStringWithFormatv("error: process {0} in state = {1}, but "
1815146a9eaSAaron Smith                                     "cannot detach it in this state.",
1825146a9eaSAaron Smith                                     GetID(), state);
1835146a9eaSAaron Smith     LLDB_LOG(log, "error: {0}", error);
1845146a9eaSAaron Smith   }
1855146a9eaSAaron Smith   return error;
1865146a9eaSAaron Smith }
1875146a9eaSAaron Smith 
Signal(int signo)1885146a9eaSAaron Smith Status NativeProcessWindows::Signal(int signo) {
1895146a9eaSAaron Smith   Status error;
1905146a9eaSAaron Smith   error.SetErrorString("Windows does not support sending signals to processes");
1915146a9eaSAaron Smith   return error;
1925146a9eaSAaron Smith }
1935146a9eaSAaron Smith 
Interrupt()1945146a9eaSAaron Smith Status NativeProcessWindows::Interrupt() { return Halt(); }
1955146a9eaSAaron Smith 
Kill()1965146a9eaSAaron Smith Status NativeProcessWindows::Kill() {
1975146a9eaSAaron Smith   StateType state = GetState();
1985146a9eaSAaron Smith   return DestroyProcess(state);
1995146a9eaSAaron Smith }
2005146a9eaSAaron Smith 
IgnoreSignals(llvm::ArrayRef<int> signals)2015146a9eaSAaron Smith Status NativeProcessWindows::IgnoreSignals(llvm::ArrayRef<int> signals) {
2025146a9eaSAaron Smith   return Status();
2035146a9eaSAaron Smith }
2045146a9eaSAaron Smith 
GetMemoryRegionInfo(lldb::addr_t load_addr,MemoryRegionInfo & range_info)2055146a9eaSAaron Smith Status NativeProcessWindows::GetMemoryRegionInfo(lldb::addr_t load_addr,
2065146a9eaSAaron Smith                                                  MemoryRegionInfo &range_info) {
2075146a9eaSAaron Smith   return ProcessDebugger::GetMemoryRegionInfo(load_addr, range_info);
2085146a9eaSAaron Smith }
2095146a9eaSAaron Smith 
ReadMemory(lldb::addr_t addr,void * buf,size_t size,size_t & bytes_read)2105146a9eaSAaron Smith Status NativeProcessWindows::ReadMemory(lldb::addr_t addr, void *buf,
2115146a9eaSAaron Smith                                         size_t size, size_t &bytes_read) {
2125146a9eaSAaron Smith   return ProcessDebugger::ReadMemory(addr, buf, size, bytes_read);
2135146a9eaSAaron Smith }
2145146a9eaSAaron Smith 
WriteMemory(lldb::addr_t addr,const void * buf,size_t size,size_t & bytes_written)2155146a9eaSAaron Smith Status NativeProcessWindows::WriteMemory(lldb::addr_t addr, const void *buf,
2165146a9eaSAaron Smith                                          size_t size, size_t &bytes_written) {
2175146a9eaSAaron Smith   return ProcessDebugger::WriteMemory(addr, buf, size, bytes_written);
2185146a9eaSAaron Smith }
2195146a9eaSAaron Smith 
2202c4226f8SPavel Labath llvm::Expected<lldb::addr_t>
AllocateMemory(size_t size,uint32_t permissions)2212c4226f8SPavel Labath NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions) {
2222c4226f8SPavel Labath   lldb::addr_t addr;
2232c4226f8SPavel Labath   Status ST = ProcessDebugger::AllocateMemory(size, permissions, addr);
2242c4226f8SPavel Labath   if (ST.Success())
2252c4226f8SPavel Labath     return addr;
2262c4226f8SPavel Labath   return ST.ToError();
2275146a9eaSAaron Smith }
2285146a9eaSAaron Smith 
DeallocateMemory(lldb::addr_t addr)2292c4226f8SPavel Labath llvm::Error NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) {
2302c4226f8SPavel Labath   return ProcessDebugger::DeallocateMemory(addr).ToError();
2315146a9eaSAaron Smith }
2325146a9eaSAaron Smith 
GetSharedLibraryInfoAddress()2335146a9eaSAaron Smith lldb::addr_t NativeProcessWindows::GetSharedLibraryInfoAddress() { return 0; }
2345146a9eaSAaron Smith 
IsAlive() const2355146a9eaSAaron Smith bool NativeProcessWindows::IsAlive() const {
2365146a9eaSAaron Smith   StateType state = GetState();
2375146a9eaSAaron Smith   switch (state) {
2385146a9eaSAaron Smith   case eStateCrashed:
2395146a9eaSAaron Smith   case eStateDetached:
2405146a9eaSAaron Smith   case eStateExited:
2415146a9eaSAaron Smith   case eStateInvalid:
2425146a9eaSAaron Smith   case eStateUnloaded:
2435146a9eaSAaron Smith     return false;
2445146a9eaSAaron Smith   default:
2455146a9eaSAaron Smith     return true;
2465146a9eaSAaron Smith   }
2475146a9eaSAaron Smith }
2485146a9eaSAaron Smith 
SetStopReasonForThread(NativeThreadWindows & thread,lldb::StopReason reason,std::string description)2495146a9eaSAaron Smith void NativeProcessWindows::SetStopReasonForThread(NativeThreadWindows &thread,
2505146a9eaSAaron Smith                                                   lldb::StopReason reason,
2515146a9eaSAaron Smith                                                   std::string description) {
2525146a9eaSAaron Smith   SetCurrentThreadID(thread.GetID());
2535146a9eaSAaron Smith 
2545146a9eaSAaron Smith   ThreadStopInfo stop_info;
2555146a9eaSAaron Smith   stop_info.reason = reason;
2565146a9eaSAaron Smith   // No signal support on Windows but required to provide a 'valid' signum.
257d6b3de72SMichał Górny   stop_info.signo = SIGTRAP;
258d6b3de72SMichał Górny 
2595146a9eaSAaron Smith   if (reason == StopReason::eStopReasonException) {
2605146a9eaSAaron Smith     stop_info.details.exception.type = 0;
2615146a9eaSAaron Smith     stop_info.details.exception.data_count = 0;
2625146a9eaSAaron Smith   }
2635146a9eaSAaron Smith 
2645146a9eaSAaron Smith   thread.SetStopReason(stop_info, description);
2655146a9eaSAaron Smith }
2665146a9eaSAaron Smith 
StopThread(lldb::tid_t thread_id,lldb::StopReason reason,std::string description)2675146a9eaSAaron Smith void NativeProcessWindows::StopThread(lldb::tid_t thread_id,
2685146a9eaSAaron Smith                                       lldb::StopReason reason,
2695146a9eaSAaron Smith                                       std::string description) {
2705146a9eaSAaron Smith   NativeThreadWindows *thread = GetThreadByID(thread_id);
2715146a9eaSAaron Smith   if (!thread)
2725146a9eaSAaron Smith     return;
2735146a9eaSAaron Smith 
2745146a9eaSAaron Smith   for (uint32_t i = 0; i < m_threads.size(); ++i) {
2755146a9eaSAaron Smith     auto t = static_cast<NativeThreadWindows *>(m_threads[i].get());
2765146a9eaSAaron Smith     Status error = t->DoStop();
2775146a9eaSAaron Smith     if (error.Fail())
2785146a9eaSAaron Smith       exit(1);
2795146a9eaSAaron Smith   }
2805146a9eaSAaron Smith   SetStopReasonForThread(*thread, reason, description);
2815146a9eaSAaron Smith }
2825146a9eaSAaron Smith 
UpdateThreads()2835146a9eaSAaron Smith size_t NativeProcessWindows::UpdateThreads() { return m_threads.size(); }
2845146a9eaSAaron Smith 
2855146a9eaSAaron Smith llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
GetAuxvData() const2865146a9eaSAaron Smith NativeProcessWindows::GetAuxvData() const {
2875146a9eaSAaron Smith   // Not available on this target.
2885146a9eaSAaron Smith   return llvm::errc::not_supported;
2895146a9eaSAaron Smith }
2905146a9eaSAaron Smith 
2919f34f75fSMartin Storsjö llvm::Expected<llvm::ArrayRef<uint8_t>>
GetSoftwareBreakpointTrapOpcode(size_t size_hint)2929f34f75fSMartin Storsjö NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
2939f34f75fSMartin Storsjö   static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
2949f34f75fSMartin Storsjö   static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
2959f34f75fSMartin Storsjö 
2969f34f75fSMartin Storsjö   switch (GetArchitecture().GetMachine()) {
2979f34f75fSMartin Storsjö   case llvm::Triple::aarch64:
2989f34f75fSMartin Storsjö     return llvm::makeArrayRef(g_aarch64_opcode);
2999f34f75fSMartin Storsjö 
3009f34f75fSMartin Storsjö   case llvm::Triple::arm:
3019f34f75fSMartin Storsjö   case llvm::Triple::thumb:
3029f34f75fSMartin Storsjö     return llvm::makeArrayRef(g_thumb_opcode);
3039f34f75fSMartin Storsjö 
3049f34f75fSMartin Storsjö   default:
3059f34f75fSMartin Storsjö     return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
3069f34f75fSMartin Storsjö   }
3079f34f75fSMartin Storsjö }
3089f34f75fSMartin Storsjö 
GetSoftwareBreakpointPCOffset()3099f34f75fSMartin Storsjö size_t NativeProcessWindows::GetSoftwareBreakpointPCOffset() {
3109f34f75fSMartin Storsjö     // Windows always reports an incremented PC after a breakpoint is hit,
3119f34f75fSMartin Storsjö     // even on ARM.
3129f34f75fSMartin Storsjö     return cantFail(GetSoftwareBreakpointTrapOpcode(0)).size();
3139f34f75fSMartin Storsjö }
3149f34f75fSMartin Storsjö 
FindSoftwareBreakpoint(lldb::addr_t addr)3155146a9eaSAaron Smith bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) {
3165146a9eaSAaron Smith   auto it = m_software_breakpoints.find(addr);
3175146a9eaSAaron Smith   if (it == m_software_breakpoints.end())
3185146a9eaSAaron Smith     return false;
3195146a9eaSAaron Smith   return true;
3205146a9eaSAaron Smith }
3215146a9eaSAaron Smith 
SetBreakpoint(lldb::addr_t addr,uint32_t size,bool hardware)3225146a9eaSAaron Smith Status NativeProcessWindows::SetBreakpoint(lldb::addr_t addr, uint32_t size,
3235146a9eaSAaron Smith                                            bool hardware) {
3245146a9eaSAaron Smith   if (hardware)
3255146a9eaSAaron Smith     return SetHardwareBreakpoint(addr, size);
3265146a9eaSAaron Smith   return SetSoftwareBreakpoint(addr, size);
3275146a9eaSAaron Smith }
3285146a9eaSAaron Smith 
RemoveBreakpoint(lldb::addr_t addr,bool hardware)3295146a9eaSAaron Smith Status NativeProcessWindows::RemoveBreakpoint(lldb::addr_t addr,
3305146a9eaSAaron Smith                                               bool hardware) {
3315146a9eaSAaron Smith   if (hardware)
3325146a9eaSAaron Smith     return RemoveHardwareBreakpoint(addr);
3335146a9eaSAaron Smith   return RemoveSoftwareBreakpoint(addr);
3345146a9eaSAaron Smith }
3355146a9eaSAaron Smith 
CacheLoadedModules()3365146a9eaSAaron Smith Status NativeProcessWindows::CacheLoadedModules() {
3375146a9eaSAaron Smith   Status error;
3385146a9eaSAaron Smith   if (!m_loaded_modules.empty())
3395146a9eaSAaron Smith     return Status();
3405146a9eaSAaron Smith 
3415146a9eaSAaron Smith   // Retrieve loaded modules by a Target/Module free implemenation.
3425146a9eaSAaron Smith   AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID()));
3435146a9eaSAaron Smith   if (snapshot.IsValid()) {
3445146a9eaSAaron Smith     MODULEENTRY32W me;
3455146a9eaSAaron Smith     me.dwSize = sizeof(MODULEENTRY32W);
3465146a9eaSAaron Smith     if (Module32FirstW(snapshot.get(), &me)) {
3475146a9eaSAaron Smith       do {
3485146a9eaSAaron Smith         std::string path;
3495146a9eaSAaron Smith         if (!llvm::convertWideToUTF8(me.szExePath, path))
3505146a9eaSAaron Smith           continue;
3515146a9eaSAaron Smith 
3525146a9eaSAaron Smith         FileSpec file_spec(path);
3535146a9eaSAaron Smith         FileSystem::Instance().Resolve(file_spec);
3545146a9eaSAaron Smith         m_loaded_modules[file_spec] = (addr_t)me.modBaseAddr;
3555146a9eaSAaron Smith       } while (Module32Next(snapshot.get(), &me));
3565146a9eaSAaron Smith     }
3575146a9eaSAaron Smith 
3585146a9eaSAaron Smith     if (!m_loaded_modules.empty())
3595146a9eaSAaron Smith       return Status();
3605146a9eaSAaron Smith   }
3615146a9eaSAaron Smith 
3625146a9eaSAaron Smith   error.SetError(::GetLastError(), lldb::ErrorType::eErrorTypeWin32);
3635146a9eaSAaron Smith   return error;
3645146a9eaSAaron Smith }
3655146a9eaSAaron Smith 
GetLoadedModuleFileSpec(const char * module_path,FileSpec & file_spec)3665146a9eaSAaron Smith Status NativeProcessWindows::GetLoadedModuleFileSpec(const char *module_path,
3675146a9eaSAaron Smith                                                      FileSpec &file_spec) {
3685146a9eaSAaron Smith   Status error = CacheLoadedModules();
3695146a9eaSAaron Smith   if (error.Fail())
3705146a9eaSAaron Smith     return error;
3715146a9eaSAaron Smith 
3725146a9eaSAaron Smith   FileSpec module_file_spec(module_path);
3735146a9eaSAaron Smith   FileSystem::Instance().Resolve(module_file_spec);
3745146a9eaSAaron Smith   for (auto &it : m_loaded_modules) {
3755146a9eaSAaron Smith     if (it.first == module_file_spec) {
3765146a9eaSAaron Smith       file_spec = it.first;
3775146a9eaSAaron Smith       return Status();
3785146a9eaSAaron Smith     }
3795146a9eaSAaron Smith   }
3805146a9eaSAaron Smith   return Status("Module (%s) not found in process %" PRIu64 "!",
3815146a9eaSAaron Smith                 module_file_spec.GetCString(), GetID());
3825146a9eaSAaron Smith }
3835146a9eaSAaron Smith 
3845146a9eaSAaron Smith Status
GetFileLoadAddress(const llvm::StringRef & file_name,lldb::addr_t & load_addr)3855146a9eaSAaron Smith NativeProcessWindows::GetFileLoadAddress(const llvm::StringRef &file_name,
3865146a9eaSAaron Smith                                          lldb::addr_t &load_addr) {
3875146a9eaSAaron Smith   Status error = CacheLoadedModules();
3885146a9eaSAaron Smith   if (error.Fail())
3895146a9eaSAaron Smith     return error;
3905146a9eaSAaron Smith 
3915146a9eaSAaron Smith   load_addr = LLDB_INVALID_ADDRESS;
3925146a9eaSAaron Smith   FileSpec file_spec(file_name);
3935146a9eaSAaron Smith   FileSystem::Instance().Resolve(file_spec);
3945146a9eaSAaron Smith   for (auto &it : m_loaded_modules) {
3955146a9eaSAaron Smith     if (it.first == file_spec) {
3965146a9eaSAaron Smith       load_addr = it.second;
3975146a9eaSAaron Smith       return Status();
3985146a9eaSAaron Smith     }
3995146a9eaSAaron Smith   }
4005146a9eaSAaron Smith   return Status("Can't get loaded address of file (%s) in process %" PRIu64 "!",
4015146a9eaSAaron Smith                 file_spec.GetCString(), GetID());
4025146a9eaSAaron Smith }
4035146a9eaSAaron Smith 
OnExitProcess(uint32_t exit_code)4045146a9eaSAaron Smith void NativeProcessWindows::OnExitProcess(uint32_t exit_code) {
4056730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
4065146a9eaSAaron Smith   LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
4075146a9eaSAaron Smith 
4085146a9eaSAaron Smith   ProcessDebugger::OnExitProcess(exit_code);
4095146a9eaSAaron Smith 
4105146a9eaSAaron Smith   // No signal involved.  It is just an exit event.
4115146a9eaSAaron Smith   WaitStatus wait_status(WaitStatus::Exit, exit_code);
4125146a9eaSAaron Smith   SetExitStatus(wait_status, true);
4135146a9eaSAaron Smith 
4145146a9eaSAaron Smith   // Notify the native delegate.
4155146a9eaSAaron Smith   SetState(eStateExited, true);
4165146a9eaSAaron Smith }
4175146a9eaSAaron Smith 
OnDebuggerConnected(lldb::addr_t image_base)4185146a9eaSAaron Smith void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
4196730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
4205146a9eaSAaron Smith   LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}",
4215146a9eaSAaron Smith            GetDebuggedProcessId(), image_base);
4225146a9eaSAaron Smith 
4235146a9eaSAaron Smith   // This is the earliest chance we can resolve the process ID and
424e9264b74SKazuaki Ishizaki   // architecture if we don't know them yet.
4255146a9eaSAaron Smith   if (GetID() == LLDB_INVALID_PROCESS_ID)
4265146a9eaSAaron Smith     SetID(GetDebuggedProcessId());
4275146a9eaSAaron Smith 
4285146a9eaSAaron Smith   if (GetArchitecture().GetMachine() == llvm::Triple::UnknownArch) {
4295146a9eaSAaron Smith     ProcessInstanceInfo process_info;
4305146a9eaSAaron Smith     if (!Host::GetProcessInfo(GetDebuggedProcessId(), process_info)) {
4315146a9eaSAaron Smith       LLDB_LOG(log, "Cannot get process information during debugger connecting "
4325146a9eaSAaron Smith                     "to process");
4335146a9eaSAaron Smith       return;
4345146a9eaSAaron Smith     }
4355146a9eaSAaron Smith     SetArchitecture(process_info.GetArchitecture());
4365146a9eaSAaron Smith   }
4375146a9eaSAaron Smith 
4385146a9eaSAaron Smith   // The very first one shall always be the main thread.
4395146a9eaSAaron Smith   assert(m_threads.empty());
440a8f3ae7cSJonas Devlieghere   m_threads.push_back(std::make_unique<NativeThreadWindows>(
4415146a9eaSAaron Smith       *this, m_session_data->m_debugger->GetMainThread()));
4425146a9eaSAaron Smith }
4435146a9eaSAaron Smith 
4445146a9eaSAaron Smith ExceptionResult
OnDebugException(bool first_chance,const ExceptionRecord & record)4455146a9eaSAaron Smith NativeProcessWindows::OnDebugException(bool first_chance,
4465146a9eaSAaron Smith                                        const ExceptionRecord &record) {
4476730df47SPavel Labath   Log *log = GetLog(WindowsLog::Exception);
4485146a9eaSAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
4495146a9eaSAaron Smith 
4505146a9eaSAaron Smith   // Let the debugger establish the internal status.
4515146a9eaSAaron Smith   ProcessDebugger::OnDebugException(first_chance, record);
4525146a9eaSAaron Smith 
4535146a9eaSAaron Smith   static bool initial_stop = false;
4545146a9eaSAaron Smith   if (!first_chance) {
4555146a9eaSAaron Smith     SetState(eStateStopped, false);
4565146a9eaSAaron Smith   }
4575146a9eaSAaron Smith 
4585146a9eaSAaron Smith   ExceptionResult result = ExceptionResult::SendToApplication;
4595146a9eaSAaron Smith   switch (record.GetExceptionCode()) {
460e7823a53SSaleem Abdulrasool   case DWORD(STATUS_SINGLE_STEP):
4615b5274eaSAleksandr Urakov   case STATUS_WX86_SINGLE_STEP: {
4625b5274eaSAleksandr Urakov     uint32_t wp_id = LLDB_INVALID_INDEX32;
4635b5274eaSAleksandr Urakov     if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID())) {
4645b5274eaSAleksandr Urakov       NativeRegisterContextWindows &reg_ctx = thread->GetRegisterContext();
4655b5274eaSAleksandr Urakov       Status error =
4665b5274eaSAleksandr Urakov           reg_ctx.GetWatchpointHitIndex(wp_id, record.GetExceptionAddress());
4675b5274eaSAleksandr Urakov       if (error.Fail())
4685b5274eaSAleksandr Urakov         LLDB_LOG(log,
4695b5274eaSAleksandr Urakov                  "received error while checking for watchpoint hits, pid = "
4705b5274eaSAleksandr Urakov                  "{0}, error = {1}",
4715b5274eaSAleksandr Urakov                  thread->GetID(), error);
4725b5274eaSAleksandr Urakov       if (wp_id != LLDB_INVALID_INDEX32) {
4735b5274eaSAleksandr Urakov         addr_t wp_addr = reg_ctx.GetWatchpointAddress(wp_id);
4745b5274eaSAleksandr Urakov         addr_t wp_hit_addr = reg_ctx.GetWatchpointHitAddress(wp_id);
4755b5274eaSAleksandr Urakov         std::string desc =
4765b5274eaSAleksandr Urakov             formatv("{0} {1} {2}", wp_addr, wp_id, wp_hit_addr).str();
4775b5274eaSAleksandr Urakov         StopThread(record.GetThreadID(), StopReason::eStopReasonWatchpoint,
4785b5274eaSAleksandr Urakov                    desc);
4795b5274eaSAleksandr Urakov       }
4805b5274eaSAleksandr Urakov     }
4815b5274eaSAleksandr Urakov     if (wp_id == LLDB_INVALID_INDEX32)
4825146a9eaSAaron Smith       StopThread(record.GetThreadID(), StopReason::eStopReasonTrace);
4835b5274eaSAleksandr Urakov 
4845146a9eaSAaron Smith     SetState(eStateStopped, true);
4855146a9eaSAaron Smith 
4865146a9eaSAaron Smith     // Continue the debugger.
4875146a9eaSAaron Smith     return ExceptionResult::MaskException;
4885b5274eaSAleksandr Urakov   }
489e7823a53SSaleem Abdulrasool   case DWORD(STATUS_BREAKPOINT):
4905146a9eaSAaron Smith   case STATUS_WX86_BREAKPOINT:
4915146a9eaSAaron Smith     if (FindSoftwareBreakpoint(record.GetExceptionAddress())) {
4925146a9eaSAaron Smith       LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
4935146a9eaSAaron Smith                record.GetExceptionAddress());
4945146a9eaSAaron Smith 
4955146a9eaSAaron Smith       StopThread(record.GetThreadID(), StopReason::eStopReasonBreakpoint);
4965146a9eaSAaron Smith 
4975146a9eaSAaron Smith       if (NativeThreadWindows *stop_thread =
4985146a9eaSAaron Smith               GetThreadByID(record.GetThreadID())) {
4995146a9eaSAaron Smith         auto &register_context = stop_thread->GetRegisterContext();
5009f34f75fSMartin Storsjö         uint32_t breakpoint_size = GetSoftwareBreakpointPCOffset();
5019f34f75fSMartin Storsjö         // The current PC is AFTER the BP opcode, on all architectures.
5029f34f75fSMartin Storsjö         uint64_t pc = register_context.GetPC() - breakpoint_size;
5035146a9eaSAaron Smith         register_context.SetPC(pc);
5045146a9eaSAaron Smith       }
5055146a9eaSAaron Smith 
5065146a9eaSAaron Smith       SetState(eStateStopped, true);
5075146a9eaSAaron Smith       return ExceptionResult::MaskException;
5085146a9eaSAaron Smith     }
5095146a9eaSAaron Smith 
5105146a9eaSAaron Smith     if (!initial_stop) {
5115146a9eaSAaron Smith       initial_stop = true;
5125146a9eaSAaron Smith       LLDB_LOG(log,
5135146a9eaSAaron Smith                "Hit loader breakpoint at address {0:x}, setting initial stop "
5145146a9eaSAaron Smith                "event.",
5155146a9eaSAaron Smith                record.GetExceptionAddress());
5165146a9eaSAaron Smith 
5175146a9eaSAaron Smith       // We are required to report the reason for the first stop after
5185146a9eaSAaron Smith       // launching or being attached.
5195146a9eaSAaron Smith       if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID()))
5205146a9eaSAaron Smith         SetStopReasonForThread(*thread, StopReason::eStopReasonBreakpoint);
5215146a9eaSAaron Smith 
5225146a9eaSAaron Smith       // Do not notify the native delegate (e.g. llgs) since at this moment
5235146a9eaSAaron Smith       // the program hasn't returned from Factory::Launch() and the delegate
5245146a9eaSAaron Smith       // might not have an valid native process to operate on.
5255146a9eaSAaron Smith       SetState(eStateStopped, false);
5265146a9eaSAaron Smith 
5275146a9eaSAaron Smith       // Hit the initial stop. Continue the application.
5285146a9eaSAaron Smith       return ExceptionResult::BreakInDebugger;
5295146a9eaSAaron Smith     }
5305146a9eaSAaron Smith 
5315c38730dSMartin Storsjo     LLVM_FALLTHROUGH;
5325146a9eaSAaron Smith   default:
5335146a9eaSAaron Smith     LLDB_LOG(log,
5345146a9eaSAaron Smith              "Debugger thread reported exception {0:x} at address {1:x} "
5355146a9eaSAaron Smith              "(first_chance={2})",
5365146a9eaSAaron Smith              record.GetExceptionCode(), record.GetExceptionAddress(),
5375146a9eaSAaron Smith              first_chance);
5385146a9eaSAaron Smith 
5395146a9eaSAaron Smith     {
5405146a9eaSAaron Smith       std::string desc;
5415146a9eaSAaron Smith       llvm::raw_string_ostream desc_stream(desc);
5425146a9eaSAaron Smith       desc_stream << "Exception "
5435146a9eaSAaron Smith                   << llvm::format_hex(record.GetExceptionCode(), 8)
5445146a9eaSAaron Smith                   << " encountered at address "
5455146a9eaSAaron Smith                   << llvm::format_hex(record.GetExceptionAddress(), 8);
5465146a9eaSAaron Smith       StopThread(record.GetThreadID(), StopReason::eStopReasonException,
5475146a9eaSAaron Smith                  desc_stream.str().c_str());
5485146a9eaSAaron Smith 
5495146a9eaSAaron Smith       SetState(eStateStopped, true);
5505146a9eaSAaron Smith     }
5515146a9eaSAaron Smith 
5525146a9eaSAaron Smith     // For non-breakpoints, give the application a chance to handle the
5535146a9eaSAaron Smith     // exception first.
5545146a9eaSAaron Smith     if (first_chance)
5555146a9eaSAaron Smith       result = ExceptionResult::SendToApplication;
5565146a9eaSAaron Smith     else
5575146a9eaSAaron Smith       result = ExceptionResult::BreakInDebugger;
5585146a9eaSAaron Smith   }
5595146a9eaSAaron Smith 
5605146a9eaSAaron Smith   return result;
5615146a9eaSAaron Smith }
5625146a9eaSAaron Smith 
OnCreateThread(const HostThread & new_thread)5635146a9eaSAaron Smith void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) {
5645146a9eaSAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
5655b5274eaSAleksandr Urakov 
5665b5274eaSAleksandr Urakov   auto thread = std::make_unique<NativeThreadWindows>(*this, new_thread);
5675b5274eaSAleksandr Urakov   thread->GetRegisterContext().ClearAllHardwareWatchpoints();
5685b5274eaSAleksandr Urakov   for (const auto &pair : GetWatchpointMap()) {
5695b5274eaSAleksandr Urakov     const NativeWatchpoint &wp = pair.second;
5705b5274eaSAleksandr Urakov     thread->SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags,
5715b5274eaSAleksandr Urakov                           wp.m_hardware);
5725b5274eaSAleksandr Urakov   }
5735b5274eaSAleksandr Urakov 
5745b5274eaSAleksandr Urakov   m_threads.push_back(std::move(thread));
5755146a9eaSAaron Smith }
5765146a9eaSAaron Smith 
OnExitThread(lldb::tid_t thread_id,uint32_t exit_code)5775146a9eaSAaron Smith void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id,
5785146a9eaSAaron Smith                                         uint32_t exit_code) {
5795146a9eaSAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
5805146a9eaSAaron Smith   NativeThreadWindows *thread = GetThreadByID(thread_id);
5815146a9eaSAaron Smith   if (!thread)
5825146a9eaSAaron Smith     return;
5835146a9eaSAaron Smith 
5845146a9eaSAaron Smith   for (auto t = m_threads.begin(); t != m_threads.end();) {
5855146a9eaSAaron Smith     if ((*t)->GetID() == thread_id) {
5865146a9eaSAaron Smith       t = m_threads.erase(t);
5875146a9eaSAaron Smith     } else {
5885146a9eaSAaron Smith       ++t;
5895146a9eaSAaron Smith     }
5905146a9eaSAaron Smith   }
5915146a9eaSAaron Smith }
5925146a9eaSAaron Smith 
OnLoadDll(const ModuleSpec & module_spec,lldb::addr_t module_addr)5935146a9eaSAaron Smith void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
5945146a9eaSAaron Smith                                      lldb::addr_t module_addr) {
5955146a9eaSAaron Smith   // Simply invalidate the cached loaded modules.
5965146a9eaSAaron Smith   if (!m_loaded_modules.empty())
5975146a9eaSAaron Smith     m_loaded_modules.clear();
5985146a9eaSAaron Smith }
5995146a9eaSAaron Smith 
OnUnloadDll(lldb::addr_t module_addr)6005146a9eaSAaron Smith void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
6015146a9eaSAaron Smith   if (!m_loaded_modules.empty())
6025146a9eaSAaron Smith     m_loaded_modules.clear();
6035146a9eaSAaron Smith }
6045146a9eaSAaron Smith 
6055146a9eaSAaron Smith llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Launch(ProcessLaunchInfo & launch_info,NativeProcessProtocol::NativeDelegate & native_delegate,MainLoop & mainloop) const6065146a9eaSAaron Smith NativeProcessWindows::Factory::Launch(
6075146a9eaSAaron Smith     ProcessLaunchInfo &launch_info,
6085146a9eaSAaron Smith     NativeProcessProtocol::NativeDelegate &native_delegate,
6095146a9eaSAaron Smith     MainLoop &mainloop) const {
6105146a9eaSAaron Smith   Error E = Error::success();
6115146a9eaSAaron Smith   auto process_up = std::unique_ptr<NativeProcessWindows>(
6125146a9eaSAaron Smith       new NativeProcessWindows(launch_info, native_delegate, E));
6135146a9eaSAaron Smith   if (E)
6145146a9eaSAaron Smith     return std::move(E);
6155146a9eaSAaron Smith   return std::move(process_up);
6165146a9eaSAaron Smith }
6175146a9eaSAaron Smith 
6185146a9eaSAaron Smith llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Attach(lldb::pid_t pid,NativeProcessProtocol::NativeDelegate & native_delegate,MainLoop & mainloop) const6195146a9eaSAaron Smith NativeProcessWindows::Factory::Attach(
6205146a9eaSAaron Smith     lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
6215146a9eaSAaron Smith     MainLoop &mainloop) const {
6225146a9eaSAaron Smith   Error E = Error::success();
62352a3ed5bSQuinn Pham   // Set pty primary fd invalid since it is not available.
6245146a9eaSAaron Smith   auto process_up = std::unique_ptr<NativeProcessWindows>(
6255146a9eaSAaron Smith       new NativeProcessWindows(pid, -1, native_delegate, E));
6265146a9eaSAaron Smith   if (E)
6275146a9eaSAaron Smith     return std::move(E);
6285146a9eaSAaron Smith   return std::move(process_up);
6295146a9eaSAaron Smith }
6305146a9eaSAaron Smith } // namespace lldb_private
631