118a9135dSAdrian McCarthy //===-- ProcessWindows.cpp --------------------------------------*- C++ -*-===//
218a9135dSAdrian McCarthy //
318a9135dSAdrian McCarthy //                     The LLVM Compiler Infrastructure
418a9135dSAdrian McCarthy //
518a9135dSAdrian McCarthy // This file is distributed under the University of Illinois Open Source
618a9135dSAdrian McCarthy // License. See LICENSE.TXT for details.
718a9135dSAdrian McCarthy //
818a9135dSAdrian McCarthy //===----------------------------------------------------------------------===//
918a9135dSAdrian McCarthy 
1018a9135dSAdrian McCarthy #include "ProcessWindows.h"
1118a9135dSAdrian McCarthy 
124ad5def9SAdrian McCarthy // Windows includes
134ad5def9SAdrian McCarthy #include "lldb/Host/windows/windows.h"
144ad5def9SAdrian McCarthy #include <psapi.h>
154ad5def9SAdrian McCarthy 
1618a9135dSAdrian McCarthy #include "lldb/Core/Module.h"
1718a9135dSAdrian McCarthy #include "lldb/Core/ModuleSpec.h"
1818a9135dSAdrian McCarthy #include "lldb/Core/PluginManager.h"
1918a9135dSAdrian McCarthy #include "lldb/Core/Section.h"
2060cf3f82SJonas Devlieghere #include "lldb/Host/FileSystem.h"
214ad5def9SAdrian McCarthy #include "lldb/Host/HostNativeProcessBase.h"
224ad5def9SAdrian McCarthy #include "lldb/Host/HostProcess.h"
234ad5def9SAdrian McCarthy #include "lldb/Host/windows/HostThreadWindows.h"
240c35cde9SAdrian McCarthy #include "lldb/Host/windows/windows.h"
252f3df613SZachary Turner #include "lldb/Symbol/ObjectFile.h"
2618a9135dSAdrian McCarthy #include "lldb/Target/DynamicLoader.h"
2718a9135dSAdrian McCarthy #include "lldb/Target/MemoryRegionInfo.h"
284ad5def9SAdrian McCarthy #include "lldb/Target/StopInfo.h"
2918a9135dSAdrian McCarthy #include "lldb/Target/Target.h"
30d821c997SPavel Labath #include "lldb/Utility/State.h"
3118a9135dSAdrian McCarthy 
324ad5def9SAdrian McCarthy #include "llvm/Support/ConvertUTF.h"
334ad5def9SAdrian McCarthy #include "llvm/Support/Format.h"
34c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h"
354ad5def9SAdrian McCarthy #include "llvm/Support/raw_ostream.h"
364ad5def9SAdrian McCarthy 
374ad5def9SAdrian McCarthy #include "DebuggerThread.h"
384ad5def9SAdrian McCarthy #include "ExceptionRecord.h"
394ad5def9SAdrian McCarthy #include "ForwardDecl.h"
404ad5def9SAdrian McCarthy #include "LocalDebugDelegate.h"
414ad5def9SAdrian McCarthy #include "ProcessWindowsLog.h"
424ad5def9SAdrian McCarthy #include "TargetThreadWindows.h"
434ad5def9SAdrian McCarthy 
4418a9135dSAdrian McCarthy using namespace lldb;
4518a9135dSAdrian McCarthy using namespace lldb_private;
4618a9135dSAdrian McCarthy 
474ad5def9SAdrian McCarthy namespace {
484ad5def9SAdrian McCarthy std::string GetProcessExecutableName(HANDLE process_handle) {
494ad5def9SAdrian McCarthy   std::vector<wchar_t> file_name;
504ad5def9SAdrian McCarthy   DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit
514ad5def9SAdrian McCarthy   DWORD copied = 0;
524ad5def9SAdrian McCarthy   do {
534ad5def9SAdrian McCarthy     file_name_size *= 2;
544ad5def9SAdrian McCarthy     file_name.resize(file_name_size);
554ad5def9SAdrian McCarthy     copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(),
564ad5def9SAdrian McCarthy                                     file_name_size);
574ad5def9SAdrian McCarthy   } while (copied >= file_name_size);
584ad5def9SAdrian McCarthy   file_name.resize(copied);
594ad5def9SAdrian McCarthy   std::string result;
604ad5def9SAdrian McCarthy   llvm::convertWideToUTF8(file_name.data(), result);
614ad5def9SAdrian McCarthy   return result;
624ad5def9SAdrian McCarthy }
634ad5def9SAdrian McCarthy 
644ad5def9SAdrian McCarthy std::string GetProcessExecutableName(DWORD pid) {
654ad5def9SAdrian McCarthy   std::string file_name;
664ad5def9SAdrian McCarthy   HANDLE process_handle =
674ad5def9SAdrian McCarthy       ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
684ad5def9SAdrian McCarthy   if (process_handle != NULL) {
694ad5def9SAdrian McCarthy     file_name = GetProcessExecutableName(process_handle);
704ad5def9SAdrian McCarthy     ::CloseHandle(process_handle);
714ad5def9SAdrian McCarthy   }
724ad5def9SAdrian McCarthy   return file_name;
734ad5def9SAdrian McCarthy }
744ad5def9SAdrian McCarthy 
759d5b2d4aSAleksandr Urakov DWORD ConvertLldbToWinApiProtect(uint32_t protect) {
769d5b2d4aSAleksandr Urakov   // We also can process a read / write permissions here, but if the debugger
779d5b2d4aSAleksandr Urakov   // will make later a write into the allocated memory, it will fail. To get
789d5b2d4aSAleksandr Urakov   // around it is possible inside DoWriteMemory to remember memory permissions,
799d5b2d4aSAleksandr Urakov   // allow write, write and restore permissions, but for now we process only
809d5b2d4aSAleksandr Urakov   // the executable permission.
819d5b2d4aSAleksandr Urakov   //
829d5b2d4aSAleksandr Urakov   // TODO: Process permissions other than executable
839d5b2d4aSAleksandr Urakov   if (protect & ePermissionsExecutable)
849d5b2d4aSAleksandr Urakov     return PAGE_EXECUTE_READWRITE;
859d5b2d4aSAleksandr Urakov 
869d5b2d4aSAleksandr Urakov   return PAGE_READWRITE;
879d5b2d4aSAleksandr Urakov }
889d5b2d4aSAleksandr Urakov 
894ad5def9SAdrian McCarthy } // anonymous namespace
904ad5def9SAdrian McCarthy 
91b9c1b51eSKate Stone namespace lldb_private {
9218a9135dSAdrian McCarthy 
934ad5def9SAdrian McCarthy // We store a pointer to this class in the ProcessWindows, so that we don't
9405097246SAdrian Prantl // expose Windows-specific types and implementation details from a public
9505097246SAdrian Prantl // header file.
964ad5def9SAdrian McCarthy class ProcessWindowsData {
974ad5def9SAdrian McCarthy public:
984ad5def9SAdrian McCarthy   ProcessWindowsData(bool stop_at_entry) : m_stop_at_entry(stop_at_entry) {
994ad5def9SAdrian McCarthy     m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
1004ad5def9SAdrian McCarthy   }
1014ad5def9SAdrian McCarthy 
1024ad5def9SAdrian McCarthy   ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); }
1034ad5def9SAdrian McCarthy 
10497206d57SZachary Turner   Status m_launch_error;
1054ad5def9SAdrian McCarthy   DebuggerThreadSP m_debugger;
1064ad5def9SAdrian McCarthy   StopInfoSP m_pending_stop_info;
1074ad5def9SAdrian McCarthy   HANDLE m_initial_stop_event = nullptr;
1084ad5def9SAdrian McCarthy   bool m_initial_stop_received = false;
1094ad5def9SAdrian McCarthy   bool m_stop_at_entry;
1104ad5def9SAdrian McCarthy   std::map<lldb::tid_t, HostThread> m_new_threads;
1114ad5def9SAdrian McCarthy   std::set<lldb::tid_t> m_exited_threads;
1124ad5def9SAdrian McCarthy };
1134ad5def9SAdrian McCarthy 
1144ad5def9SAdrian McCarthy ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp,
1154ad5def9SAdrian McCarthy                                          lldb::ListenerSP listener_sp,
1164ad5def9SAdrian McCarthy                                          const FileSpec *) {
1174ad5def9SAdrian McCarthy   return ProcessSP(new ProcessWindows(target_sp, listener_sp));
1184ad5def9SAdrian McCarthy }
1194ad5def9SAdrian McCarthy 
1204ad5def9SAdrian McCarthy void ProcessWindows::Initialize() {
121c5f28e2aSKamil Rytarowski   static llvm::once_flag g_once_flag;
1224ad5def9SAdrian McCarthy 
123c5f28e2aSKamil Rytarowski   llvm::call_once(g_once_flag, []() {
1244ad5def9SAdrian McCarthy     PluginManager::RegisterPlugin(GetPluginNameStatic(),
1254ad5def9SAdrian McCarthy                                   GetPluginDescriptionStatic(), CreateInstance);
1264ad5def9SAdrian McCarthy   });
1274ad5def9SAdrian McCarthy }
1284ad5def9SAdrian McCarthy 
1294ad5def9SAdrian McCarthy void ProcessWindows::Terminate() {}
1304ad5def9SAdrian McCarthy 
1314ad5def9SAdrian McCarthy lldb_private::ConstString ProcessWindows::GetPluginNameStatic() {
1324ad5def9SAdrian McCarthy   static ConstString g_name("windows");
1334ad5def9SAdrian McCarthy   return g_name;
1344ad5def9SAdrian McCarthy }
1354ad5def9SAdrian McCarthy 
1364ad5def9SAdrian McCarthy const char *ProcessWindows::GetPluginDescriptionStatic() {
1374ad5def9SAdrian McCarthy   return "Process plugin for Windows";
1384ad5def9SAdrian McCarthy }
1394ad5def9SAdrian McCarthy 
14018a9135dSAdrian McCarthy //------------------------------------------------------------------------------
14118a9135dSAdrian McCarthy // Constructors and destructors.
14218a9135dSAdrian McCarthy 
143b9c1b51eSKate Stone ProcessWindows::ProcessWindows(lldb::TargetSP target_sp,
144b9c1b51eSKate Stone                                lldb::ListenerSP listener_sp)
145b9c1b51eSKate Stone     : lldb_private::Process(target_sp, listener_sp) {}
14618a9135dSAdrian McCarthy 
147b9c1b51eSKate Stone ProcessWindows::~ProcessWindows() {}
14818a9135dSAdrian McCarthy 
14997206d57SZachary Turner size_t ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Status &error) {
15018a9135dSAdrian McCarthy   error.SetErrorString("GetSTDOUT unsupported on Windows");
15118a9135dSAdrian McCarthy   return 0;
15218a9135dSAdrian McCarthy }
15318a9135dSAdrian McCarthy 
15497206d57SZachary Turner size_t ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Status &error) {
15518a9135dSAdrian McCarthy   error.SetErrorString("GetSTDERR unsupported on Windows");
15618a9135dSAdrian McCarthy   return 0;
15718a9135dSAdrian McCarthy }
15818a9135dSAdrian McCarthy 
159b9c1b51eSKate Stone size_t ProcessWindows::PutSTDIN(const char *buf, size_t buf_size,
16097206d57SZachary Turner                                 Status &error) {
16118a9135dSAdrian McCarthy   error.SetErrorString("PutSTDIN unsupported on Windows");
16218a9135dSAdrian McCarthy   return 0;
16318a9135dSAdrian McCarthy }
16418a9135dSAdrian McCarthy 
16518a9135dSAdrian McCarthy //------------------------------------------------------------------------------
16618a9135dSAdrian McCarthy // ProcessInterface protocol.
16718a9135dSAdrian McCarthy 
1684ad5def9SAdrian McCarthy lldb_private::ConstString ProcessWindows::GetPluginName() {
1694ad5def9SAdrian McCarthy   return GetPluginNameStatic();
1704ad5def9SAdrian McCarthy }
1714ad5def9SAdrian McCarthy 
1724ad5def9SAdrian McCarthy uint32_t ProcessWindows::GetPluginVersion() { return 1; }
1734ad5def9SAdrian McCarthy 
17497206d57SZachary Turner Status ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) {
175a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS);
176a385d2c1SPavel Labath   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
177a385d2c1SPavel Labath            bp_site->GetID(), bp_site->GetLoadAddress());
1784ad5def9SAdrian McCarthy 
17997206d57SZachary Turner   Status error = EnableSoftwareBreakpoint(bp_site);
180a385d2c1SPavel Labath   if (!error.Success())
181a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
1824ad5def9SAdrian McCarthy   return error;
1834ad5def9SAdrian McCarthy }
1844ad5def9SAdrian McCarthy 
18597206d57SZachary Turner Status ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) {
186a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS);
187a385d2c1SPavel Labath   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
188a385d2c1SPavel Labath            bp_site->GetID(), bp_site->GetLoadAddress());
1894ad5def9SAdrian McCarthy 
19097206d57SZachary Turner   Status error = DisableSoftwareBreakpoint(bp_site);
1914ad5def9SAdrian McCarthy 
192a385d2c1SPavel Labath   if (!error.Success())
193a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
1944ad5def9SAdrian McCarthy   return error;
1954ad5def9SAdrian McCarthy }
1964ad5def9SAdrian McCarthy 
19797206d57SZachary Turner Status ProcessWindows::DoDetach(bool keep_stopped) {
198a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
1994ad5def9SAdrian McCarthy   DebuggerThreadSP debugger_thread;
2004ad5def9SAdrian McCarthy   StateType private_state;
2014ad5def9SAdrian McCarthy   {
2024ad5def9SAdrian McCarthy     // Acquire the lock only long enough to get the DebuggerThread.
20305097246SAdrian Prantl     // StopDebugging() will trigger a call back into ProcessWindows which will
20405097246SAdrian Prantl     // also acquire the lock.  Thus we have to release the lock before calling
20505097246SAdrian Prantl     // StopDebugging().
2064ad5def9SAdrian McCarthy     llvm::sys::ScopedLock lock(m_mutex);
2074ad5def9SAdrian McCarthy 
2084ad5def9SAdrian McCarthy     private_state = GetPrivateState();
2094ad5def9SAdrian McCarthy 
2104ad5def9SAdrian McCarthy     if (!m_session_data) {
211a385d2c1SPavel Labath       LLDB_LOG(log, "state = {0}, but there is no active session.",
2124ad5def9SAdrian McCarthy                private_state);
21397206d57SZachary Turner       return Status();
2144ad5def9SAdrian McCarthy     }
2154ad5def9SAdrian McCarthy 
2164ad5def9SAdrian McCarthy     debugger_thread = m_session_data->m_debugger;
2174ad5def9SAdrian McCarthy   }
2184ad5def9SAdrian McCarthy 
21997206d57SZachary Turner   Status error;
2204ad5def9SAdrian McCarthy   if (private_state != eStateExited && private_state != eStateDetached) {
221a385d2c1SPavel Labath     LLDB_LOG(log, "detaching from process {0} while state = {1}.",
2224ad5def9SAdrian McCarthy              debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
2234ad5def9SAdrian McCarthy              private_state);
2244ad5def9SAdrian McCarthy     error = debugger_thread->StopDebugging(false);
2254ad5def9SAdrian McCarthy     if (error.Success()) {
2264ad5def9SAdrian McCarthy       SetPrivateState(eStateDetached);
2274ad5def9SAdrian McCarthy     }
2284ad5def9SAdrian McCarthy 
2294ad5def9SAdrian McCarthy     // By the time StopDebugging returns, there is no more debugger thread, so
2304ad5def9SAdrian McCarthy     // we can be assured that no other thread will race for the session data.
2314ad5def9SAdrian McCarthy     m_session_data.reset();
2324ad5def9SAdrian McCarthy   } else {
233a385d2c1SPavel Labath     LLDB_LOG(
234a385d2c1SPavel Labath         log,
235a385d2c1SPavel Labath         "error: process {0} in state = {1}, but cannot destroy in this state.",
2364ad5def9SAdrian McCarthy         debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
2374ad5def9SAdrian McCarthy         private_state);
2384ad5def9SAdrian McCarthy   }
2394ad5def9SAdrian McCarthy 
2404ad5def9SAdrian McCarthy   return error;
2414ad5def9SAdrian McCarthy }
2424ad5def9SAdrian McCarthy 
24397206d57SZachary Turner Status ProcessWindows::DoLaunch(Module *exe_module,
2444ad5def9SAdrian McCarthy                                 ProcessLaunchInfo &launch_info) {
24505097246SAdrian Prantl   // Even though m_session_data is accessed here, it is before a debugger
24605097246SAdrian Prantl   // thread has been kicked off.  So there's no race conditions, and it
24705097246SAdrian Prantl   // shouldn't be necessary to acquire the mutex.
2484ad5def9SAdrian McCarthy 
249a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
25097206d57SZachary Turner   Status result;
2519d6fabf9SStella Stamenova 
2529d6fabf9SStella Stamenova   FileSpec working_dir = launch_info.GetWorkingDirectory();
2539d6fabf9SStella Stamenova   namespace fs = llvm::sys::fs;
25454bb3161SAleksandr Urakov   if (working_dir) {
25554bb3161SAleksandr Urakov     FileSystem::Instance().Resolve(working_dir);
2563a58d898SJonas Devlieghere     if (!FileSystem::Instance().IsDirectory(working_dir)) {
2579d6fabf9SStella Stamenova       result.SetErrorStringWithFormat("No such file or directory: %s",
2589d6fabf9SStella Stamenova                                       working_dir.GetCString());
2599d6fabf9SStella Stamenova       return result;
2609d6fabf9SStella Stamenova     }
26154bb3161SAleksandr Urakov   }
2629d6fabf9SStella Stamenova 
2634ad5def9SAdrian McCarthy   if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) {
2644ad5def9SAdrian McCarthy     StreamString stream;
2654ad5def9SAdrian McCarthy     stream.Printf("ProcessWindows unable to launch '%s'.  ProcessWindows can "
2664ad5def9SAdrian McCarthy                   "only be used for debug launches.",
2674ad5def9SAdrian McCarthy                   launch_info.GetExecutableFile().GetPath().c_str());
2684ad5def9SAdrian McCarthy     std::string message = stream.GetString();
2694ad5def9SAdrian McCarthy     result.SetErrorString(message.c_str());
2704ad5def9SAdrian McCarthy 
271a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", message);
2724ad5def9SAdrian McCarthy     return result;
2734ad5def9SAdrian McCarthy   }
2744ad5def9SAdrian McCarthy 
2754ad5def9SAdrian McCarthy   bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
2764ad5def9SAdrian McCarthy   m_session_data.reset(new ProcessWindowsData(stop_at_entry));
2774ad5def9SAdrian McCarthy 
2784ad5def9SAdrian McCarthy   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
2794ad5def9SAdrian McCarthy   m_session_data->m_debugger.reset(new DebuggerThread(delegate));
2804ad5def9SAdrian McCarthy   DebuggerThreadSP debugger = m_session_data->m_debugger;
2814ad5def9SAdrian McCarthy 
2824ad5def9SAdrian McCarthy   // Kick off the DebugLaunch asynchronously and wait for it to complete.
2834ad5def9SAdrian McCarthy   result = debugger->DebugLaunch(launch_info);
2844ad5def9SAdrian McCarthy   if (result.Fail()) {
285a385d2c1SPavel Labath     LLDB_LOG(log, "failed launching '{0}'. {1}",
286a385d2c1SPavel Labath              launch_info.GetExecutableFile().GetPath(), result);
2874ad5def9SAdrian McCarthy     return result;
2884ad5def9SAdrian McCarthy   }
2894ad5def9SAdrian McCarthy 
2904ad5def9SAdrian McCarthy   HostProcess process;
29197206d57SZachary Turner   Status error = WaitForDebuggerConnection(debugger, process);
2924ad5def9SAdrian McCarthy   if (error.Fail()) {
293a385d2c1SPavel Labath     LLDB_LOG(log, "failed launching '{0}'. {1}",
294a385d2c1SPavel Labath              launch_info.GetExecutableFile().GetPath(), error);
2954ad5def9SAdrian McCarthy     return error;
2964ad5def9SAdrian McCarthy   }
2974ad5def9SAdrian McCarthy 
298a385d2c1SPavel Labath   LLDB_LOG(log, "successfully launched '{0}'",
299a385d2c1SPavel Labath            launch_info.GetExecutableFile().GetPath());
3004ad5def9SAdrian McCarthy 
3014ad5def9SAdrian McCarthy   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
30205097246SAdrian Prantl   // private state should already be set to eStateStopped as a result of
30305097246SAdrian Prantl   // hitting the initial breakpoint.  If it was not set, the breakpoint should
30405097246SAdrian Prantl   // have already been resumed from and the private state should already be
30505097246SAdrian Prantl   // eStateRunning.
3064ad5def9SAdrian McCarthy   launch_info.SetProcessID(process.GetProcessId());
3074ad5def9SAdrian McCarthy   SetID(process.GetProcessId());
3084ad5def9SAdrian McCarthy 
3094ad5def9SAdrian McCarthy   return result;
3104ad5def9SAdrian McCarthy }
3114ad5def9SAdrian McCarthy 
31297206d57SZachary Turner Status
31397206d57SZachary Turner ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid,
31497206d57SZachary Turner                                         const ProcessAttachInfo &attach_info) {
315a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
3164ad5def9SAdrian McCarthy   m_session_data.reset(
3174ad5def9SAdrian McCarthy       new ProcessWindowsData(!attach_info.GetContinueOnceAttached()));
3184ad5def9SAdrian McCarthy 
3194ad5def9SAdrian McCarthy   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
3204ad5def9SAdrian McCarthy   DebuggerThreadSP debugger(new DebuggerThread(delegate));
3214ad5def9SAdrian McCarthy 
3224ad5def9SAdrian McCarthy   m_session_data->m_debugger = debugger;
3234ad5def9SAdrian McCarthy 
3244ad5def9SAdrian McCarthy   DWORD process_id = static_cast<DWORD>(pid);
32597206d57SZachary Turner   Status error = debugger->DebugAttach(process_id, attach_info);
3264ad5def9SAdrian McCarthy   if (error.Fail()) {
327a385d2c1SPavel Labath     LLDB_LOG(
328a385d2c1SPavel Labath         log,
329a385d2c1SPavel Labath         "encountered an error occurred initiating the asynchronous attach. {0}",
330a385d2c1SPavel Labath         error);
3314ad5def9SAdrian McCarthy     return error;
3324ad5def9SAdrian McCarthy   }
3334ad5def9SAdrian McCarthy 
3344ad5def9SAdrian McCarthy   HostProcess process;
3354ad5def9SAdrian McCarthy   error = WaitForDebuggerConnection(debugger, process);
3364ad5def9SAdrian McCarthy   if (error.Fail()) {
337a385d2c1SPavel Labath     LLDB_LOG(log,
338a385d2c1SPavel Labath              "encountered an error waiting for the debugger to connect. {0}",
339a385d2c1SPavel Labath              error);
3404ad5def9SAdrian McCarthy     return error;
3414ad5def9SAdrian McCarthy   }
3424ad5def9SAdrian McCarthy 
343a385d2c1SPavel Labath   LLDB_LOG(log, "successfully attached to process with pid={0}", process_id);
3444ad5def9SAdrian McCarthy 
3454ad5def9SAdrian McCarthy   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
34605097246SAdrian Prantl   // private state should already be set to eStateStopped as a result of
34705097246SAdrian Prantl   // hitting the initial breakpoint.  If it was not set, the breakpoint should
34805097246SAdrian Prantl   // have already been resumed from and the private state should already be
34905097246SAdrian Prantl   // eStateRunning.
3504ad5def9SAdrian McCarthy   SetID(process.GetProcessId());
3514ad5def9SAdrian McCarthy   return error;
3524ad5def9SAdrian McCarthy }
3534ad5def9SAdrian McCarthy 
35497206d57SZachary Turner Status ProcessWindows::DoResume() {
355a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
3564ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
35797206d57SZachary Turner   Status error;
3584ad5def9SAdrian McCarthy 
3594ad5def9SAdrian McCarthy   StateType private_state = GetPrivateState();
3604ad5def9SAdrian McCarthy   if (private_state == eStateStopped || private_state == eStateCrashed) {
361a385d2c1SPavel Labath     LLDB_LOG(log, "process {0} is in state {1}.  Resuming...",
3624ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId(),
3634ad5def9SAdrian McCarthy              GetPrivateState());
3644ad5def9SAdrian McCarthy 
3654ad5def9SAdrian McCarthy     ExceptionRecordSP active_exception =
3664ad5def9SAdrian McCarthy         m_session_data->m_debugger->GetActiveException().lock();
3674ad5def9SAdrian McCarthy     if (active_exception) {
36805097246SAdrian Prantl       // Resume the process and continue processing debug events.  Mask the
36905097246SAdrian Prantl       // exception so that from the process's view, there is no indication that
37005097246SAdrian Prantl       // anything happened.
3714ad5def9SAdrian McCarthy       m_session_data->m_debugger->ContinueAsyncException(
3724ad5def9SAdrian McCarthy           ExceptionResult::MaskException);
3734ad5def9SAdrian McCarthy     }
3744ad5def9SAdrian McCarthy 
375a385d2c1SPavel Labath     LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize());
3764ad5def9SAdrian McCarthy 
3770fd67b53SStella Stamenova     bool failed = false;
3784ad5def9SAdrian McCarthy     for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) {
3794ad5def9SAdrian McCarthy       auto thread = std::static_pointer_cast<TargetThreadWindows>(
3804ad5def9SAdrian McCarthy           m_thread_list.GetThreadAtIndex(i));
3810fd67b53SStella Stamenova       Status result = thread->DoResume();
3820fd67b53SStella Stamenova       if (result.Fail()) {
3830fd67b53SStella Stamenova         failed = true;
38462c76db4SStella Stamenova         LLDB_LOG(
38562c76db4SStella Stamenova             log,
38662c76db4SStella Stamenova             "Trying to resume thread at index {0}, but failed with error {1}.",
38762c76db4SStella Stamenova             i, result);
3880fd67b53SStella Stamenova       }
3894ad5def9SAdrian McCarthy     }
3904ad5def9SAdrian McCarthy 
3910fd67b53SStella Stamenova     if (failed) {
3920fd67b53SStella Stamenova       error.SetErrorString("ProcessWindows::DoResume failed");
3930fd67b53SStella Stamenova       return error;
3940fd67b53SStella Stamenova     } else {
3954ad5def9SAdrian McCarthy       SetPrivateState(eStateRunning);
3960fd67b53SStella Stamenova     }
3974ad5def9SAdrian McCarthy   } else {
398*c28daec5SAaron Smith     LLDB_LOG(log, "error: process {0} is in state {1}.  Returning...",
3994ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId(),
4004ad5def9SAdrian McCarthy              GetPrivateState());
4014ad5def9SAdrian McCarthy   }
4024ad5def9SAdrian McCarthy   return error;
4034ad5def9SAdrian McCarthy }
4044ad5def9SAdrian McCarthy 
40597206d57SZachary Turner Status ProcessWindows::DoDestroy() {
406a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
4074ad5def9SAdrian McCarthy   DebuggerThreadSP debugger_thread;
4084ad5def9SAdrian McCarthy   StateType private_state;
4094ad5def9SAdrian McCarthy   {
4104ad5def9SAdrian McCarthy     // Acquire this lock inside an inner scope, only long enough to get the
41105097246SAdrian Prantl     // DebuggerThread. StopDebugging() will trigger a call back into
41205097246SAdrian Prantl     // ProcessWindows which will acquire the lock again, so we need to not
41305097246SAdrian Prantl     // deadlock.
4144ad5def9SAdrian McCarthy     llvm::sys::ScopedLock lock(m_mutex);
4154ad5def9SAdrian McCarthy 
4164ad5def9SAdrian McCarthy     private_state = GetPrivateState();
4174ad5def9SAdrian McCarthy 
4184ad5def9SAdrian McCarthy     if (!m_session_data) {
419a385d2c1SPavel Labath       LLDB_LOG(log, "warning: state = {0}, but there is no active session.",
4204ad5def9SAdrian McCarthy                private_state);
42197206d57SZachary Turner       return Status();
4224ad5def9SAdrian McCarthy     }
4234ad5def9SAdrian McCarthy 
4244ad5def9SAdrian McCarthy     debugger_thread = m_session_data->m_debugger;
4254ad5def9SAdrian McCarthy   }
4264ad5def9SAdrian McCarthy 
42797206d57SZachary Turner   Status error;
4284ad5def9SAdrian McCarthy   if (private_state != eStateExited && private_state != eStateDetached) {
429a385d2c1SPavel Labath     LLDB_LOG(log, "Shutting down process {0} while state = {1}.",
4304ad5def9SAdrian McCarthy              debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
4314ad5def9SAdrian McCarthy              private_state);
4324ad5def9SAdrian McCarthy     error = debugger_thread->StopDebugging(true);
4334ad5def9SAdrian McCarthy 
4344ad5def9SAdrian McCarthy     // By the time StopDebugging returns, there is no more debugger thread, so
4354ad5def9SAdrian McCarthy     // we can be assured that no other thread will race for the session data.
4364ad5def9SAdrian McCarthy     m_session_data.reset();
4374ad5def9SAdrian McCarthy   } else {
438a385d2c1SPavel Labath     LLDB_LOG(log, "cannot destroy process {0} while state = {1}",
4394ad5def9SAdrian McCarthy              debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(),
4404ad5def9SAdrian McCarthy              private_state);
4414ad5def9SAdrian McCarthy   }
4424ad5def9SAdrian McCarthy 
4434ad5def9SAdrian McCarthy   return error;
4444ad5def9SAdrian McCarthy }
4454ad5def9SAdrian McCarthy 
44697206d57SZachary Turner Status ProcessWindows::DoHalt(bool &caused_stop) {
447a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
44897206d57SZachary Turner   Status error;
4494ad5def9SAdrian McCarthy   StateType state = GetPrivateState();
4504ad5def9SAdrian McCarthy   if (state == eStateStopped)
4514ad5def9SAdrian McCarthy     caused_stop = false;
4524ad5def9SAdrian McCarthy   else {
4534ad5def9SAdrian McCarthy     llvm::sys::ScopedLock lock(m_mutex);
4544ad5def9SAdrian McCarthy     caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess()
4554ad5def9SAdrian McCarthy                                           .GetNativeProcess()
4564ad5def9SAdrian McCarthy                                           .GetSystemHandle());
4574ad5def9SAdrian McCarthy     if (!caused_stop) {
4584ad5def9SAdrian McCarthy       error.SetError(::GetLastError(), eErrorTypeWin32);
459a385d2c1SPavel Labath       LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error);
4604ad5def9SAdrian McCarthy     }
4614ad5def9SAdrian McCarthy   }
4624ad5def9SAdrian McCarthy   return error;
4634ad5def9SAdrian McCarthy }
4644ad5def9SAdrian McCarthy 
4654ad5def9SAdrian McCarthy void ProcessWindows::DidLaunch() {
4664ad5def9SAdrian McCarthy   ArchSpec arch_spec;
4674ad5def9SAdrian McCarthy   DidAttach(arch_spec);
4684ad5def9SAdrian McCarthy }
4694ad5def9SAdrian McCarthy 
4704ad5def9SAdrian McCarthy void ProcessWindows::DidAttach(ArchSpec &arch_spec) {
4714ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
4724ad5def9SAdrian McCarthy 
4734ad5def9SAdrian McCarthy   // The initial stop won't broadcast the state change event, so account for
4744ad5def9SAdrian McCarthy   // that here.
4754ad5def9SAdrian McCarthy   if (m_session_data && GetPrivateState() == eStateStopped &&
4764ad5def9SAdrian McCarthy       m_session_data->m_stop_at_entry)
4774ad5def9SAdrian McCarthy     RefreshStateAfterStop();
4784ad5def9SAdrian McCarthy }
4794ad5def9SAdrian McCarthy 
4804ad5def9SAdrian McCarthy void ProcessWindows::RefreshStateAfterStop() {
481a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
4824ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
4834ad5def9SAdrian McCarthy 
4844ad5def9SAdrian McCarthy   if (!m_session_data) {
485a385d2c1SPavel Labath     LLDB_LOG(log, "no active session.  Returning...");
4864ad5def9SAdrian McCarthy     return;
4874ad5def9SAdrian McCarthy   }
4884ad5def9SAdrian McCarthy 
4894ad5def9SAdrian McCarthy   m_thread_list.RefreshStateAfterStop();
4904ad5def9SAdrian McCarthy 
4914ad5def9SAdrian McCarthy   std::weak_ptr<ExceptionRecord> exception_record =
4924ad5def9SAdrian McCarthy       m_session_data->m_debugger->GetActiveException();
4934ad5def9SAdrian McCarthy   ExceptionRecordSP active_exception = exception_record.lock();
4944ad5def9SAdrian McCarthy   if (!active_exception) {
49562c76db4SStella Stamenova     LLDB_LOG(log,
49662c76db4SStella Stamenova              "there is no active exception in process {0}.  Why is the "
497a385d2c1SPavel Labath              "process stopped?",
4984ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId());
4994ad5def9SAdrian McCarthy     return;
5004ad5def9SAdrian McCarthy   }
5014ad5def9SAdrian McCarthy 
5024ad5def9SAdrian McCarthy   StopInfoSP stop_info;
5034ad5def9SAdrian McCarthy   m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID());
5044ad5def9SAdrian McCarthy   ThreadSP stop_thread = m_thread_list.GetSelectedThread();
5054ad5def9SAdrian McCarthy   if (!stop_thread)
5064ad5def9SAdrian McCarthy     return;
5074ad5def9SAdrian McCarthy 
5084ad5def9SAdrian McCarthy   switch (active_exception->GetExceptionCode()) {
5094ad5def9SAdrian McCarthy   case EXCEPTION_SINGLE_STEP: {
5104ad5def9SAdrian McCarthy     RegisterContextSP register_context = stop_thread->GetRegisterContext();
5114ad5def9SAdrian McCarthy     const uint64_t pc = register_context->GetPC();
5124ad5def9SAdrian McCarthy     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
5134ad5def9SAdrian McCarthy     if (site && site->ValidForThisThread(stop_thread.get())) {
51462c76db4SStella Stamenova       LLDB_LOG(log,
51562c76db4SStella Stamenova                "Single-stepped onto a breakpoint in process {0} at "
516a385d2c1SPavel Labath                "address {1:x} with breakpoint site {2}",
5174ad5def9SAdrian McCarthy                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
5184ad5def9SAdrian McCarthy                site->GetID());
5194ad5def9SAdrian McCarthy       stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread,
5204ad5def9SAdrian McCarthy                                                                  site->GetID());
5214ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
5224ad5def9SAdrian McCarthy     } else {
523a385d2c1SPavel Labath       LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID());
5244ad5def9SAdrian McCarthy       stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
5254ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
5264ad5def9SAdrian McCarthy     }
5274ad5def9SAdrian McCarthy     return;
5284ad5def9SAdrian McCarthy   }
5294ad5def9SAdrian McCarthy 
5304ad5def9SAdrian McCarthy   case EXCEPTION_BREAKPOINT: {
5314ad5def9SAdrian McCarthy     RegisterContextSP register_context = stop_thread->GetRegisterContext();
5324ad5def9SAdrian McCarthy 
5334ad5def9SAdrian McCarthy     // The current EIP is AFTER the BP opcode, which is one byte.
5344ad5def9SAdrian McCarthy     uint64_t pc = register_context->GetPC() - 1;
5354ad5def9SAdrian McCarthy 
5364ad5def9SAdrian McCarthy     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
5374ad5def9SAdrian McCarthy     if (site) {
53862c76db4SStella Stamenova       LLDB_LOG(log,
53962c76db4SStella Stamenova                "detected breakpoint in process {0} at address {1:x} with "
540a385d2c1SPavel Labath                "breakpoint site {2}",
5414ad5def9SAdrian McCarthy                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
5424ad5def9SAdrian McCarthy                site->GetID());
5434ad5def9SAdrian McCarthy 
5444ad5def9SAdrian McCarthy       if (site->ValidForThisThread(stop_thread.get())) {
54562c76db4SStella Stamenova         LLDB_LOG(log,
54662c76db4SStella Stamenova                  "Breakpoint site {0} is valid for this thread ({1:x}), "
5474ad5def9SAdrian McCarthy                  "creating stop info.",
5484ad5def9SAdrian McCarthy                  site->GetID(), stop_thread->GetID());
5494ad5def9SAdrian McCarthy 
5504ad5def9SAdrian McCarthy         stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
5514ad5def9SAdrian McCarthy             *stop_thread, site->GetID());
5524ad5def9SAdrian McCarthy         register_context->SetPC(pc);
5534ad5def9SAdrian McCarthy       } else {
55462c76db4SStella Stamenova         LLDB_LOG(log,
55562c76db4SStella Stamenova                  "Breakpoint site {0} is not valid for this thread, "
5564ad5def9SAdrian McCarthy                  "creating empty stop info.",
5574ad5def9SAdrian McCarthy                  site->GetID());
5584ad5def9SAdrian McCarthy       }
5594ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
5604ad5def9SAdrian McCarthy       return;
5614ad5def9SAdrian McCarthy     } else {
5624ad5def9SAdrian McCarthy       // The thread hit a hard-coded breakpoint like an `int 3` or
5634ad5def9SAdrian McCarthy       // `__debugbreak()`.
564a385d2c1SPavel Labath       LLDB_LOG(log,
5654ad5def9SAdrian McCarthy                "No breakpoint site matches for this thread. __debugbreak()?  "
5664ad5def9SAdrian McCarthy                "Creating stop info with the exception.");
5674ad5def9SAdrian McCarthy       // FALLTHROUGH:  We'll treat this as a generic exception record in the
5684ad5def9SAdrian McCarthy       // default case.
5694ad5def9SAdrian McCarthy     }
5704ad5def9SAdrian McCarthy   }
5714ad5def9SAdrian McCarthy 
5724ad5def9SAdrian McCarthy   default: {
5734ad5def9SAdrian McCarthy     std::string desc;
5744ad5def9SAdrian McCarthy     llvm::raw_string_ostream desc_stream(desc);
5754ad5def9SAdrian McCarthy     desc_stream << "Exception "
5764ad5def9SAdrian McCarthy                 << llvm::format_hex(active_exception->GetExceptionCode(), 8)
5774ad5def9SAdrian McCarthy                 << " encountered at address "
5784ad5def9SAdrian McCarthy                 << llvm::format_hex(active_exception->GetExceptionAddress(), 8);
5794ad5def9SAdrian McCarthy     stop_info = StopInfo::CreateStopReasonWithException(
5804ad5def9SAdrian McCarthy         *stop_thread, desc_stream.str().c_str());
5814ad5def9SAdrian McCarthy     stop_thread->SetStopInfo(stop_info);
582a385d2c1SPavel Labath     LLDB_LOG(log, "{0}", desc_stream.str());
5834ad5def9SAdrian McCarthy     return;
5844ad5def9SAdrian McCarthy   }
5854ad5def9SAdrian McCarthy   }
5864ad5def9SAdrian McCarthy }
5874ad5def9SAdrian McCarthy 
5884ad5def9SAdrian McCarthy bool ProcessWindows::CanDebug(lldb::TargetSP target_sp,
5894ad5def9SAdrian McCarthy                               bool plugin_specified_by_name) {
5904ad5def9SAdrian McCarthy   if (plugin_specified_by_name)
5914ad5def9SAdrian McCarthy     return true;
5924ad5def9SAdrian McCarthy 
5934ad5def9SAdrian McCarthy   // For now we are just making sure the file exists for a given module
5944ad5def9SAdrian McCarthy   ModuleSP exe_module_sp(target_sp->GetExecutableModule());
5954ad5def9SAdrian McCarthy   if (exe_module_sp.get())
59660cf3f82SJonas Devlieghere     return FileSystem::Instance().Exists(exe_module_sp->GetFileSpec());
59705097246SAdrian Prantl   // However, if there is no executable module, we return true since we might
59805097246SAdrian Prantl   // be preparing to attach.
5994ad5def9SAdrian McCarthy   return true;
6004ad5def9SAdrian McCarthy }
6014ad5def9SAdrian McCarthy 
6024ad5def9SAdrian McCarthy bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list,
6034ad5def9SAdrian McCarthy                                       ThreadList &new_thread_list) {
604a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_THREAD);
6054ad5def9SAdrian McCarthy   // Add all the threads that were previously running and for which we did not
6064ad5def9SAdrian McCarthy   // detect a thread exited event.
6074ad5def9SAdrian McCarthy   int new_size = 0;
6084ad5def9SAdrian McCarthy   int continued_threads = 0;
6094ad5def9SAdrian McCarthy   int exited_threads = 0;
6104ad5def9SAdrian McCarthy   int new_threads = 0;
6114ad5def9SAdrian McCarthy 
6124ad5def9SAdrian McCarthy   for (ThreadSP old_thread : old_thread_list.Threads()) {
6134ad5def9SAdrian McCarthy     lldb::tid_t old_thread_id = old_thread->GetID();
6144ad5def9SAdrian McCarthy     auto exited_thread_iter =
6154ad5def9SAdrian McCarthy         m_session_data->m_exited_threads.find(old_thread_id);
6164ad5def9SAdrian McCarthy     if (exited_thread_iter == m_session_data->m_exited_threads.end()) {
6174ad5def9SAdrian McCarthy       new_thread_list.AddThread(old_thread);
6184ad5def9SAdrian McCarthy       ++new_size;
6194ad5def9SAdrian McCarthy       ++continued_threads;
620a385d2c1SPavel Labath       LLDB_LOGV(log, "Thread {0} was running and is still running.",
6214ad5def9SAdrian McCarthy                 old_thread_id);
6224ad5def9SAdrian McCarthy     } else {
623a385d2c1SPavel Labath       LLDB_LOGV(log, "Thread {0} was running and has exited.", old_thread_id);
6244ad5def9SAdrian McCarthy       ++exited_threads;
6254ad5def9SAdrian McCarthy     }
6264ad5def9SAdrian McCarthy   }
6274ad5def9SAdrian McCarthy 
62805097246SAdrian Prantl   // Also add all the threads that are new since the last time we broke into
62905097246SAdrian Prantl   // the debugger.
6304ad5def9SAdrian McCarthy   for (const auto &thread_info : m_session_data->m_new_threads) {
6314ad5def9SAdrian McCarthy     ThreadSP thread(new TargetThreadWindows(*this, thread_info.second));
6324ad5def9SAdrian McCarthy     thread->SetID(thread_info.first);
6334ad5def9SAdrian McCarthy     new_thread_list.AddThread(thread);
6344ad5def9SAdrian McCarthy     ++new_size;
6354ad5def9SAdrian McCarthy     ++new_threads;
636a385d2c1SPavel Labath     LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first);
6374ad5def9SAdrian McCarthy   }
6384ad5def9SAdrian McCarthy 
639a385d2c1SPavel Labath   LLDB_LOG(log, "{0} new threads, {1} old threads, {2} exited threads.",
6404ad5def9SAdrian McCarthy            new_threads, continued_threads, exited_threads);
6414ad5def9SAdrian McCarthy 
6424ad5def9SAdrian McCarthy   m_session_data->m_new_threads.clear();
6434ad5def9SAdrian McCarthy   m_session_data->m_exited_threads.clear();
6444ad5def9SAdrian McCarthy 
6454ad5def9SAdrian McCarthy   return new_size > 0;
6464ad5def9SAdrian McCarthy }
6474ad5def9SAdrian McCarthy 
6484ad5def9SAdrian McCarthy bool ProcessWindows::IsAlive() {
6494ad5def9SAdrian McCarthy   StateType state = GetPrivateState();
6504ad5def9SAdrian McCarthy   switch (state) {
6514ad5def9SAdrian McCarthy   case eStateCrashed:
6524ad5def9SAdrian McCarthy   case eStateDetached:
6534ad5def9SAdrian McCarthy   case eStateUnloaded:
6544ad5def9SAdrian McCarthy   case eStateExited:
6554ad5def9SAdrian McCarthy   case eStateInvalid:
6564ad5def9SAdrian McCarthy     return false;
6574ad5def9SAdrian McCarthy   default:
6584ad5def9SAdrian McCarthy     return true;
6594ad5def9SAdrian McCarthy   }
6604ad5def9SAdrian McCarthy }
6614ad5def9SAdrian McCarthy 
6624ad5def9SAdrian McCarthy size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf,
66397206d57SZachary Turner                                     size_t size, Status &error) {
664a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
6654ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
6664ad5def9SAdrian McCarthy 
6674ad5def9SAdrian McCarthy   if (!m_session_data)
6684ad5def9SAdrian McCarthy     return 0;
6694ad5def9SAdrian McCarthy 
670a385d2c1SPavel Labath   LLDB_LOG(log, "attempting to read {0} bytes from address {1:x}", size,
671a385d2c1SPavel Labath            vm_addr);
6724ad5def9SAdrian McCarthy 
6734ad5def9SAdrian McCarthy   HostProcess process = m_session_data->m_debugger->GetProcess();
6744ad5def9SAdrian McCarthy   void *addr = reinterpret_cast<void *>(vm_addr);
6754ad5def9SAdrian McCarthy   SIZE_T bytes_read = 0;
6764ad5def9SAdrian McCarthy   if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr,
6774ad5def9SAdrian McCarthy                          buf, size, &bytes_read)) {
67862c76db4SStella Stamenova     // Reading from the process can fail for a number of reasons - set the
67962c76db4SStella Stamenova     // error code and make sure that the number of bytes read is set back to 0
68062c76db4SStella Stamenova     // because in some scenarios the value of bytes_read returned from the API
68162c76db4SStella Stamenova     // is garbage.
6824ad5def9SAdrian McCarthy     error.SetError(GetLastError(), eErrorTypeWin32);
683a385d2c1SPavel Labath     LLDB_LOG(log, "reading failed with error: {0}", error);
68462c76db4SStella Stamenova     bytes_read = 0;
6854ad5def9SAdrian McCarthy   }
6864ad5def9SAdrian McCarthy   return bytes_read;
6874ad5def9SAdrian McCarthy }
6884ad5def9SAdrian McCarthy 
6894ad5def9SAdrian McCarthy size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
69097206d57SZachary Turner                                      size_t size, Status &error) {
691a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
6924ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
693a385d2c1SPavel Labath   LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size,
6944ad5def9SAdrian McCarthy            vm_addr);
6954ad5def9SAdrian McCarthy 
6964ad5def9SAdrian McCarthy   if (!m_session_data) {
697a385d2c1SPavel Labath     LLDB_LOG(log, "cannot write, there is no active debugger connection.");
6984ad5def9SAdrian McCarthy     return 0;
6994ad5def9SAdrian McCarthy   }
7004ad5def9SAdrian McCarthy 
7014ad5def9SAdrian McCarthy   HostProcess process = m_session_data->m_debugger->GetProcess();
7024ad5def9SAdrian McCarthy   void *addr = reinterpret_cast<void *>(vm_addr);
7034ad5def9SAdrian McCarthy   SIZE_T bytes_written = 0;
7044ad5def9SAdrian McCarthy   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
7054ad5def9SAdrian McCarthy   if (WriteProcessMemory(handle, addr, buf, size, &bytes_written))
7064ad5def9SAdrian McCarthy     FlushInstructionCache(handle, addr, bytes_written);
7074ad5def9SAdrian McCarthy   else {
7084ad5def9SAdrian McCarthy     error.SetError(GetLastError(), eErrorTypeWin32);
709a385d2c1SPavel Labath     LLDB_LOG(log, "writing failed with error: {0}", error);
7104ad5def9SAdrian McCarthy   }
7114ad5def9SAdrian McCarthy   return bytes_written;
7124ad5def9SAdrian McCarthy }
7134ad5def9SAdrian McCarthy 
7149d5b2d4aSAleksandr Urakov lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions,
7159d5b2d4aSAleksandr Urakov                                               Status &error) {
7169d5b2d4aSAleksandr Urakov   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
7179d5b2d4aSAleksandr Urakov   llvm::sys::ScopedLock lock(m_mutex);
7189d5b2d4aSAleksandr Urakov   LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size,
7199d5b2d4aSAleksandr Urakov            permissions);
7209d5b2d4aSAleksandr Urakov 
7219d5b2d4aSAleksandr Urakov   if (!m_session_data) {
7229d5b2d4aSAleksandr Urakov     LLDB_LOG(log, "cannot allocate, there is no active debugger connection.");
7239d5b2d4aSAleksandr Urakov     error.SetErrorString(
7249d5b2d4aSAleksandr Urakov         "cannot allocate, there is no active debugger connection");
725975814a7SStella Stamenova     return LLDB_INVALID_ADDRESS;
7269d5b2d4aSAleksandr Urakov   }
7279d5b2d4aSAleksandr Urakov 
7289d5b2d4aSAleksandr Urakov   HostProcess process = m_session_data->m_debugger->GetProcess();
7299d5b2d4aSAleksandr Urakov   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
7309d5b2d4aSAleksandr Urakov   auto protect = ConvertLldbToWinApiProtect(permissions);
7319d5b2d4aSAleksandr Urakov   auto result = VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect);
7329d5b2d4aSAleksandr Urakov   if (!result) {
7339d5b2d4aSAleksandr Urakov     error.SetError(GetLastError(), eErrorTypeWin32);
7349d5b2d4aSAleksandr Urakov     LLDB_LOG(log, "allocating failed with error: {0}", error);
735975814a7SStella Stamenova     return LLDB_INVALID_ADDRESS;
7369d5b2d4aSAleksandr Urakov   }
7379d5b2d4aSAleksandr Urakov 
7389d5b2d4aSAleksandr Urakov   return reinterpret_cast<addr_t>(result);
7399d5b2d4aSAleksandr Urakov }
7409d5b2d4aSAleksandr Urakov 
7419d5b2d4aSAleksandr Urakov Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) {
7429d5b2d4aSAleksandr Urakov   Status result;
7439d5b2d4aSAleksandr Urakov 
7449d5b2d4aSAleksandr Urakov   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
7459d5b2d4aSAleksandr Urakov   llvm::sys::ScopedLock lock(m_mutex);
7469d5b2d4aSAleksandr Urakov   LLDB_LOG(log, "attempting to deallocate bytes at address {0}", ptr);
7479d5b2d4aSAleksandr Urakov 
7489d5b2d4aSAleksandr Urakov   if (!m_session_data) {
7499d5b2d4aSAleksandr Urakov     LLDB_LOG(log, "cannot deallocate, there is no active debugger connection.");
7509d5b2d4aSAleksandr Urakov     result.SetErrorString(
7519d5b2d4aSAleksandr Urakov         "cannot deallocate, there is no active debugger connection");
7529d5b2d4aSAleksandr Urakov     return result;
7539d5b2d4aSAleksandr Urakov   }
7549d5b2d4aSAleksandr Urakov 
7559d5b2d4aSAleksandr Urakov   HostProcess process = m_session_data->m_debugger->GetProcess();
7569d5b2d4aSAleksandr Urakov   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
7579d5b2d4aSAleksandr Urakov   if (!VirtualFreeEx(handle, reinterpret_cast<LPVOID>(ptr), 0, MEM_RELEASE)) {
7589d5b2d4aSAleksandr Urakov     result.SetError(GetLastError(), eErrorTypeWin32);
7599d5b2d4aSAleksandr Urakov     LLDB_LOG(log, "deallocating failed with error: {0}", result);
7609d5b2d4aSAleksandr Urakov     return result;
7619d5b2d4aSAleksandr Urakov   }
7629d5b2d4aSAleksandr Urakov 
7639d5b2d4aSAleksandr Urakov   return result;
7649d5b2d4aSAleksandr Urakov }
7659d5b2d4aSAleksandr Urakov 
76697206d57SZachary Turner Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr,
7674ad5def9SAdrian McCarthy                                            MemoryRegionInfo &info) {
768a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
76997206d57SZachary Turner   Status error;
7704ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
7714ad5def9SAdrian McCarthy   info.Clear();
7724ad5def9SAdrian McCarthy 
7734ad5def9SAdrian McCarthy   if (!m_session_data) {
7744ad5def9SAdrian McCarthy     error.SetErrorString(
7754ad5def9SAdrian McCarthy         "GetMemoryRegionInfo called with no debugging session.");
776a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
7774ad5def9SAdrian McCarthy     return error;
7784ad5def9SAdrian McCarthy   }
7794ad5def9SAdrian McCarthy   HostProcess process = m_session_data->m_debugger->GetProcess();
7804ad5def9SAdrian McCarthy   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
7814ad5def9SAdrian McCarthy   if (handle == nullptr || handle == LLDB_INVALID_PROCESS) {
7824ad5def9SAdrian McCarthy     error.SetErrorString(
7834ad5def9SAdrian McCarthy         "GetMemoryRegionInfo called with an invalid target process.");
784a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
7854ad5def9SAdrian McCarthy     return error;
7864ad5def9SAdrian McCarthy   }
7874ad5def9SAdrian McCarthy 
788a385d2c1SPavel Labath   LLDB_LOG(log, "getting info for address {0:x}", vm_addr);
7894ad5def9SAdrian McCarthy 
7904ad5def9SAdrian McCarthy   void *addr = reinterpret_cast<void *>(vm_addr);
7914ad5def9SAdrian McCarthy   MEMORY_BASIC_INFORMATION mem_info = {};
7924ad5def9SAdrian McCarthy   SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
7934ad5def9SAdrian McCarthy   if (result == 0) {
7944ad5def9SAdrian McCarthy     if (::GetLastError() == ERROR_INVALID_PARAMETER) {
79505097246SAdrian Prantl       // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with
79605097246SAdrian Prantl       // an address past the highest accessible address. We should return a
79705097246SAdrian Prantl       // range from the vm_addr to LLDB_INVALID_ADDRESS
7984ad5def9SAdrian McCarthy       info.GetRange().SetRangeBase(vm_addr);
7994ad5def9SAdrian McCarthy       info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
8004ad5def9SAdrian McCarthy       info.SetReadable(MemoryRegionInfo::eNo);
8014ad5def9SAdrian McCarthy       info.SetExecutable(MemoryRegionInfo::eNo);
8024ad5def9SAdrian McCarthy       info.SetWritable(MemoryRegionInfo::eNo);
8034ad5def9SAdrian McCarthy       info.SetMapped(MemoryRegionInfo::eNo);
8044ad5def9SAdrian McCarthy       return error;
8054ad5def9SAdrian McCarthy     } else {
8064ad5def9SAdrian McCarthy       error.SetError(::GetLastError(), eErrorTypeWin32);
80762c76db4SStella Stamenova       LLDB_LOG(log,
80862c76db4SStella Stamenova                "VirtualQueryEx returned error {0} while getting memory "
809a385d2c1SPavel Labath                "region info for address {1:x}",
810a385d2c1SPavel Labath                error, vm_addr);
8114ad5def9SAdrian McCarthy       return error;
8124ad5def9SAdrian McCarthy     }
8134ad5def9SAdrian McCarthy   }
8144ad5def9SAdrian McCarthy 
8154ad5def9SAdrian McCarthy   // Protect bits are only valid for MEM_COMMIT regions.
8164ad5def9SAdrian McCarthy   if (mem_info.State == MEM_COMMIT) {
8174ad5def9SAdrian McCarthy     const bool readable = IsPageReadable(mem_info.Protect);
8184ad5def9SAdrian McCarthy     const bool executable = IsPageExecutable(mem_info.Protect);
8194ad5def9SAdrian McCarthy     const bool writable = IsPageWritable(mem_info.Protect);
8204ad5def9SAdrian McCarthy     info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
8214ad5def9SAdrian McCarthy     info.SetExecutable(executable ? MemoryRegionInfo::eYes
8224ad5def9SAdrian McCarthy                                   : MemoryRegionInfo::eNo);
8234ad5def9SAdrian McCarthy     info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
8244ad5def9SAdrian McCarthy   } else {
8254ad5def9SAdrian McCarthy     info.SetReadable(MemoryRegionInfo::eNo);
8264ad5def9SAdrian McCarthy     info.SetExecutable(MemoryRegionInfo::eNo);
8274ad5def9SAdrian McCarthy     info.SetWritable(MemoryRegionInfo::eNo);
8284ad5def9SAdrian McCarthy   }
8294ad5def9SAdrian McCarthy 
8304ad5def9SAdrian McCarthy   // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE.
8314ad5def9SAdrian McCarthy   if (mem_info.State != MEM_FREE) {
8324ad5def9SAdrian McCarthy     info.GetRange().SetRangeBase(
8334ad5def9SAdrian McCarthy         reinterpret_cast<addr_t>(mem_info.AllocationBase));
8344ad5def9SAdrian McCarthy     info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) +
8354ad5def9SAdrian McCarthy                                 mem_info.RegionSize);
8364ad5def9SAdrian McCarthy     info.SetMapped(MemoryRegionInfo::eYes);
8374ad5def9SAdrian McCarthy   } else {
8384ad5def9SAdrian McCarthy     // In the unmapped case we need to return the distance to the next block of
83905097246SAdrian Prantl     // memory. VirtualQueryEx nearly does that except that it gives the
84005097246SAdrian Prantl     // distance from the start of the page containing vm_addr.
8414ad5def9SAdrian McCarthy     SYSTEM_INFO data;
8424ad5def9SAdrian McCarthy     GetSystemInfo(&data);
8434ad5def9SAdrian McCarthy     DWORD page_offset = vm_addr % data.dwPageSize;
8444ad5def9SAdrian McCarthy     info.GetRange().SetRangeBase(vm_addr);
8454ad5def9SAdrian McCarthy     info.GetRange().SetByteSize(mem_info.RegionSize - page_offset);
8464ad5def9SAdrian McCarthy     info.SetMapped(MemoryRegionInfo::eNo);
8474ad5def9SAdrian McCarthy   }
8484ad5def9SAdrian McCarthy 
8494ad5def9SAdrian McCarthy   error.SetError(::GetLastError(), eErrorTypeWin32);
85062c76db4SStella Stamenova   LLDB_LOGV(log,
85162c76db4SStella Stamenova             "Memory region info for address {0}: readable={1}, "
852a385d2c1SPavel Labath             "executable={2}, writable={3}",
853a385d2c1SPavel Labath             vm_addr, info.GetReadable(), info.GetExecutable(),
854a385d2c1SPavel Labath             info.GetWritable());
8554ad5def9SAdrian McCarthy   return error;
8564ad5def9SAdrian McCarthy }
8574ad5def9SAdrian McCarthy 
858b9c1b51eSKate Stone lldb::addr_t ProcessWindows::GetImageInfoAddress() {
85918a9135dSAdrian McCarthy   Target &target = GetTarget();
86018a9135dSAdrian McCarthy   ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile();
86118a9135dSAdrian McCarthy   Address addr = obj_file->GetImageInfoAddress(&target);
86218a9135dSAdrian McCarthy   if (addr.IsValid())
86318a9135dSAdrian McCarthy     return addr.GetLoadAddress(&target);
86418a9135dSAdrian McCarthy   else
86518a9135dSAdrian McCarthy     return LLDB_INVALID_ADDRESS;
86618a9135dSAdrian McCarthy }
86718a9135dSAdrian McCarthy 
8684ad5def9SAdrian McCarthy void ProcessWindows::OnExitProcess(uint32_t exit_code) {
8694ad5def9SAdrian McCarthy   // No need to acquire the lock since m_session_data isn't accessed.
870a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
871a385d2c1SPavel Labath   LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
8724ad5def9SAdrian McCarthy 
873d7e126c4SJim Ingham   TargetSP target = CalculateTarget();
8744ad5def9SAdrian McCarthy   if (target) {
8754ad5def9SAdrian McCarthy     ModuleSP executable_module = target->GetExecutableModule();
8764ad5def9SAdrian McCarthy     ModuleList unloaded_modules;
8774ad5def9SAdrian McCarthy     unloaded_modules.Append(executable_module);
8784ad5def9SAdrian McCarthy     target->ModulesDidUnload(unloaded_modules, true);
8794ad5def9SAdrian McCarthy   }
8804ad5def9SAdrian McCarthy 
8814ad5def9SAdrian McCarthy   SetProcessExitStatus(GetID(), true, 0, exit_code);
8824ad5def9SAdrian McCarthy   SetPrivateState(eStateExited);
883e3037904SAaron Smith 
884e3037904SAaron Smith   // If the process exits before any initial stop then notify the debugger
885e3037904SAaron Smith   // of the error otherwise WaitForDebuggerConnection() will be blocked.
886e3037904SAaron Smith   // An example of this issue is when a process fails to load a dependent DLL.
887*c28daec5SAaron Smith   if (m_session_data && !m_session_data->m_initial_stop_received) {
888e3037904SAaron Smith     Status error(exit_code, eErrorTypeWin32);
889e3037904SAaron Smith     OnDebuggerError(error, 0);
890e3037904SAaron Smith   }
8914ad5def9SAdrian McCarthy }
8924ad5def9SAdrian McCarthy 
8934ad5def9SAdrian McCarthy void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
8944ad5def9SAdrian McCarthy   DebuggerThreadSP debugger = m_session_data->m_debugger;
895a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
896a385d2c1SPavel Labath   LLDB_LOG(log, "Debugger connected to process {0}.  Image base = {1:x}",
8974ad5def9SAdrian McCarthy            debugger->GetProcess().GetProcessId(), image_base);
8984ad5def9SAdrian McCarthy 
8994ad5def9SAdrian McCarthy   ModuleSP module = GetTarget().GetExecutableModule();
9004ad5def9SAdrian McCarthy   if (!module) {
9014ad5def9SAdrian McCarthy     // During attach, we won't have the executable module, so find it now.
9024ad5def9SAdrian McCarthy     const DWORD pid = debugger->GetProcess().GetProcessId();
9034ad5def9SAdrian McCarthy     const std::string file_name = GetProcessExecutableName(pid);
9044ad5def9SAdrian McCarthy     if (file_name.empty()) {
9054ad5def9SAdrian McCarthy       return;
9064ad5def9SAdrian McCarthy     }
9074ad5def9SAdrian McCarthy 
90854bb3161SAleksandr Urakov     FileSpec executable_file(file_name);
90954bb3161SAleksandr Urakov     FileSystem::Instance().Resolve(executable_file);
9104ad5def9SAdrian McCarthy     ModuleSpec module_spec(executable_file);
91197206d57SZachary Turner     Status error;
9124ad5def9SAdrian McCarthy     module = GetTarget().GetSharedModule(module_spec, &error);
9134ad5def9SAdrian McCarthy     if (!module) {
9144ad5def9SAdrian McCarthy       return;
9154ad5def9SAdrian McCarthy     }
9164ad5def9SAdrian McCarthy 
917d54ee88aSTatyana Krasnukha     GetTarget().SetExecutableModule(module, eLoadDependentsNo);
9184ad5def9SAdrian McCarthy   }
9194ad5def9SAdrian McCarthy 
9204ad5def9SAdrian McCarthy   bool load_addr_changed;
9214ad5def9SAdrian McCarthy   module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed);
9224ad5def9SAdrian McCarthy 
9234ad5def9SAdrian McCarthy   ModuleList loaded_modules;
9244ad5def9SAdrian McCarthy   loaded_modules.Append(module);
9254ad5def9SAdrian McCarthy   GetTarget().ModulesDidLoad(loaded_modules);
9264ad5def9SAdrian McCarthy 
9274ad5def9SAdrian McCarthy   // Add the main executable module to the list of pending module loads.  We
92805097246SAdrian Prantl   // can't call GetTarget().ModulesDidLoad() here because we still haven't
92905097246SAdrian Prantl   // returned from DoLaunch() / DoAttach() yet so the target may not have set
93005097246SAdrian Prantl   // the process instance to `this` yet.
9314ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
9324ad5def9SAdrian McCarthy   const HostThreadWindows &wmain_thread =
9334ad5def9SAdrian McCarthy       debugger->GetMainThread().GetNativeThread();
9344ad5def9SAdrian McCarthy   m_session_data->m_new_threads[wmain_thread.GetThreadId()] =
9354ad5def9SAdrian McCarthy       debugger->GetMainThread();
9364ad5def9SAdrian McCarthy }
9374ad5def9SAdrian McCarthy 
9384ad5def9SAdrian McCarthy ExceptionResult
9394ad5def9SAdrian McCarthy ProcessWindows::OnDebugException(bool first_chance,
9404ad5def9SAdrian McCarthy                                  const ExceptionRecord &record) {
941a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
9424ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
9434ad5def9SAdrian McCarthy 
9444ad5def9SAdrian McCarthy   // FIXME: Without this check, occasionally when running the test suite there
9454ad5def9SAdrian McCarthy   // is
9464ad5def9SAdrian McCarthy   // an issue where m_session_data can be null.  It's not clear how this could
94705097246SAdrian Prantl   // happen but it only surfaces while running the test suite.  In order to
94805097246SAdrian Prantl   // properly diagnose this, we probably need to first figure allow the test
94905097246SAdrian Prantl   // suite to print out full lldb logs, and then add logging to the process
95005097246SAdrian Prantl   // plugin.
9514ad5def9SAdrian McCarthy   if (!m_session_data) {
95262c76db4SStella Stamenova     LLDB_LOG(log,
95362c76db4SStella Stamenova              "Debugger thread reported exception {0:x} at address {1:x}, "
954a385d2c1SPavel Labath              "but there is no session.",
9554ad5def9SAdrian McCarthy              record.GetExceptionCode(), record.GetExceptionAddress());
9564ad5def9SAdrian McCarthy     return ExceptionResult::SendToApplication;
9574ad5def9SAdrian McCarthy   }
9584ad5def9SAdrian McCarthy 
9594ad5def9SAdrian McCarthy   if (!first_chance) {
960a5235af9SAleksandr Urakov     // Not any second chance exception is an application crash by definition.
961a5235af9SAleksandr Urakov     // It may be an expression evaluation crash.
962a5235af9SAleksandr Urakov     SetPrivateState(eStateStopped);
9634ad5def9SAdrian McCarthy   }
9644ad5def9SAdrian McCarthy 
9654ad5def9SAdrian McCarthy   ExceptionResult result = ExceptionResult::SendToApplication;
9664ad5def9SAdrian McCarthy   switch (record.GetExceptionCode()) {
9674ad5def9SAdrian McCarthy   case EXCEPTION_BREAKPOINT:
9684ad5def9SAdrian McCarthy     // Handle breakpoints at the first chance.
9694ad5def9SAdrian McCarthy     result = ExceptionResult::BreakInDebugger;
9704ad5def9SAdrian McCarthy 
9714ad5def9SAdrian McCarthy     if (!m_session_data->m_initial_stop_received) {
972a385d2c1SPavel Labath       LLDB_LOG(
973a385d2c1SPavel Labath           log,
974a385d2c1SPavel Labath           "Hit loader breakpoint at address {0:x}, setting initial stop event.",
9754ad5def9SAdrian McCarthy           record.GetExceptionAddress());
9764ad5def9SAdrian McCarthy       m_session_data->m_initial_stop_received = true;
9774ad5def9SAdrian McCarthy       ::SetEvent(m_session_data->m_initial_stop_event);
9784ad5def9SAdrian McCarthy     } else {
979a385d2c1SPavel Labath       LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
9804ad5def9SAdrian McCarthy                record.GetExceptionAddress());
9814ad5def9SAdrian McCarthy     }
9824ad5def9SAdrian McCarthy     SetPrivateState(eStateStopped);
9834ad5def9SAdrian McCarthy     break;
9844ad5def9SAdrian McCarthy   case EXCEPTION_SINGLE_STEP:
9854ad5def9SAdrian McCarthy     result = ExceptionResult::BreakInDebugger;
9864ad5def9SAdrian McCarthy     SetPrivateState(eStateStopped);
9874ad5def9SAdrian McCarthy     break;
9884ad5def9SAdrian McCarthy   default:
98962c76db4SStella Stamenova     LLDB_LOG(log,
99062c76db4SStella Stamenova              "Debugger thread reported exception {0:x} at address {1:x} "
991a385d2c1SPavel Labath              "(first_chance={2})",
9924ad5def9SAdrian McCarthy              record.GetExceptionCode(), record.GetExceptionAddress(),
993a385d2c1SPavel Labath              first_chance);
9944ad5def9SAdrian McCarthy     // For non-breakpoints, give the application a chance to handle the
9954ad5def9SAdrian McCarthy     // exception first.
9964ad5def9SAdrian McCarthy     if (first_chance)
9974ad5def9SAdrian McCarthy       result = ExceptionResult::SendToApplication;
9984ad5def9SAdrian McCarthy     else
9994ad5def9SAdrian McCarthy       result = ExceptionResult::BreakInDebugger;
10004ad5def9SAdrian McCarthy   }
10014ad5def9SAdrian McCarthy 
10024ad5def9SAdrian McCarthy   return result;
10034ad5def9SAdrian McCarthy }
10044ad5def9SAdrian McCarthy 
10054ad5def9SAdrian McCarthy void ProcessWindows::OnCreateThread(const HostThread &new_thread) {
10064ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
10074ad5def9SAdrian McCarthy   const HostThreadWindows &wnew_thread = new_thread.GetNativeThread();
10084ad5def9SAdrian McCarthy   m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread;
10094ad5def9SAdrian McCarthy }
10104ad5def9SAdrian McCarthy 
10114ad5def9SAdrian McCarthy void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
10124ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
10134ad5def9SAdrian McCarthy 
10144ad5def9SAdrian McCarthy   // On a forced termination, we may get exit thread events after the session
10154ad5def9SAdrian McCarthy   // data has been cleaned up.
10164ad5def9SAdrian McCarthy   if (!m_session_data)
10174ad5def9SAdrian McCarthy     return;
10184ad5def9SAdrian McCarthy 
10194ad5def9SAdrian McCarthy   // A thread may have started and exited before the debugger stopped allowing a
10204ad5def9SAdrian McCarthy   // refresh.
10214ad5def9SAdrian McCarthy   // Just remove it from the new threads list in that case.
10224ad5def9SAdrian McCarthy   auto iter = m_session_data->m_new_threads.find(thread_id);
10234ad5def9SAdrian McCarthy   if (iter != m_session_data->m_new_threads.end())
10244ad5def9SAdrian McCarthy     m_session_data->m_new_threads.erase(iter);
10254ad5def9SAdrian McCarthy   else
10264ad5def9SAdrian McCarthy     m_session_data->m_exited_threads.insert(thread_id);
10274ad5def9SAdrian McCarthy }
10284ad5def9SAdrian McCarthy 
10294ad5def9SAdrian McCarthy void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
10304ad5def9SAdrian McCarthy                                lldb::addr_t module_addr) {
10314ad5def9SAdrian McCarthy   // Confusingly, there is no Target::AddSharedModule.  Instead, calling
103205097246SAdrian Prantl   // GetSharedModule() with a new module will add it to the module list and
103305097246SAdrian Prantl   // return a corresponding ModuleSP.
103497206d57SZachary Turner   Status error;
10354ad5def9SAdrian McCarthy   ModuleSP module = GetTarget().GetSharedModule(module_spec, &error);
10364ad5def9SAdrian McCarthy   bool load_addr_changed = false;
10374ad5def9SAdrian McCarthy   module->SetLoadAddress(GetTarget(), module_addr, false, load_addr_changed);
10384ad5def9SAdrian McCarthy 
10394ad5def9SAdrian McCarthy   ModuleList loaded_modules;
10404ad5def9SAdrian McCarthy   loaded_modules.Append(module);
10414ad5def9SAdrian McCarthy   GetTarget().ModulesDidLoad(loaded_modules);
10424ad5def9SAdrian McCarthy }
10434ad5def9SAdrian McCarthy 
10444ad5def9SAdrian McCarthy void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
10454ad5def9SAdrian McCarthy   Address resolved_addr;
10464ad5def9SAdrian McCarthy   if (GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) {
10474ad5def9SAdrian McCarthy     ModuleSP module = resolved_addr.GetModule();
10484ad5def9SAdrian McCarthy     if (module) {
10494ad5def9SAdrian McCarthy       ModuleList unloaded_modules;
10504ad5def9SAdrian McCarthy       unloaded_modules.Append(module);
10514ad5def9SAdrian McCarthy       GetTarget().ModulesDidUnload(unloaded_modules, false);
10524ad5def9SAdrian McCarthy     }
10534ad5def9SAdrian McCarthy   }
10544ad5def9SAdrian McCarthy }
10554ad5def9SAdrian McCarthy 
10564ad5def9SAdrian McCarthy void ProcessWindows::OnDebugString(const std::string &string) {}
10574ad5def9SAdrian McCarthy 
105897206d57SZachary Turner void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) {
10594ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
1060a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
10614ad5def9SAdrian McCarthy 
10624ad5def9SAdrian McCarthy   if (m_session_data->m_initial_stop_received) {
106305097246SAdrian Prantl     // This happened while debugging.  Do we shutdown the debugging session,
106405097246SAdrian Prantl     // try to continue, or do something else?
106562c76db4SStella Stamenova     LLDB_LOG(log,
106662c76db4SStella Stamenova              "Error {0} occurred during debugging.  Unexpected behavior "
1067a385d2c1SPavel Labath              "may result.  {1}",
1068a385d2c1SPavel Labath              error.GetError(), error);
10694ad5def9SAdrian McCarthy   } else {
10704ad5def9SAdrian McCarthy     // If we haven't actually launched the process yet, this was an error
107105097246SAdrian Prantl     // launching the process.  Set the internal error and signal the initial
107205097246SAdrian Prantl     // stop event so that the DoLaunch method wakes up and returns a failure.
10734ad5def9SAdrian McCarthy     m_session_data->m_launch_error = error;
10744ad5def9SAdrian McCarthy     ::SetEvent(m_session_data->m_initial_stop_event);
1075a385d2c1SPavel Labath     LLDB_LOG(
1076a385d2c1SPavel Labath         log,
1077a385d2c1SPavel Labath         "Error {0} occurred launching the process before the initial stop. {1}",
1078a385d2c1SPavel Labath         error.GetError(), error);
10794ad5def9SAdrian McCarthy     return;
10804ad5def9SAdrian McCarthy   }
10814ad5def9SAdrian McCarthy }
10824ad5def9SAdrian McCarthy 
108397206d57SZachary Turner Status ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger,
10844ad5def9SAdrian McCarthy                                                  HostProcess &process) {
108597206d57SZachary Turner   Status result;
1086a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS |
1087a385d2c1SPavel Labath                                             WINDOWS_LOG_BREAKPOINTS);
1088a385d2c1SPavel Labath   LLDB_LOG(log, "Waiting for loader breakpoint.");
10894ad5def9SAdrian McCarthy 
10904ad5def9SAdrian McCarthy   // Block this function until we receive the initial stop from the process.
10914ad5def9SAdrian McCarthy   if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) ==
10924ad5def9SAdrian McCarthy       WAIT_OBJECT_0) {
1093a385d2c1SPavel Labath     LLDB_LOG(log, "hit loader breakpoint, returning.");
10944ad5def9SAdrian McCarthy 
10954ad5def9SAdrian McCarthy     process = debugger->GetProcess();
10964ad5def9SAdrian McCarthy     return m_session_data->m_launch_error;
10974ad5def9SAdrian McCarthy   } else
109897206d57SZachary Turner     return Status(::GetLastError(), eErrorTypeWin32);
10994ad5def9SAdrian McCarthy }
11004ad5def9SAdrian McCarthy 
1101b9c1b51eSKate Stone // The Windows page protection bits are NOT independent masks that can be
110205097246SAdrian Prantl // bitwise-ORed together.  For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE
110305097246SAdrian Prantl // | PAGE_READ).  To test for an access type, it's necessary to test for any of
110405097246SAdrian Prantl // the bits that provide that access type.
1105b9c1b51eSKate Stone bool ProcessWindows::IsPageReadable(uint32_t protect) {
11060c35cde9SAdrian McCarthy   return (protect & PAGE_NOACCESS) == 0;
11070c35cde9SAdrian McCarthy }
11080c35cde9SAdrian McCarthy 
1109b9c1b51eSKate Stone bool ProcessWindows::IsPageWritable(uint32_t protect) {
1110b9c1b51eSKate Stone   return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY |
1111b9c1b51eSKate Stone                      PAGE_READWRITE | PAGE_WRITECOPY)) != 0;
11120c35cde9SAdrian McCarthy }
11130c35cde9SAdrian McCarthy 
1114b9c1b51eSKate Stone bool ProcessWindows::IsPageExecutable(uint32_t protect) {
1115b9c1b51eSKate Stone   return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
1116b9c1b51eSKate Stone                      PAGE_EXECUTE_WRITECOPY)) != 0;
11170c35cde9SAdrian McCarthy }
11184ad5def9SAdrian McCarthy 
11194ad5def9SAdrian McCarthy } // namespace lldb_private
1120