118a9135dSAdrian McCarthy //===-- ProcessWindows.cpp --------------------------------------*- C++ -*-===//
218a9135dSAdrian McCarthy //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618a9135dSAdrian McCarthy //
718a9135dSAdrian McCarthy //===----------------------------------------------------------------------===//
818a9135dSAdrian McCarthy 
918a9135dSAdrian McCarthy #include "ProcessWindows.h"
1018a9135dSAdrian McCarthy 
114ad5def9SAdrian McCarthy // Windows includes
124ad5def9SAdrian McCarthy #include "lldb/Host/windows/windows.h"
134ad5def9SAdrian McCarthy #include <psapi.h>
144ad5def9SAdrian McCarthy 
1518a9135dSAdrian McCarthy #include "lldb/Core/Module.h"
1618a9135dSAdrian McCarthy #include "lldb/Core/ModuleSpec.h"
1718a9135dSAdrian McCarthy #include "lldb/Core/PluginManager.h"
1818a9135dSAdrian McCarthy #include "lldb/Core/Section.h"
1960cf3f82SJonas Devlieghere #include "lldb/Host/FileSystem.h"
204ad5def9SAdrian McCarthy #include "lldb/Host/HostNativeProcessBase.h"
214ad5def9SAdrian McCarthy #include "lldb/Host/HostProcess.h"
224ad5def9SAdrian McCarthy #include "lldb/Host/windows/HostThreadWindows.h"
230c35cde9SAdrian McCarthy #include "lldb/Host/windows/windows.h"
242f3df613SZachary Turner #include "lldb/Symbol/ObjectFile.h"
2518a9135dSAdrian McCarthy #include "lldb/Target/DynamicLoader.h"
2618a9135dSAdrian McCarthy #include "lldb/Target/MemoryRegionInfo.h"
274ad5def9SAdrian McCarthy #include "lldb/Target/StopInfo.h"
2818a9135dSAdrian McCarthy #include "lldb/Target/Target.h"
29d821c997SPavel Labath #include "lldb/Utility/State.h"
3018a9135dSAdrian McCarthy 
314ad5def9SAdrian McCarthy #include "llvm/Support/ConvertUTF.h"
324ad5def9SAdrian McCarthy #include "llvm/Support/Format.h"
33c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h"
344ad5def9SAdrian McCarthy #include "llvm/Support/raw_ostream.h"
354ad5def9SAdrian McCarthy 
364ad5def9SAdrian McCarthy #include "DebuggerThread.h"
374ad5def9SAdrian McCarthy #include "ExceptionRecord.h"
384ad5def9SAdrian McCarthy #include "ForwardDecl.h"
394ad5def9SAdrian McCarthy #include "LocalDebugDelegate.h"
404ad5def9SAdrian McCarthy #include "ProcessWindowsLog.h"
414ad5def9SAdrian McCarthy #include "TargetThreadWindows.h"
424ad5def9SAdrian McCarthy 
4318a9135dSAdrian McCarthy using namespace lldb;
4418a9135dSAdrian McCarthy using namespace lldb_private;
4518a9135dSAdrian McCarthy 
464ad5def9SAdrian McCarthy namespace {
474ad5def9SAdrian McCarthy std::string GetProcessExecutableName(HANDLE process_handle) {
484ad5def9SAdrian McCarthy   std::vector<wchar_t> file_name;
494ad5def9SAdrian McCarthy   DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit
504ad5def9SAdrian McCarthy   DWORD copied = 0;
514ad5def9SAdrian McCarthy   do {
524ad5def9SAdrian McCarthy     file_name_size *= 2;
534ad5def9SAdrian McCarthy     file_name.resize(file_name_size);
544ad5def9SAdrian McCarthy     copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(),
554ad5def9SAdrian McCarthy                                     file_name_size);
564ad5def9SAdrian McCarthy   } while (copied >= file_name_size);
574ad5def9SAdrian McCarthy   file_name.resize(copied);
584ad5def9SAdrian McCarthy   std::string result;
594ad5def9SAdrian McCarthy   llvm::convertWideToUTF8(file_name.data(), result);
604ad5def9SAdrian McCarthy   return result;
614ad5def9SAdrian McCarthy }
624ad5def9SAdrian McCarthy 
634ad5def9SAdrian McCarthy std::string GetProcessExecutableName(DWORD pid) {
644ad5def9SAdrian McCarthy   std::string file_name;
654ad5def9SAdrian McCarthy   HANDLE process_handle =
664ad5def9SAdrian McCarthy       ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
674ad5def9SAdrian McCarthy   if (process_handle != NULL) {
684ad5def9SAdrian McCarthy     file_name = GetProcessExecutableName(process_handle);
694ad5def9SAdrian McCarthy     ::CloseHandle(process_handle);
704ad5def9SAdrian McCarthy   }
714ad5def9SAdrian McCarthy   return file_name;
724ad5def9SAdrian McCarthy }
73*ed499a36SStella Stamenova 
74*ed499a36SStella Stamenova DWORD ConvertLldbToWinApiProtect(uint32_t protect) {
75*ed499a36SStella Stamenova   // We also can process a read / write permissions here, but if the debugger
76*ed499a36SStella Stamenova   // will make later a write into the allocated memory, it will fail. To get
77*ed499a36SStella Stamenova   // around it is possible inside DoWriteMemory to remember memory permissions,
78*ed499a36SStella Stamenova   // allow write, write and restore permissions, but for now we process only
79*ed499a36SStella Stamenova   // the executable permission.
80*ed499a36SStella Stamenova   //
81*ed499a36SStella Stamenova   // TODO: Process permissions other than executable
82*ed499a36SStella Stamenova   if (protect & ePermissionsExecutable)
83*ed499a36SStella Stamenova     return PAGE_EXECUTE_READWRITE;
84*ed499a36SStella Stamenova 
85*ed499a36SStella Stamenova   return PAGE_READWRITE;
86*ed499a36SStella Stamenova }
87*ed499a36SStella Stamenova 
884ad5def9SAdrian McCarthy } // anonymous namespace
894ad5def9SAdrian McCarthy 
90b9c1b51eSKate Stone namespace lldb_private {
9118a9135dSAdrian McCarthy 
92*ed499a36SStella Stamenova // We store a pointer to this class in the ProcessWindows, so that we don't
93*ed499a36SStella Stamenova // expose Windows-specific types and implementation details from a public
94*ed499a36SStella Stamenova // header file.
95*ed499a36SStella Stamenova class ProcessWindowsData {
96*ed499a36SStella Stamenova public:
97*ed499a36SStella Stamenova   ProcessWindowsData(bool stop_at_entry) : m_stop_at_entry(stop_at_entry) {
98*ed499a36SStella Stamenova     m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
99*ed499a36SStella Stamenova   }
100*ed499a36SStella Stamenova 
101*ed499a36SStella Stamenova   ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); }
102*ed499a36SStella Stamenova 
103*ed499a36SStella Stamenova   Status m_launch_error;
104*ed499a36SStella Stamenova   DebuggerThreadSP m_debugger;
105*ed499a36SStella Stamenova   StopInfoSP m_pending_stop_info;
106*ed499a36SStella Stamenova   HANDLE m_initial_stop_event = nullptr;
107*ed499a36SStella Stamenova   bool m_initial_stop_received = false;
108*ed499a36SStella Stamenova   bool m_stop_at_entry;
109*ed499a36SStella Stamenova   std::map<lldb::tid_t, HostThread> m_new_threads;
110*ed499a36SStella Stamenova   std::set<lldb::tid_t> m_exited_threads;
111*ed499a36SStella Stamenova };
112*ed499a36SStella Stamenova 
1134ad5def9SAdrian McCarthy ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp,
1144ad5def9SAdrian McCarthy                                          lldb::ListenerSP listener_sp,
1154ad5def9SAdrian McCarthy                                          const FileSpec *) {
1164ad5def9SAdrian McCarthy   return ProcessSP(new ProcessWindows(target_sp, listener_sp));
1174ad5def9SAdrian McCarthy }
1184ad5def9SAdrian McCarthy 
1194ad5def9SAdrian McCarthy void ProcessWindows::Initialize() {
120c5f28e2aSKamil Rytarowski   static llvm::once_flag g_once_flag;
1214ad5def9SAdrian McCarthy 
122c5f28e2aSKamil Rytarowski   llvm::call_once(g_once_flag, []() {
1234ad5def9SAdrian McCarthy     PluginManager::RegisterPlugin(GetPluginNameStatic(),
1244ad5def9SAdrian McCarthy                                   GetPluginDescriptionStatic(), CreateInstance);
1254ad5def9SAdrian McCarthy   });
1264ad5def9SAdrian McCarthy }
1274ad5def9SAdrian McCarthy 
1284ad5def9SAdrian McCarthy void ProcessWindows::Terminate() {}
1294ad5def9SAdrian McCarthy 
1304ad5def9SAdrian McCarthy lldb_private::ConstString ProcessWindows::GetPluginNameStatic() {
1314ad5def9SAdrian McCarthy   static ConstString g_name("windows");
1324ad5def9SAdrian McCarthy   return g_name;
1334ad5def9SAdrian McCarthy }
1344ad5def9SAdrian McCarthy 
1354ad5def9SAdrian McCarthy const char *ProcessWindows::GetPluginDescriptionStatic() {
1364ad5def9SAdrian McCarthy   return "Process plugin for Windows";
1374ad5def9SAdrian McCarthy }
1384ad5def9SAdrian McCarthy 
13918a9135dSAdrian McCarthy // Constructors and destructors.
14018a9135dSAdrian McCarthy 
141b9c1b51eSKate Stone ProcessWindows::ProcessWindows(lldb::TargetSP target_sp,
142b9c1b51eSKate Stone                                lldb::ListenerSP listener_sp)
143b9c1b51eSKate Stone     : lldb_private::Process(target_sp, listener_sp) {}
14418a9135dSAdrian McCarthy 
145b9c1b51eSKate Stone ProcessWindows::~ProcessWindows() {}
14618a9135dSAdrian McCarthy 
14797206d57SZachary Turner size_t ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Status &error) {
14818a9135dSAdrian McCarthy   error.SetErrorString("GetSTDOUT unsupported on Windows");
14918a9135dSAdrian McCarthy   return 0;
15018a9135dSAdrian McCarthy }
15118a9135dSAdrian McCarthy 
15297206d57SZachary Turner size_t ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Status &error) {
15318a9135dSAdrian McCarthy   error.SetErrorString("GetSTDERR unsupported on Windows");
15418a9135dSAdrian McCarthy   return 0;
15518a9135dSAdrian McCarthy }
15618a9135dSAdrian McCarthy 
157b9c1b51eSKate Stone size_t ProcessWindows::PutSTDIN(const char *buf, size_t buf_size,
15897206d57SZachary Turner                                 Status &error) {
15918a9135dSAdrian McCarthy   error.SetErrorString("PutSTDIN unsupported on Windows");
16018a9135dSAdrian McCarthy   return 0;
16118a9135dSAdrian McCarthy }
16218a9135dSAdrian McCarthy 
16318a9135dSAdrian McCarthy // ProcessInterface protocol.
16418a9135dSAdrian McCarthy 
1654ad5def9SAdrian McCarthy lldb_private::ConstString ProcessWindows::GetPluginName() {
1664ad5def9SAdrian McCarthy   return GetPluginNameStatic();
1674ad5def9SAdrian McCarthy }
1684ad5def9SAdrian McCarthy 
1694ad5def9SAdrian McCarthy uint32_t ProcessWindows::GetPluginVersion() { return 1; }
1704ad5def9SAdrian McCarthy 
17197206d57SZachary Turner Status ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) {
172a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS);
173a385d2c1SPavel Labath   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
174a385d2c1SPavel Labath            bp_site->GetID(), bp_site->GetLoadAddress());
1754ad5def9SAdrian McCarthy 
17697206d57SZachary Turner   Status error = EnableSoftwareBreakpoint(bp_site);
177a385d2c1SPavel Labath   if (!error.Success())
178a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
1794ad5def9SAdrian McCarthy   return error;
1804ad5def9SAdrian McCarthy }
1814ad5def9SAdrian McCarthy 
18297206d57SZachary Turner Status ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) {
183a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS);
184a385d2c1SPavel Labath   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
185a385d2c1SPavel Labath            bp_site->GetID(), bp_site->GetLoadAddress());
1864ad5def9SAdrian McCarthy 
18797206d57SZachary Turner   Status error = DisableSoftwareBreakpoint(bp_site);
1884ad5def9SAdrian McCarthy 
189a385d2c1SPavel Labath   if (!error.Success())
190a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
1914ad5def9SAdrian McCarthy   return error;
1924ad5def9SAdrian McCarthy }
1934ad5def9SAdrian McCarthy 
19497206d57SZachary Turner Status ProcessWindows::DoDetach(bool keep_stopped) {
1959c01eaffSAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
196*ed499a36SStella Stamenova   DebuggerThreadSP debugger_thread;
197*ed499a36SStella Stamenova   StateType private_state;
198*ed499a36SStella Stamenova   {
199*ed499a36SStella Stamenova     // Acquire the lock only long enough to get the DebuggerThread.
200*ed499a36SStella Stamenova     // StopDebugging() will trigger a call back into ProcessWindows which will
201*ed499a36SStella Stamenova     // also acquire the lock.  Thus we have to release the lock before calling
202*ed499a36SStella Stamenova     // StopDebugging().
203*ed499a36SStella Stamenova     llvm::sys::ScopedLock lock(m_mutex);
204*ed499a36SStella Stamenova 
205*ed499a36SStella Stamenova     private_state = GetPrivateState();
206*ed499a36SStella Stamenova 
207*ed499a36SStella Stamenova     if (!m_session_data) {
208*ed499a36SStella Stamenova       LLDB_LOG(log, "state = {0}, but there is no active session.",
209*ed499a36SStella Stamenova                private_state);
210*ed499a36SStella Stamenova       return Status();
2114ad5def9SAdrian McCarthy     }
212*ed499a36SStella Stamenova 
213*ed499a36SStella Stamenova     debugger_thread = m_session_data->m_debugger;
214*ed499a36SStella Stamenova   }
215*ed499a36SStella Stamenova 
216*ed499a36SStella Stamenova   Status error;
217*ed499a36SStella Stamenova   if (private_state != eStateExited && private_state != eStateDetached) {
218*ed499a36SStella Stamenova     LLDB_LOG(log, "detaching from process {0} while state = {1}.",
219*ed499a36SStella Stamenova              debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
220*ed499a36SStella Stamenova              private_state);
221*ed499a36SStella Stamenova     error = debugger_thread->StopDebugging(false);
222*ed499a36SStella Stamenova     if (error.Success()) {
223*ed499a36SStella Stamenova       SetPrivateState(eStateDetached);
224*ed499a36SStella Stamenova     }
225*ed499a36SStella Stamenova 
226*ed499a36SStella Stamenova     // By the time StopDebugging returns, there is no more debugger thread, so
227*ed499a36SStella Stamenova     // we can be assured that no other thread will race for the session data.
228*ed499a36SStella Stamenova     m_session_data.reset();
229*ed499a36SStella Stamenova   } else {
230*ed499a36SStella Stamenova     LLDB_LOG(
231*ed499a36SStella Stamenova         log,
232*ed499a36SStella Stamenova         "error: process {0} in state = {1}, but cannot destroy in this state.",
233*ed499a36SStella Stamenova         debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
234*ed499a36SStella Stamenova         private_state);
235*ed499a36SStella Stamenova   }
236*ed499a36SStella Stamenova 
2374ad5def9SAdrian McCarthy   return error;
2384ad5def9SAdrian McCarthy }
2394ad5def9SAdrian McCarthy 
24097206d57SZachary Turner Status ProcessWindows::DoLaunch(Module *exe_module,
2414ad5def9SAdrian McCarthy                                 ProcessLaunchInfo &launch_info) {
242*ed499a36SStella Stamenova   // Even though m_session_data is accessed here, it is before a debugger
243*ed499a36SStella Stamenova   // thread has been kicked off.  So there's no race conditions, and it
244*ed499a36SStella Stamenova   // shouldn't be necessary to acquire the mutex.
245*ed499a36SStella Stamenova 
246*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
247*ed499a36SStella Stamenova   Status result;
248*ed499a36SStella Stamenova 
249*ed499a36SStella Stamenova   FileSpec working_dir = launch_info.GetWorkingDirectory();
250*ed499a36SStella Stamenova   namespace fs = llvm::sys::fs;
251*ed499a36SStella Stamenova   if (working_dir) {
252*ed499a36SStella Stamenova     FileSystem::Instance().Resolve(working_dir);
253*ed499a36SStella Stamenova     if (!FileSystem::Instance().IsDirectory(working_dir)) {
254*ed499a36SStella Stamenova       result.SetErrorStringWithFormat("No such file or directory: %s",
255*ed499a36SStella Stamenova                                       working_dir.GetCString());
256*ed499a36SStella Stamenova       return result;
257*ed499a36SStella Stamenova     }
258*ed499a36SStella Stamenova   }
259*ed499a36SStella Stamenova 
260*ed499a36SStella Stamenova   if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) {
261*ed499a36SStella Stamenova     StreamString stream;
262*ed499a36SStella Stamenova     stream.Printf("ProcessWindows unable to launch '%s'.  ProcessWindows can "
263*ed499a36SStella Stamenova                   "only be used for debug launches.",
264*ed499a36SStella Stamenova                   launch_info.GetExecutableFile().GetPath().c_str());
265*ed499a36SStella Stamenova     std::string message = stream.GetString();
266*ed499a36SStella Stamenova     result.SetErrorString(message.c_str());
267*ed499a36SStella Stamenova 
268*ed499a36SStella Stamenova     LLDB_LOG(log, "error: {0}", message);
269*ed499a36SStella Stamenova     return result;
270*ed499a36SStella Stamenova   }
271*ed499a36SStella Stamenova 
272*ed499a36SStella Stamenova   bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
273*ed499a36SStella Stamenova   m_session_data.reset(new ProcessWindowsData(stop_at_entry));
274*ed499a36SStella Stamenova 
2754ad5def9SAdrian McCarthy   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
276*ed499a36SStella Stamenova   m_session_data->m_debugger.reset(new DebuggerThread(delegate));
277*ed499a36SStella Stamenova   DebuggerThreadSP debugger = m_session_data->m_debugger;
278*ed499a36SStella Stamenova 
279*ed499a36SStella Stamenova   // Kick off the DebugLaunch asynchronously and wait for it to complete.
280*ed499a36SStella Stamenova   result = debugger->DebugLaunch(launch_info);
281*ed499a36SStella Stamenova   if (result.Fail()) {
282*ed499a36SStella Stamenova     LLDB_LOG(log, "failed launching '{0}'. {1}",
283*ed499a36SStella Stamenova              launch_info.GetExecutableFile().GetPath(), result);
284*ed499a36SStella Stamenova     return result;
285*ed499a36SStella Stamenova   }
286*ed499a36SStella Stamenova 
287*ed499a36SStella Stamenova   HostProcess process;
288*ed499a36SStella Stamenova   Status error = WaitForDebuggerConnection(debugger, process);
289*ed499a36SStella Stamenova   if (error.Fail()) {
290*ed499a36SStella Stamenova     LLDB_LOG(log, "failed launching '{0}'. {1}",
291*ed499a36SStella Stamenova              launch_info.GetExecutableFile().GetPath(), error);
2924ad5def9SAdrian McCarthy     return error;
2934ad5def9SAdrian McCarthy   }
2944ad5def9SAdrian McCarthy 
295*ed499a36SStella Stamenova   LLDB_LOG(log, "successfully launched '{0}'",
296*ed499a36SStella Stamenova            launch_info.GetExecutableFile().GetPath());
297*ed499a36SStella Stamenova 
298*ed499a36SStella Stamenova   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
299*ed499a36SStella Stamenova   // private state should already be set to eStateStopped as a result of
300*ed499a36SStella Stamenova   // hitting the initial breakpoint.  If it was not set, the breakpoint should
301*ed499a36SStella Stamenova   // have already been resumed from and the private state should already be
302*ed499a36SStella Stamenova   // eStateRunning.
303*ed499a36SStella Stamenova   launch_info.SetProcessID(process.GetProcessId());
304*ed499a36SStella Stamenova   SetID(process.GetProcessId());
305*ed499a36SStella Stamenova 
306*ed499a36SStella Stamenova   return result;
307*ed499a36SStella Stamenova }
308*ed499a36SStella Stamenova 
30997206d57SZachary Turner Status
31097206d57SZachary Turner ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid,
31197206d57SZachary Turner                                         const ProcessAttachInfo &attach_info) {
312*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
313*ed499a36SStella Stamenova   m_session_data.reset(
314*ed499a36SStella Stamenova       new ProcessWindowsData(!attach_info.GetContinueOnceAttached()));
315*ed499a36SStella Stamenova 
3164ad5def9SAdrian McCarthy   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
317*ed499a36SStella Stamenova   DebuggerThreadSP debugger(new DebuggerThread(delegate));
318*ed499a36SStella Stamenova 
319*ed499a36SStella Stamenova   m_session_data->m_debugger = debugger;
320*ed499a36SStella Stamenova 
321*ed499a36SStella Stamenova   DWORD process_id = static_cast<DWORD>(pid);
322*ed499a36SStella Stamenova   Status error = debugger->DebugAttach(process_id, attach_info);
323*ed499a36SStella Stamenova   if (error.Fail()) {
324*ed499a36SStella Stamenova     LLDB_LOG(
325*ed499a36SStella Stamenova         log,
326*ed499a36SStella Stamenova         "encountered an error occurred initiating the asynchronous attach. {0}",
327*ed499a36SStella Stamenova         error);
328*ed499a36SStella Stamenova     return error;
329*ed499a36SStella Stamenova   }
330*ed499a36SStella Stamenova 
331*ed499a36SStella Stamenova   HostProcess process;
332*ed499a36SStella Stamenova   error = WaitForDebuggerConnection(debugger, process);
333*ed499a36SStella Stamenova   if (error.Fail()) {
334*ed499a36SStella Stamenova     LLDB_LOG(log,
335*ed499a36SStella Stamenova              "encountered an error waiting for the debugger to connect. {0}",
336*ed499a36SStella Stamenova              error);
337*ed499a36SStella Stamenova     return error;
338*ed499a36SStella Stamenova   }
339*ed499a36SStella Stamenova 
340*ed499a36SStella Stamenova   LLDB_LOG(log, "successfully attached to process with pid={0}", process_id);
341*ed499a36SStella Stamenova 
342*ed499a36SStella Stamenova   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
343*ed499a36SStella Stamenova   // private state should already be set to eStateStopped as a result of
344*ed499a36SStella Stamenova   // hitting the initial breakpoint.  If it was not set, the breakpoint should
345*ed499a36SStella Stamenova   // have already been resumed from and the private state should already be
346*ed499a36SStella Stamenova   // eStateRunning.
347*ed499a36SStella Stamenova   SetID(process.GetProcessId());
3484ad5def9SAdrian McCarthy   return error;
3494ad5def9SAdrian McCarthy }
3504ad5def9SAdrian McCarthy 
35197206d57SZachary Turner Status ProcessWindows::DoResume() {
352a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
3534ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
35497206d57SZachary Turner   Status error;
3554ad5def9SAdrian McCarthy 
3564ad5def9SAdrian McCarthy   StateType private_state = GetPrivateState();
3574ad5def9SAdrian McCarthy   if (private_state == eStateStopped || private_state == eStateCrashed) {
358a385d2c1SPavel Labath     LLDB_LOG(log, "process {0} is in state {1}.  Resuming...",
3594ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId(),
3604ad5def9SAdrian McCarthy              GetPrivateState());
3614ad5def9SAdrian McCarthy 
3624ad5def9SAdrian McCarthy     ExceptionRecordSP active_exception =
3634ad5def9SAdrian McCarthy         m_session_data->m_debugger->GetActiveException().lock();
3644ad5def9SAdrian McCarthy     if (active_exception) {
36505097246SAdrian Prantl       // Resume the process and continue processing debug events.  Mask the
36605097246SAdrian Prantl       // exception so that from the process's view, there is no indication that
36705097246SAdrian Prantl       // anything happened.
3684ad5def9SAdrian McCarthy       m_session_data->m_debugger->ContinueAsyncException(
3694ad5def9SAdrian McCarthy           ExceptionResult::MaskException);
3704ad5def9SAdrian McCarthy     }
3714ad5def9SAdrian McCarthy 
372a385d2c1SPavel Labath     LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize());
3734ad5def9SAdrian McCarthy 
3740fd67b53SStella Stamenova     bool failed = false;
3754ad5def9SAdrian McCarthy     for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) {
3764ad5def9SAdrian McCarthy       auto thread = std::static_pointer_cast<TargetThreadWindows>(
3774ad5def9SAdrian McCarthy           m_thread_list.GetThreadAtIndex(i));
3780fd67b53SStella Stamenova       Status result = thread->DoResume();
3790fd67b53SStella Stamenova       if (result.Fail()) {
3800fd67b53SStella Stamenova         failed = true;
38162c76db4SStella Stamenova         LLDB_LOG(
38262c76db4SStella Stamenova             log,
38362c76db4SStella Stamenova             "Trying to resume thread at index {0}, but failed with error {1}.",
38462c76db4SStella Stamenova             i, result);
3850fd67b53SStella Stamenova       }
3864ad5def9SAdrian McCarthy     }
3874ad5def9SAdrian McCarthy 
3880fd67b53SStella Stamenova     if (failed) {
3890fd67b53SStella Stamenova       error.SetErrorString("ProcessWindows::DoResume failed");
3900fd67b53SStella Stamenova       return error;
3910fd67b53SStella Stamenova     } else {
3924ad5def9SAdrian McCarthy       SetPrivateState(eStateRunning);
3930fd67b53SStella Stamenova     }
3944ad5def9SAdrian McCarthy   } else {
395c28daec5SAaron Smith     LLDB_LOG(log, "error: process {0} is in state {1}.  Returning...",
3964ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId(),
3974ad5def9SAdrian McCarthy              GetPrivateState());
3984ad5def9SAdrian McCarthy   }
3994ad5def9SAdrian McCarthy   return error;
4004ad5def9SAdrian McCarthy }
4014ad5def9SAdrian McCarthy 
40297206d57SZachary Turner Status ProcessWindows::DoDestroy() {
4039c01eaffSAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
404*ed499a36SStella Stamenova   DebuggerThreadSP debugger_thread;
405*ed499a36SStella Stamenova   StateType private_state;
406*ed499a36SStella Stamenova   {
407*ed499a36SStella Stamenova     // Acquire this lock inside an inner scope, only long enough to get the
408*ed499a36SStella Stamenova     // DebuggerThread. StopDebugging() will trigger a call back into
409*ed499a36SStella Stamenova     // ProcessWindows which will acquire the lock again, so we need to not
410*ed499a36SStella Stamenova     // deadlock.
411*ed499a36SStella Stamenova     llvm::sys::ScopedLock lock(m_mutex);
412*ed499a36SStella Stamenova 
413*ed499a36SStella Stamenova     private_state = GetPrivateState();
414*ed499a36SStella Stamenova 
415*ed499a36SStella Stamenova     if (!m_session_data) {
416*ed499a36SStella Stamenova       LLDB_LOG(log, "warning: state = {0}, but there is no active session.",
417*ed499a36SStella Stamenova                private_state);
418*ed499a36SStella Stamenova       return Status();
4194ad5def9SAdrian McCarthy     }
420*ed499a36SStella Stamenova 
421*ed499a36SStella Stamenova     debugger_thread = m_session_data->m_debugger;
422*ed499a36SStella Stamenova   }
423*ed499a36SStella Stamenova 
424*ed499a36SStella Stamenova   Status error;
425*ed499a36SStella Stamenova   if (private_state != eStateExited && private_state != eStateDetached) {
426*ed499a36SStella Stamenova     LLDB_LOG(log, "Shutting down process {0} while state = {1}.",
427*ed499a36SStella Stamenova              debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
428*ed499a36SStella Stamenova              private_state);
429*ed499a36SStella Stamenova     error = debugger_thread->StopDebugging(true);
430*ed499a36SStella Stamenova 
431*ed499a36SStella Stamenova     // By the time StopDebugging returns, there is no more debugger thread, so
432*ed499a36SStella Stamenova     // we can be assured that no other thread will race for the session data.
433*ed499a36SStella Stamenova     m_session_data.reset();
434*ed499a36SStella Stamenova   } else {
435*ed499a36SStella Stamenova     LLDB_LOG(log, "cannot destroy process {0} while state = {1}",
436*ed499a36SStella Stamenova              debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
437*ed499a36SStella Stamenova              private_state);
438*ed499a36SStella Stamenova   }
439*ed499a36SStella Stamenova 
4404ad5def9SAdrian McCarthy   return error;
4414ad5def9SAdrian McCarthy }
4424ad5def9SAdrian McCarthy 
44397206d57SZachary Turner Status ProcessWindows::DoHalt(bool &caused_stop) {
444*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
445*ed499a36SStella Stamenova   Status error;
4464ad5def9SAdrian McCarthy   StateType state = GetPrivateState();
447*ed499a36SStella Stamenova   if (state == eStateStopped)
4484ad5def9SAdrian McCarthy     caused_stop = false;
449*ed499a36SStella Stamenova   else {
450*ed499a36SStella Stamenova     llvm::sys::ScopedLock lock(m_mutex);
451*ed499a36SStella Stamenova     caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess()
452*ed499a36SStella Stamenova                                           .GetNativeProcess()
453*ed499a36SStella Stamenova                                           .GetSystemHandle());
454*ed499a36SStella Stamenova     if (!caused_stop) {
455*ed499a36SStella Stamenova       error.SetError(::GetLastError(), eErrorTypeWin32);
456*ed499a36SStella Stamenova       LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error);
457*ed499a36SStella Stamenova     }
458*ed499a36SStella Stamenova   }
459*ed499a36SStella Stamenova   return error;
4604ad5def9SAdrian McCarthy }
4614ad5def9SAdrian McCarthy 
4624ad5def9SAdrian McCarthy void ProcessWindows::DidLaunch() {
4634ad5def9SAdrian McCarthy   ArchSpec arch_spec;
4644ad5def9SAdrian McCarthy   DidAttach(arch_spec);
4654ad5def9SAdrian McCarthy }
4664ad5def9SAdrian McCarthy 
4674ad5def9SAdrian McCarthy void ProcessWindows::DidAttach(ArchSpec &arch_spec) {
4684ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
4694ad5def9SAdrian McCarthy 
4704ad5def9SAdrian McCarthy   // The initial stop won't broadcast the state change event, so account for
4714ad5def9SAdrian McCarthy   // that here.
4724ad5def9SAdrian McCarthy   if (m_session_data && GetPrivateState() == eStateStopped &&
4734ad5def9SAdrian McCarthy       m_session_data->m_stop_at_entry)
4744ad5def9SAdrian McCarthy     RefreshStateAfterStop();
4754ad5def9SAdrian McCarthy }
4764ad5def9SAdrian McCarthy 
47726366c3eSAleksandr Urakov static void
47826366c3eSAleksandr Urakov DumpAdditionalExceptionInformation(llvm::raw_ostream &stream,
47926366c3eSAleksandr Urakov                                    const ExceptionRecordSP &exception) {
48026366c3eSAleksandr Urakov   // Decode additional exception information for specific exception types based
48126366c3eSAleksandr Urakov   // on
48226366c3eSAleksandr Urakov   // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_exception_record
48326366c3eSAleksandr Urakov 
48426366c3eSAleksandr Urakov   const int addr_min_width = 2 + 8; // "0x" + 4 address bytes
48526366c3eSAleksandr Urakov 
48626366c3eSAleksandr Urakov   const std::vector<ULONG_PTR> &args = exception->GetExceptionArguments();
48726366c3eSAleksandr Urakov   switch (exception->GetExceptionCode()) {
48826366c3eSAleksandr Urakov   case EXCEPTION_ACCESS_VIOLATION: {
48926366c3eSAleksandr Urakov     if (args.size() < 2)
49026366c3eSAleksandr Urakov       break;
49126366c3eSAleksandr Urakov 
49226366c3eSAleksandr Urakov     stream << ": ";
49326366c3eSAleksandr Urakov     const int access_violation_code = args[0];
49426366c3eSAleksandr Urakov     const lldb::addr_t access_violation_address = args[1];
49526366c3eSAleksandr Urakov     switch (access_violation_code) {
49626366c3eSAleksandr Urakov     case 0:
49726366c3eSAleksandr Urakov       stream << "Access violation reading";
49826366c3eSAleksandr Urakov       break;
49926366c3eSAleksandr Urakov     case 1:
50026366c3eSAleksandr Urakov       stream << "Access violation writing";
50126366c3eSAleksandr Urakov       break;
50226366c3eSAleksandr Urakov     case 8:
50326366c3eSAleksandr Urakov       stream << "User-mode data execution prevention (DEP) violation at";
50426366c3eSAleksandr Urakov       break;
50526366c3eSAleksandr Urakov     default:
50626366c3eSAleksandr Urakov       stream << "Unknown access violation (code " << access_violation_code
50726366c3eSAleksandr Urakov              << ") at";
50826366c3eSAleksandr Urakov       break;
50926366c3eSAleksandr Urakov     }
51026366c3eSAleksandr Urakov     stream << " location "
51126366c3eSAleksandr Urakov            << llvm::format_hex(access_violation_address, addr_min_width);
51226366c3eSAleksandr Urakov     break;
51326366c3eSAleksandr Urakov   }
51426366c3eSAleksandr Urakov   case EXCEPTION_IN_PAGE_ERROR: {
51526366c3eSAleksandr Urakov     if (args.size() < 3)
51626366c3eSAleksandr Urakov       break;
51726366c3eSAleksandr Urakov 
51826366c3eSAleksandr Urakov     stream << ": ";
51926366c3eSAleksandr Urakov     const int page_load_error_code = args[0];
52026366c3eSAleksandr Urakov     const lldb::addr_t page_load_error_address = args[1];
52126366c3eSAleksandr Urakov     const DWORD underlying_code = args[2];
52226366c3eSAleksandr Urakov     switch (page_load_error_code) {
52326366c3eSAleksandr Urakov     case 0:
52426366c3eSAleksandr Urakov       stream << "In page error reading";
52526366c3eSAleksandr Urakov       break;
52626366c3eSAleksandr Urakov     case 1:
52726366c3eSAleksandr Urakov       stream << "In page error writing";
52826366c3eSAleksandr Urakov       break;
52926366c3eSAleksandr Urakov     case 8:
53026366c3eSAleksandr Urakov       stream << "User-mode data execution prevention (DEP) violation at";
53126366c3eSAleksandr Urakov       break;
53226366c3eSAleksandr Urakov     default:
53326366c3eSAleksandr Urakov       stream << "Unknown page loading error (code " << page_load_error_code
53426366c3eSAleksandr Urakov              << ") at";
53526366c3eSAleksandr Urakov       break;
53626366c3eSAleksandr Urakov     }
53726366c3eSAleksandr Urakov     stream << " location "
53826366c3eSAleksandr Urakov            << llvm::format_hex(page_load_error_address, addr_min_width)
53926366c3eSAleksandr Urakov            << " (status code " << llvm::format_hex(underlying_code, 8) << ")";
54026366c3eSAleksandr Urakov     break;
54126366c3eSAleksandr Urakov   }
54226366c3eSAleksandr Urakov   }
54326366c3eSAleksandr Urakov }
54426366c3eSAleksandr Urakov 
5454ad5def9SAdrian McCarthy void ProcessWindows::RefreshStateAfterStop() {
546a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
5474ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
5484ad5def9SAdrian McCarthy 
5494ad5def9SAdrian McCarthy   if (!m_session_data) {
550a385d2c1SPavel Labath     LLDB_LOG(log, "no active session.  Returning...");
5514ad5def9SAdrian McCarthy     return;
5524ad5def9SAdrian McCarthy   }
5534ad5def9SAdrian McCarthy 
5544ad5def9SAdrian McCarthy   m_thread_list.RefreshStateAfterStop();
5554ad5def9SAdrian McCarthy 
5564ad5def9SAdrian McCarthy   std::weak_ptr<ExceptionRecord> exception_record =
5574ad5def9SAdrian McCarthy       m_session_data->m_debugger->GetActiveException();
5584ad5def9SAdrian McCarthy   ExceptionRecordSP active_exception = exception_record.lock();
5594ad5def9SAdrian McCarthy   if (!active_exception) {
56062c76db4SStella Stamenova     LLDB_LOG(log,
56162c76db4SStella Stamenova              "there is no active exception in process {0}.  Why is the "
562a385d2c1SPavel Labath              "process stopped?",
5634ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId());
5644ad5def9SAdrian McCarthy     return;
5654ad5def9SAdrian McCarthy   }
5664ad5def9SAdrian McCarthy 
5674ad5def9SAdrian McCarthy   StopInfoSP stop_info;
5684ad5def9SAdrian McCarthy   m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID());
5694ad5def9SAdrian McCarthy   ThreadSP stop_thread = m_thread_list.GetSelectedThread();
5704ad5def9SAdrian McCarthy   if (!stop_thread)
5714ad5def9SAdrian McCarthy     return;
5724ad5def9SAdrian McCarthy 
5734ad5def9SAdrian McCarthy   switch (active_exception->GetExceptionCode()) {
5744ad5def9SAdrian McCarthy   case EXCEPTION_SINGLE_STEP: {
5754ad5def9SAdrian McCarthy     RegisterContextSP register_context = stop_thread->GetRegisterContext();
5764ad5def9SAdrian McCarthy     const uint64_t pc = register_context->GetPC();
5774ad5def9SAdrian McCarthy     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
5784ad5def9SAdrian McCarthy     if (site && site->ValidForThisThread(stop_thread.get())) {
57962c76db4SStella Stamenova       LLDB_LOG(log,
58062c76db4SStella Stamenova                "Single-stepped onto a breakpoint in process {0} at "
581a385d2c1SPavel Labath                "address {1:x} with breakpoint site {2}",
5824ad5def9SAdrian McCarthy                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
5834ad5def9SAdrian McCarthy                site->GetID());
5844ad5def9SAdrian McCarthy       stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread,
5854ad5def9SAdrian McCarthy                                                                  site->GetID());
5864ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
5874ad5def9SAdrian McCarthy     } else {
588a385d2c1SPavel Labath       LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID());
5894ad5def9SAdrian McCarthy       stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
5904ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
5914ad5def9SAdrian McCarthy     }
5924ad5def9SAdrian McCarthy     return;
5934ad5def9SAdrian McCarthy   }
5944ad5def9SAdrian McCarthy 
5954ad5def9SAdrian McCarthy   case EXCEPTION_BREAKPOINT: {
5964ad5def9SAdrian McCarthy     RegisterContextSP register_context = stop_thread->GetRegisterContext();
5974ad5def9SAdrian McCarthy 
5984ad5def9SAdrian McCarthy     // The current EIP is AFTER the BP opcode, which is one byte.
5994ad5def9SAdrian McCarthy     uint64_t pc = register_context->GetPC() - 1;
6004ad5def9SAdrian McCarthy 
6014ad5def9SAdrian McCarthy     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
6024ad5def9SAdrian McCarthy     if (site) {
60362c76db4SStella Stamenova       LLDB_LOG(log,
60462c76db4SStella Stamenova                "detected breakpoint in process {0} at address {1:x} with "
605a385d2c1SPavel Labath                "breakpoint site {2}",
6064ad5def9SAdrian McCarthy                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
6074ad5def9SAdrian McCarthy                site->GetID());
6084ad5def9SAdrian McCarthy 
6094ad5def9SAdrian McCarthy       if (site->ValidForThisThread(stop_thread.get())) {
61062c76db4SStella Stamenova         LLDB_LOG(log,
61162c76db4SStella Stamenova                  "Breakpoint site {0} is valid for this thread ({1:x}), "
6124ad5def9SAdrian McCarthy                  "creating stop info.",
6134ad5def9SAdrian McCarthy                  site->GetID(), stop_thread->GetID());
6144ad5def9SAdrian McCarthy 
6154ad5def9SAdrian McCarthy         stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
6164ad5def9SAdrian McCarthy             *stop_thread, site->GetID());
6174ad5def9SAdrian McCarthy         register_context->SetPC(pc);
6184ad5def9SAdrian McCarthy       } else {
61962c76db4SStella Stamenova         LLDB_LOG(log,
62062c76db4SStella Stamenova                  "Breakpoint site {0} is not valid for this thread, "
6214ad5def9SAdrian McCarthy                  "creating empty stop info.",
6224ad5def9SAdrian McCarthy                  site->GetID());
6234ad5def9SAdrian McCarthy       }
6244ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
6254ad5def9SAdrian McCarthy       return;
6264ad5def9SAdrian McCarthy     } else {
6274ad5def9SAdrian McCarthy       // The thread hit a hard-coded breakpoint like an `int 3` or
6284ad5def9SAdrian McCarthy       // `__debugbreak()`.
629a385d2c1SPavel Labath       LLDB_LOG(log,
6304ad5def9SAdrian McCarthy                "No breakpoint site matches for this thread. __debugbreak()?  "
6314ad5def9SAdrian McCarthy                "Creating stop info with the exception.");
6324ad5def9SAdrian McCarthy       // FALLTHROUGH:  We'll treat this as a generic exception record in the
6334ad5def9SAdrian McCarthy       // default case.
634b0717666SAlexandre Ganea       LLVM_FALLTHROUGH;
6354ad5def9SAdrian McCarthy     }
6364ad5def9SAdrian McCarthy   }
6374ad5def9SAdrian McCarthy 
6384ad5def9SAdrian McCarthy   default: {
6394ad5def9SAdrian McCarthy     std::string desc;
6404ad5def9SAdrian McCarthy     llvm::raw_string_ostream desc_stream(desc);
6414ad5def9SAdrian McCarthy     desc_stream << "Exception "
6424ad5def9SAdrian McCarthy                 << llvm::format_hex(active_exception->GetExceptionCode(), 8)
6434ad5def9SAdrian McCarthy                 << " encountered at address "
6444ad5def9SAdrian McCarthy                 << llvm::format_hex(active_exception->GetExceptionAddress(), 8);
64526366c3eSAleksandr Urakov     DumpAdditionalExceptionInformation(desc_stream, active_exception);
64626366c3eSAleksandr Urakov 
6474ad5def9SAdrian McCarthy     stop_info = StopInfo::CreateStopReasonWithException(
6484ad5def9SAdrian McCarthy         *stop_thread, desc_stream.str().c_str());
6494ad5def9SAdrian McCarthy     stop_thread->SetStopInfo(stop_info);
650a385d2c1SPavel Labath     LLDB_LOG(log, "{0}", desc_stream.str());
6514ad5def9SAdrian McCarthy     return;
6524ad5def9SAdrian McCarthy   }
6534ad5def9SAdrian McCarthy   }
6544ad5def9SAdrian McCarthy }
6554ad5def9SAdrian McCarthy 
6564ad5def9SAdrian McCarthy bool ProcessWindows::CanDebug(lldb::TargetSP target_sp,
6574ad5def9SAdrian McCarthy                               bool plugin_specified_by_name) {
6584ad5def9SAdrian McCarthy   if (plugin_specified_by_name)
6594ad5def9SAdrian McCarthy     return true;
6604ad5def9SAdrian McCarthy 
6614ad5def9SAdrian McCarthy   // For now we are just making sure the file exists for a given module
6624ad5def9SAdrian McCarthy   ModuleSP exe_module_sp(target_sp->GetExecutableModule());
6634ad5def9SAdrian McCarthy   if (exe_module_sp.get())
66460cf3f82SJonas Devlieghere     return FileSystem::Instance().Exists(exe_module_sp->GetFileSpec());
66505097246SAdrian Prantl   // However, if there is no executable module, we return true since we might
66605097246SAdrian Prantl   // be preparing to attach.
6674ad5def9SAdrian McCarthy   return true;
6684ad5def9SAdrian McCarthy }
6694ad5def9SAdrian McCarthy 
6704ad5def9SAdrian McCarthy bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list,
6714ad5def9SAdrian McCarthy                                       ThreadList &new_thread_list) {
672a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_THREAD);
6734ad5def9SAdrian McCarthy   // Add all the threads that were previously running and for which we did not
6744ad5def9SAdrian McCarthy   // detect a thread exited event.
6754ad5def9SAdrian McCarthy   int new_size = 0;
6764ad5def9SAdrian McCarthy   int continued_threads = 0;
6774ad5def9SAdrian McCarthy   int exited_threads = 0;
6784ad5def9SAdrian McCarthy   int new_threads = 0;
6794ad5def9SAdrian McCarthy 
6804ad5def9SAdrian McCarthy   for (ThreadSP old_thread : old_thread_list.Threads()) {
6814ad5def9SAdrian McCarthy     lldb::tid_t old_thread_id = old_thread->GetID();
6824ad5def9SAdrian McCarthy     auto exited_thread_iter =
6834ad5def9SAdrian McCarthy         m_session_data->m_exited_threads.find(old_thread_id);
6844ad5def9SAdrian McCarthy     if (exited_thread_iter == m_session_data->m_exited_threads.end()) {
6854ad5def9SAdrian McCarthy       new_thread_list.AddThread(old_thread);
6864ad5def9SAdrian McCarthy       ++new_size;
6874ad5def9SAdrian McCarthy       ++continued_threads;
688a385d2c1SPavel Labath       LLDB_LOGV(log, "Thread {0} was running and is still running.",
6894ad5def9SAdrian McCarthy                 old_thread_id);
6904ad5def9SAdrian McCarthy     } else {
691a385d2c1SPavel Labath       LLDB_LOGV(log, "Thread {0} was running and has exited.", old_thread_id);
6924ad5def9SAdrian McCarthy       ++exited_threads;
6934ad5def9SAdrian McCarthy     }
6944ad5def9SAdrian McCarthy   }
6954ad5def9SAdrian McCarthy 
69605097246SAdrian Prantl   // Also add all the threads that are new since the last time we broke into
69705097246SAdrian Prantl   // the debugger.
6984ad5def9SAdrian McCarthy   for (const auto &thread_info : m_session_data->m_new_threads) {
6994ad5def9SAdrian McCarthy     ThreadSP thread(new TargetThreadWindows(*this, thread_info.second));
7004ad5def9SAdrian McCarthy     thread->SetID(thread_info.first);
7014ad5def9SAdrian McCarthy     new_thread_list.AddThread(thread);
7024ad5def9SAdrian McCarthy     ++new_size;
7034ad5def9SAdrian McCarthy     ++new_threads;
704a385d2c1SPavel Labath     LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first);
7054ad5def9SAdrian McCarthy   }
7064ad5def9SAdrian McCarthy 
707a385d2c1SPavel Labath   LLDB_LOG(log, "{0} new threads, {1} old threads, {2} exited threads.",
7084ad5def9SAdrian McCarthy            new_threads, continued_threads, exited_threads);
7094ad5def9SAdrian McCarthy 
7104ad5def9SAdrian McCarthy   m_session_data->m_new_threads.clear();
7114ad5def9SAdrian McCarthy   m_session_data->m_exited_threads.clear();
7124ad5def9SAdrian McCarthy 
7134ad5def9SAdrian McCarthy   return new_size > 0;
7144ad5def9SAdrian McCarthy }
7154ad5def9SAdrian McCarthy 
7164ad5def9SAdrian McCarthy bool ProcessWindows::IsAlive() {
7174ad5def9SAdrian McCarthy   StateType state = GetPrivateState();
7184ad5def9SAdrian McCarthy   switch (state) {
7194ad5def9SAdrian McCarthy   case eStateCrashed:
7204ad5def9SAdrian McCarthy   case eStateDetached:
7214ad5def9SAdrian McCarthy   case eStateUnloaded:
7224ad5def9SAdrian McCarthy   case eStateExited:
7234ad5def9SAdrian McCarthy   case eStateInvalid:
7244ad5def9SAdrian McCarthy     return false;
7254ad5def9SAdrian McCarthy   default:
7264ad5def9SAdrian McCarthy     return true;
7274ad5def9SAdrian McCarthy   }
7284ad5def9SAdrian McCarthy }
7294ad5def9SAdrian McCarthy 
7304ad5def9SAdrian McCarthy size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf,
73197206d57SZachary Turner                                     size_t size, Status &error) {
732*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
733*ed499a36SStella Stamenova   llvm::sys::ScopedLock lock(m_mutex);
734*ed499a36SStella Stamenova 
735*ed499a36SStella Stamenova   if (!m_session_data)
736*ed499a36SStella Stamenova     return 0;
737*ed499a36SStella Stamenova 
738*ed499a36SStella Stamenova   LLDB_LOG(log, "attempting to read {0} bytes from address {1:x}", size,
739*ed499a36SStella Stamenova            vm_addr);
740*ed499a36SStella Stamenova 
741*ed499a36SStella Stamenova   HostProcess process = m_session_data->m_debugger->GetProcess();
742*ed499a36SStella Stamenova   void *addr = reinterpret_cast<void *>(vm_addr);
743*ed499a36SStella Stamenova   SIZE_T bytes_read = 0;
744*ed499a36SStella Stamenova   if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr,
745*ed499a36SStella Stamenova                          buf, size, &bytes_read)) {
746*ed499a36SStella Stamenova     // Reading from the process can fail for a number of reasons - set the
747*ed499a36SStella Stamenova     // error code and make sure that the number of bytes read is set back to 0
748*ed499a36SStella Stamenova     // because in some scenarios the value of bytes_read returned from the API
749*ed499a36SStella Stamenova     // is garbage.
750*ed499a36SStella Stamenova     error.SetError(GetLastError(), eErrorTypeWin32);
751*ed499a36SStella Stamenova     LLDB_LOG(log, "reading failed with error: {0}", error);
752*ed499a36SStella Stamenova     bytes_read = 0;
753*ed499a36SStella Stamenova   }
7544ad5def9SAdrian McCarthy   return bytes_read;
7554ad5def9SAdrian McCarthy }
7564ad5def9SAdrian McCarthy 
7574ad5def9SAdrian McCarthy size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
75897206d57SZachary Turner                                      size_t size, Status &error) {
759*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
760*ed499a36SStella Stamenova   llvm::sys::ScopedLock lock(m_mutex);
761*ed499a36SStella Stamenova   LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size,
762*ed499a36SStella Stamenova            vm_addr);
763*ed499a36SStella Stamenova 
764*ed499a36SStella Stamenova   if (!m_session_data) {
765*ed499a36SStella Stamenova     LLDB_LOG(log, "cannot write, there is no active debugger connection.");
766*ed499a36SStella Stamenova     return 0;
767*ed499a36SStella Stamenova   }
768*ed499a36SStella Stamenova 
769*ed499a36SStella Stamenova   HostProcess process = m_session_data->m_debugger->GetProcess();
770*ed499a36SStella Stamenova   void *addr = reinterpret_cast<void *>(vm_addr);
771*ed499a36SStella Stamenova   SIZE_T bytes_written = 0;
772*ed499a36SStella Stamenova   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
773*ed499a36SStella Stamenova   if (WriteProcessMemory(handle, addr, buf, size, &bytes_written))
774*ed499a36SStella Stamenova     FlushInstructionCache(handle, addr, bytes_written);
775*ed499a36SStella Stamenova   else {
776*ed499a36SStella Stamenova     error.SetError(GetLastError(), eErrorTypeWin32);
777*ed499a36SStella Stamenova     LLDB_LOG(log, "writing failed with error: {0}", error);
778*ed499a36SStella Stamenova   }
7794ad5def9SAdrian McCarthy   return bytes_written;
7804ad5def9SAdrian McCarthy }
7814ad5def9SAdrian McCarthy 
7829d5b2d4aSAleksandr Urakov lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions,
7839d5b2d4aSAleksandr Urakov                                               Status &error) {
784*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
785*ed499a36SStella Stamenova   llvm::sys::ScopedLock lock(m_mutex);
786*ed499a36SStella Stamenova   LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size,
787*ed499a36SStella Stamenova            permissions);
788*ed499a36SStella Stamenova 
789*ed499a36SStella Stamenova   if (!m_session_data) {
790*ed499a36SStella Stamenova     LLDB_LOG(log, "cannot allocate, there is no active debugger connection.");
791*ed499a36SStella Stamenova     error.SetErrorString(
792*ed499a36SStella Stamenova         "cannot allocate, there is no active debugger connection");
793*ed499a36SStella Stamenova     return LLDB_INVALID_ADDRESS;
794*ed499a36SStella Stamenova   }
795*ed499a36SStella Stamenova 
796*ed499a36SStella Stamenova   HostProcess process = m_session_data->m_debugger->GetProcess();
797*ed499a36SStella Stamenova   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
798*ed499a36SStella Stamenova   auto protect = ConvertLldbToWinApiProtect(permissions);
799*ed499a36SStella Stamenova   auto result = VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect);
800*ed499a36SStella Stamenova   if (!result) {
801*ed499a36SStella Stamenova     error.SetError(GetLastError(), eErrorTypeWin32);
802*ed499a36SStella Stamenova     LLDB_LOG(log, "allocating failed with error: {0}", error);
803*ed499a36SStella Stamenova     return LLDB_INVALID_ADDRESS;
804*ed499a36SStella Stamenova   }
805*ed499a36SStella Stamenova 
806*ed499a36SStella Stamenova   return reinterpret_cast<addr_t>(result);
8079d5b2d4aSAleksandr Urakov }
8089d5b2d4aSAleksandr Urakov 
8099d5b2d4aSAleksandr Urakov Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) {
810*ed499a36SStella Stamenova   Status result;
811*ed499a36SStella Stamenova 
812*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
813*ed499a36SStella Stamenova   llvm::sys::ScopedLock lock(m_mutex);
814*ed499a36SStella Stamenova   LLDB_LOG(log, "attempting to deallocate bytes at address {0}", ptr);
815*ed499a36SStella Stamenova 
816*ed499a36SStella Stamenova   if (!m_session_data) {
817*ed499a36SStella Stamenova     LLDB_LOG(log, "cannot deallocate, there is no active debugger connection.");
818*ed499a36SStella Stamenova     result.SetErrorString(
819*ed499a36SStella Stamenova         "cannot deallocate, there is no active debugger connection");
820*ed499a36SStella Stamenova     return result;
821*ed499a36SStella Stamenova   }
822*ed499a36SStella Stamenova 
823*ed499a36SStella Stamenova   HostProcess process = m_session_data->m_debugger->GetProcess();
824*ed499a36SStella Stamenova   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
825*ed499a36SStella Stamenova   if (!VirtualFreeEx(handle, reinterpret_cast<LPVOID>(ptr), 0, MEM_RELEASE)) {
826*ed499a36SStella Stamenova     result.SetError(GetLastError(), eErrorTypeWin32);
827*ed499a36SStella Stamenova     LLDB_LOG(log, "deallocating failed with error: {0}", result);
828*ed499a36SStella Stamenova     return result;
829*ed499a36SStella Stamenova   }
830*ed499a36SStella Stamenova 
831*ed499a36SStella Stamenova   return result;
8329d5b2d4aSAleksandr Urakov }
8339d5b2d4aSAleksandr Urakov 
83497206d57SZachary Turner Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr,
8354ad5def9SAdrian McCarthy                                            MemoryRegionInfo &info) {
836*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
837*ed499a36SStella Stamenova   Status error;
838*ed499a36SStella Stamenova   llvm::sys::ScopedLock lock(m_mutex);
839*ed499a36SStella Stamenova   info.Clear();
840*ed499a36SStella Stamenova 
841*ed499a36SStella Stamenova   if (!m_session_data) {
842*ed499a36SStella Stamenova     error.SetErrorString(
843*ed499a36SStella Stamenova         "GetMemoryRegionInfo called with no debugging session.");
844*ed499a36SStella Stamenova     LLDB_LOG(log, "error: {0}", error);
845*ed499a36SStella Stamenova     return error;
846*ed499a36SStella Stamenova   }
847*ed499a36SStella Stamenova   HostProcess process = m_session_data->m_debugger->GetProcess();
848*ed499a36SStella Stamenova   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
849*ed499a36SStella Stamenova   if (handle == nullptr || handle == LLDB_INVALID_PROCESS) {
850*ed499a36SStella Stamenova     error.SetErrorString(
851*ed499a36SStella Stamenova         "GetMemoryRegionInfo called with an invalid target process.");
852*ed499a36SStella Stamenova     LLDB_LOG(log, "error: {0}", error);
853*ed499a36SStella Stamenova     return error;
854*ed499a36SStella Stamenova   }
855*ed499a36SStella Stamenova 
856*ed499a36SStella Stamenova   LLDB_LOG(log, "getting info for address {0:x}", vm_addr);
857*ed499a36SStella Stamenova 
858*ed499a36SStella Stamenova   void *addr = reinterpret_cast<void *>(vm_addr);
859*ed499a36SStella Stamenova   MEMORY_BASIC_INFORMATION mem_info = {};
860*ed499a36SStella Stamenova   SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
861*ed499a36SStella Stamenova   if (result == 0) {
862*ed499a36SStella Stamenova     if (::GetLastError() == ERROR_INVALID_PARAMETER) {
863*ed499a36SStella Stamenova       // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with
864*ed499a36SStella Stamenova       // an address past the highest accessible address. We should return a
865*ed499a36SStella Stamenova       // range from the vm_addr to LLDB_INVALID_ADDRESS
866*ed499a36SStella Stamenova       info.GetRange().SetRangeBase(vm_addr);
867*ed499a36SStella Stamenova       info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
868*ed499a36SStella Stamenova       info.SetReadable(MemoryRegionInfo::eNo);
869*ed499a36SStella Stamenova       info.SetExecutable(MemoryRegionInfo::eNo);
870*ed499a36SStella Stamenova       info.SetWritable(MemoryRegionInfo::eNo);
871*ed499a36SStella Stamenova       info.SetMapped(MemoryRegionInfo::eNo);
872*ed499a36SStella Stamenova       return error;
873*ed499a36SStella Stamenova     } else {
874*ed499a36SStella Stamenova       error.SetError(::GetLastError(), eErrorTypeWin32);
875*ed499a36SStella Stamenova       LLDB_LOG(log,
876*ed499a36SStella Stamenova                "VirtualQueryEx returned error {0} while getting memory "
877*ed499a36SStella Stamenova                "region info for address {1:x}",
878*ed499a36SStella Stamenova                error, vm_addr);
879*ed499a36SStella Stamenova       return error;
880*ed499a36SStella Stamenova     }
881*ed499a36SStella Stamenova   }
882*ed499a36SStella Stamenova 
883*ed499a36SStella Stamenova   // Protect bits are only valid for MEM_COMMIT regions.
884*ed499a36SStella Stamenova   if (mem_info.State == MEM_COMMIT) {
885*ed499a36SStella Stamenova     const bool readable = IsPageReadable(mem_info.Protect);
886*ed499a36SStella Stamenova     const bool executable = IsPageExecutable(mem_info.Protect);
887*ed499a36SStella Stamenova     const bool writable = IsPageWritable(mem_info.Protect);
888*ed499a36SStella Stamenova     info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
889*ed499a36SStella Stamenova     info.SetExecutable(executable ? MemoryRegionInfo::eYes
890*ed499a36SStella Stamenova                                   : MemoryRegionInfo::eNo);
891*ed499a36SStella Stamenova     info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
892*ed499a36SStella Stamenova   } else {
893*ed499a36SStella Stamenova     info.SetReadable(MemoryRegionInfo::eNo);
894*ed499a36SStella Stamenova     info.SetExecutable(MemoryRegionInfo::eNo);
895*ed499a36SStella Stamenova     info.SetWritable(MemoryRegionInfo::eNo);
896*ed499a36SStella Stamenova   }
897*ed499a36SStella Stamenova 
898*ed499a36SStella Stamenova   // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE.
899*ed499a36SStella Stamenova   if (mem_info.State != MEM_FREE) {
900*ed499a36SStella Stamenova     info.GetRange().SetRangeBase(
901*ed499a36SStella Stamenova         reinterpret_cast<addr_t>(mem_info.AllocationBase));
902*ed499a36SStella Stamenova     info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) +
903*ed499a36SStella Stamenova                                 mem_info.RegionSize);
904*ed499a36SStella Stamenova     info.SetMapped(MemoryRegionInfo::eYes);
905*ed499a36SStella Stamenova   } else {
906*ed499a36SStella Stamenova     // In the unmapped case we need to return the distance to the next block of
907*ed499a36SStella Stamenova     // memory. VirtualQueryEx nearly does that except that it gives the
908*ed499a36SStella Stamenova     // distance from the start of the page containing vm_addr.
909*ed499a36SStella Stamenova     SYSTEM_INFO data;
910*ed499a36SStella Stamenova     GetSystemInfo(&data);
911*ed499a36SStella Stamenova     DWORD page_offset = vm_addr % data.dwPageSize;
912*ed499a36SStella Stamenova     info.GetRange().SetRangeBase(vm_addr);
913*ed499a36SStella Stamenova     info.GetRange().SetByteSize(mem_info.RegionSize - page_offset);
914*ed499a36SStella Stamenova     info.SetMapped(MemoryRegionInfo::eNo);
915*ed499a36SStella Stamenova   }
916*ed499a36SStella Stamenova 
917*ed499a36SStella Stamenova   error.SetError(::GetLastError(), eErrorTypeWin32);
918*ed499a36SStella Stamenova   LLDB_LOGV(log,
919*ed499a36SStella Stamenova             "Memory region info for address {0}: readable={1}, "
920*ed499a36SStella Stamenova             "executable={2}, writable={3}",
921*ed499a36SStella Stamenova             vm_addr, info.GetReadable(), info.GetExecutable(),
922*ed499a36SStella Stamenova             info.GetWritable());
923*ed499a36SStella Stamenova   return error;
9244ad5def9SAdrian McCarthy }
9254ad5def9SAdrian McCarthy 
926b9c1b51eSKate Stone lldb::addr_t ProcessWindows::GetImageInfoAddress() {
92718a9135dSAdrian McCarthy   Target &target = GetTarget();
92818a9135dSAdrian McCarthy   ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile();
92918a9135dSAdrian McCarthy   Address addr = obj_file->GetImageInfoAddress(&target);
93018a9135dSAdrian McCarthy   if (addr.IsValid())
93118a9135dSAdrian McCarthy     return addr.GetLoadAddress(&target);
93218a9135dSAdrian McCarthy   else
93318a9135dSAdrian McCarthy     return LLDB_INVALID_ADDRESS;
93418a9135dSAdrian McCarthy }
93518a9135dSAdrian McCarthy 
936eb6671e7SAaron Smith DynamicLoaderWindowsDYLD *ProcessWindows::GetDynamicLoader() {
93796b82107SAaron Smith   if (m_dyld_up.get() == NULL)
93896b82107SAaron Smith     m_dyld_up.reset(DynamicLoader::FindPlugin(
939eb6671e7SAaron Smith         this, DynamicLoaderWindowsDYLD::GetPluginNameStatic().GetCString()));
94096b82107SAaron Smith   return static_cast<DynamicLoaderWindowsDYLD *>(m_dyld_up.get());
941eb6671e7SAaron Smith }
942eb6671e7SAaron Smith 
9434ad5def9SAdrian McCarthy void ProcessWindows::OnExitProcess(uint32_t exit_code) {
9444ad5def9SAdrian McCarthy   // No need to acquire the lock since m_session_data isn't accessed.
945a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
946a385d2c1SPavel Labath   LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
9474ad5def9SAdrian McCarthy 
948d7e126c4SJim Ingham   TargetSP target = CalculateTarget();
9494ad5def9SAdrian McCarthy   if (target) {
9504ad5def9SAdrian McCarthy     ModuleSP executable_module = target->GetExecutableModule();
9514ad5def9SAdrian McCarthy     ModuleList unloaded_modules;
9524ad5def9SAdrian McCarthy     unloaded_modules.Append(executable_module);
9534ad5def9SAdrian McCarthy     target->ModulesDidUnload(unloaded_modules, true);
9544ad5def9SAdrian McCarthy   }
9554ad5def9SAdrian McCarthy 
9564ad5def9SAdrian McCarthy   SetProcessExitStatus(GetID(), true, 0, exit_code);
9574ad5def9SAdrian McCarthy   SetPrivateState(eStateExited);
958e3037904SAaron Smith 
959e3037904SAaron Smith   // If the process exits before any initial stop then notify the debugger
960e3037904SAaron Smith   // of the error otherwise WaitForDebuggerConnection() will be blocked.
961e3037904SAaron Smith   // An example of this issue is when a process fails to load a dependent DLL.
962c28daec5SAaron Smith   if (m_session_data && !m_session_data->m_initial_stop_received) {
963e3037904SAaron Smith     Status error(exit_code, eErrorTypeWin32);
964e3037904SAaron Smith     OnDebuggerError(error, 0);
965e3037904SAaron Smith   }
9664ad5def9SAdrian McCarthy }
9674ad5def9SAdrian McCarthy 
9684ad5def9SAdrian McCarthy void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
9694ad5def9SAdrian McCarthy   DebuggerThreadSP debugger = m_session_data->m_debugger;
970a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
971a385d2c1SPavel Labath   LLDB_LOG(log, "Debugger connected to process {0}.  Image base = {1:x}",
9724ad5def9SAdrian McCarthy            debugger->GetProcess().GetProcessId(), image_base);
9734ad5def9SAdrian McCarthy 
9744ad5def9SAdrian McCarthy   ModuleSP module = GetTarget().GetExecutableModule();
9754ad5def9SAdrian McCarthy   if (!module) {
9764ad5def9SAdrian McCarthy     // During attach, we won't have the executable module, so find it now.
9774ad5def9SAdrian McCarthy     const DWORD pid = debugger->GetProcess().GetProcessId();
9784ad5def9SAdrian McCarthy     const std::string file_name = GetProcessExecutableName(pid);
9794ad5def9SAdrian McCarthy     if (file_name.empty()) {
9804ad5def9SAdrian McCarthy       return;
9814ad5def9SAdrian McCarthy     }
9824ad5def9SAdrian McCarthy 
98354bb3161SAleksandr Urakov     FileSpec executable_file(file_name);
98454bb3161SAleksandr Urakov     FileSystem::Instance().Resolve(executable_file);
9854ad5def9SAdrian McCarthy     ModuleSpec module_spec(executable_file);
98697206d57SZachary Turner     Status error;
9871724a179SJason Molenda     module = GetTarget().GetOrCreateModule(module_spec,
9881724a179SJason Molenda                                            true /* notify */, &error);
9894ad5def9SAdrian McCarthy     if (!module) {
9904ad5def9SAdrian McCarthy       return;
9914ad5def9SAdrian McCarthy     }
9924ad5def9SAdrian McCarthy 
993d54ee88aSTatyana Krasnukha     GetTarget().SetExecutableModule(module, eLoadDependentsNo);
9944ad5def9SAdrian McCarthy   }
9954ad5def9SAdrian McCarthy 
996eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
997a2d9fdf5SStella Stamenova     dyld->OnLoadModule(module, ModuleSpec(), image_base);
9984ad5def9SAdrian McCarthy 
9994ad5def9SAdrian McCarthy   // Add the main executable module to the list of pending module loads.  We
100005097246SAdrian Prantl   // can't call GetTarget().ModulesDidLoad() here because we still haven't
100105097246SAdrian Prantl   // returned from DoLaunch() / DoAttach() yet so the target may not have set
100205097246SAdrian Prantl   // the process instance to `this` yet.
10034ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
10044ad5def9SAdrian McCarthy   const HostThreadWindows &wmain_thread =
10054ad5def9SAdrian McCarthy       debugger->GetMainThread().GetNativeThread();
10064ad5def9SAdrian McCarthy   m_session_data->m_new_threads[wmain_thread.GetThreadId()] =
10074ad5def9SAdrian McCarthy       debugger->GetMainThread();
10084ad5def9SAdrian McCarthy }
10094ad5def9SAdrian McCarthy 
10104ad5def9SAdrian McCarthy ExceptionResult
10114ad5def9SAdrian McCarthy ProcessWindows::OnDebugException(bool first_chance,
10124ad5def9SAdrian McCarthy                                  const ExceptionRecord &record) {
1013a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
10144ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
10154ad5def9SAdrian McCarthy 
10164ad5def9SAdrian McCarthy   // FIXME: Without this check, occasionally when running the test suite there
10174ad5def9SAdrian McCarthy   // is
10184ad5def9SAdrian McCarthy   // an issue where m_session_data can be null.  It's not clear how this could
101905097246SAdrian Prantl   // happen but it only surfaces while running the test suite.  In order to
102005097246SAdrian Prantl   // properly diagnose this, we probably need to first figure allow the test
102105097246SAdrian Prantl   // suite to print out full lldb logs, and then add logging to the process
102205097246SAdrian Prantl   // plugin.
10234ad5def9SAdrian McCarthy   if (!m_session_data) {
102462c76db4SStella Stamenova     LLDB_LOG(log,
102562c76db4SStella Stamenova              "Debugger thread reported exception {0:x} at address {1:x}, "
1026a385d2c1SPavel Labath              "but there is no session.",
10274ad5def9SAdrian McCarthy              record.GetExceptionCode(), record.GetExceptionAddress());
10284ad5def9SAdrian McCarthy     return ExceptionResult::SendToApplication;
10294ad5def9SAdrian McCarthy   }
10304ad5def9SAdrian McCarthy 
10314ad5def9SAdrian McCarthy   if (!first_chance) {
1032a5235af9SAleksandr Urakov     // Not any second chance exception is an application crash by definition.
1033a5235af9SAleksandr Urakov     // It may be an expression evaluation crash.
1034a5235af9SAleksandr Urakov     SetPrivateState(eStateStopped);
10354ad5def9SAdrian McCarthy   }
10364ad5def9SAdrian McCarthy 
10374ad5def9SAdrian McCarthy   ExceptionResult result = ExceptionResult::SendToApplication;
10384ad5def9SAdrian McCarthy   switch (record.GetExceptionCode()) {
10394ad5def9SAdrian McCarthy   case EXCEPTION_BREAKPOINT:
10404ad5def9SAdrian McCarthy     // Handle breakpoints at the first chance.
10414ad5def9SAdrian McCarthy     result = ExceptionResult::BreakInDebugger;
10424ad5def9SAdrian McCarthy 
10434ad5def9SAdrian McCarthy     if (!m_session_data->m_initial_stop_received) {
1044a385d2c1SPavel Labath       LLDB_LOG(
1045a385d2c1SPavel Labath           log,
1046a385d2c1SPavel Labath           "Hit loader breakpoint at address {0:x}, setting initial stop event.",
10474ad5def9SAdrian McCarthy           record.GetExceptionAddress());
10484ad5def9SAdrian McCarthy       m_session_data->m_initial_stop_received = true;
10494ad5def9SAdrian McCarthy       ::SetEvent(m_session_data->m_initial_stop_event);
10504ad5def9SAdrian McCarthy     } else {
1051a385d2c1SPavel Labath       LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
10524ad5def9SAdrian McCarthy                record.GetExceptionAddress());
10534ad5def9SAdrian McCarthy     }
10544ad5def9SAdrian McCarthy     SetPrivateState(eStateStopped);
10554ad5def9SAdrian McCarthy     break;
10564ad5def9SAdrian McCarthy   case EXCEPTION_SINGLE_STEP:
10574ad5def9SAdrian McCarthy     result = ExceptionResult::BreakInDebugger;
10584ad5def9SAdrian McCarthy     SetPrivateState(eStateStopped);
10594ad5def9SAdrian McCarthy     break;
10604ad5def9SAdrian McCarthy   default:
106162c76db4SStella Stamenova     LLDB_LOG(log,
106262c76db4SStella Stamenova              "Debugger thread reported exception {0:x} at address {1:x} "
1063a385d2c1SPavel Labath              "(first_chance={2})",
10644ad5def9SAdrian McCarthy              record.GetExceptionCode(), record.GetExceptionAddress(),
1065a385d2c1SPavel Labath              first_chance);
10664ad5def9SAdrian McCarthy     // For non-breakpoints, give the application a chance to handle the
10674ad5def9SAdrian McCarthy     // exception first.
10684ad5def9SAdrian McCarthy     if (first_chance)
10694ad5def9SAdrian McCarthy       result = ExceptionResult::SendToApplication;
10704ad5def9SAdrian McCarthy     else
10714ad5def9SAdrian McCarthy       result = ExceptionResult::BreakInDebugger;
10724ad5def9SAdrian McCarthy   }
10734ad5def9SAdrian McCarthy 
10744ad5def9SAdrian McCarthy   return result;
10754ad5def9SAdrian McCarthy }
10764ad5def9SAdrian McCarthy 
10774ad5def9SAdrian McCarthy void ProcessWindows::OnCreateThread(const HostThread &new_thread) {
10784ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
10794ad5def9SAdrian McCarthy   const HostThreadWindows &wnew_thread = new_thread.GetNativeThread();
10804ad5def9SAdrian McCarthy   m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread;
10814ad5def9SAdrian McCarthy }
10824ad5def9SAdrian McCarthy 
10834ad5def9SAdrian McCarthy void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
10844ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
10854ad5def9SAdrian McCarthy 
10864ad5def9SAdrian McCarthy   // On a forced termination, we may get exit thread events after the session
10874ad5def9SAdrian McCarthy   // data has been cleaned up.
10884ad5def9SAdrian McCarthy   if (!m_session_data)
10894ad5def9SAdrian McCarthy     return;
10904ad5def9SAdrian McCarthy 
10914ad5def9SAdrian McCarthy   // A thread may have started and exited before the debugger stopped allowing a
10924ad5def9SAdrian McCarthy   // refresh.
10934ad5def9SAdrian McCarthy   // Just remove it from the new threads list in that case.
10944ad5def9SAdrian McCarthy   auto iter = m_session_data->m_new_threads.find(thread_id);
10954ad5def9SAdrian McCarthy   if (iter != m_session_data->m_new_threads.end())
10964ad5def9SAdrian McCarthy     m_session_data->m_new_threads.erase(iter);
10974ad5def9SAdrian McCarthy   else
10984ad5def9SAdrian McCarthy     m_session_data->m_exited_threads.insert(thread_id);
10994ad5def9SAdrian McCarthy }
11004ad5def9SAdrian McCarthy 
11014ad5def9SAdrian McCarthy void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
11024ad5def9SAdrian McCarthy                                lldb::addr_t module_addr) {
1103eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
1104a2d9fdf5SStella Stamenova     dyld->OnLoadModule(nullptr, module_spec, module_addr);
11054ad5def9SAdrian McCarthy }
11064ad5def9SAdrian McCarthy 
11074ad5def9SAdrian McCarthy void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
1108eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
1109eb6671e7SAaron Smith     dyld->OnUnloadModule(module_addr);
11104ad5def9SAdrian McCarthy }
11114ad5def9SAdrian McCarthy 
11124ad5def9SAdrian McCarthy void ProcessWindows::OnDebugString(const std::string &string) {}
11134ad5def9SAdrian McCarthy 
111497206d57SZachary Turner void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) {
11154ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
1116a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
11174ad5def9SAdrian McCarthy 
11184ad5def9SAdrian McCarthy   if (m_session_data->m_initial_stop_received) {
111905097246SAdrian Prantl     // This happened while debugging.  Do we shutdown the debugging session,
112005097246SAdrian Prantl     // try to continue, or do something else?
112162c76db4SStella Stamenova     LLDB_LOG(log,
112262c76db4SStella Stamenova              "Error {0} occurred during debugging.  Unexpected behavior "
1123a385d2c1SPavel Labath              "may result.  {1}",
1124a385d2c1SPavel Labath              error.GetError(), error);
11254ad5def9SAdrian McCarthy   } else {
11264ad5def9SAdrian McCarthy     // If we haven't actually launched the process yet, this was an error
112705097246SAdrian Prantl     // launching the process.  Set the internal error and signal the initial
112805097246SAdrian Prantl     // stop event so that the DoLaunch method wakes up and returns a failure.
11294ad5def9SAdrian McCarthy     m_session_data->m_launch_error = error;
11304ad5def9SAdrian McCarthy     ::SetEvent(m_session_data->m_initial_stop_event);
1131a385d2c1SPavel Labath     LLDB_LOG(
1132a385d2c1SPavel Labath         log,
1133a385d2c1SPavel Labath         "Error {0} occurred launching the process before the initial stop. {1}",
1134a385d2c1SPavel Labath         error.GetError(), error);
11354ad5def9SAdrian McCarthy     return;
11364ad5def9SAdrian McCarthy   }
11374ad5def9SAdrian McCarthy }
1138*ed499a36SStella Stamenova 
1139*ed499a36SStella Stamenova Status ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger,
1140*ed499a36SStella Stamenova                                                  HostProcess &process) {
1141*ed499a36SStella Stamenova   Status result;
1142*ed499a36SStella Stamenova   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS |
1143*ed499a36SStella Stamenova                                             WINDOWS_LOG_BREAKPOINTS);
1144*ed499a36SStella Stamenova   LLDB_LOG(log, "Waiting for loader breakpoint.");
1145*ed499a36SStella Stamenova 
1146*ed499a36SStella Stamenova   // Block this function until we receive the initial stop from the process.
1147*ed499a36SStella Stamenova   if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) ==
1148*ed499a36SStella Stamenova       WAIT_OBJECT_0) {
1149*ed499a36SStella Stamenova     LLDB_LOG(log, "hit loader breakpoint, returning.");
1150*ed499a36SStella Stamenova 
1151*ed499a36SStella Stamenova     process = debugger->GetProcess();
1152*ed499a36SStella Stamenova     return m_session_data->m_launch_error;
1153*ed499a36SStella Stamenova   } else
1154*ed499a36SStella Stamenova     return Status(::GetLastError(), eErrorTypeWin32);
1155*ed499a36SStella Stamenova }
1156*ed499a36SStella Stamenova 
1157*ed499a36SStella Stamenova // The Windows page protection bits are NOT independent masks that can be
1158*ed499a36SStella Stamenova // bitwise-ORed together.  For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE
1159*ed499a36SStella Stamenova // | PAGE_READ).  To test for an access type, it's necessary to test for any of
1160*ed499a36SStella Stamenova // the bits that provide that access type.
1161*ed499a36SStella Stamenova bool ProcessWindows::IsPageReadable(uint32_t protect) {
1162*ed499a36SStella Stamenova   return (protect & PAGE_NOACCESS) == 0;
1163*ed499a36SStella Stamenova }
1164*ed499a36SStella Stamenova 
1165*ed499a36SStella Stamenova bool ProcessWindows::IsPageWritable(uint32_t protect) {
1166*ed499a36SStella Stamenova   return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY |
1167*ed499a36SStella Stamenova                      PAGE_READWRITE | PAGE_WRITECOPY)) != 0;
1168*ed499a36SStella Stamenova }
1169*ed499a36SStella Stamenova 
1170*ed499a36SStella Stamenova bool ProcessWindows::IsPageExecutable(uint32_t protect) {
1171*ed499a36SStella Stamenova   return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
1172*ed499a36SStella Stamenova                      PAGE_EXECUTE_WRITECOPY)) != 0;
1173*ed499a36SStella Stamenova }
1174*ed499a36SStella Stamenova 
11754ad5def9SAdrian McCarthy } // namespace lldb_private
1176