1 //===-- HostProcessWindows.cpp ----------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Host/FileSpec.h"
11 #include "lldb/Host/HostThread.h"
12 #include "lldb/Host/ThreadLauncher.h"
13 #include "lldb/Host/windows/windows.h"
14 #include "lldb/Host/windows/HostProcessWindows.h"
15 
16 #include "llvm/ADT/STLExtras.h"
17 
18 #include <Psapi.h>
19 
20 using namespace lldb_private;
21 
22 namespace
23 {
24 struct MonitorInfo
25 {
26     HostProcess::MonitorCallback callback;
27     void *baton;
28     HANDLE process_handle;
29 };
30 }
31 
32 HostProcessWindows::HostProcessWindows()
33     : HostNativeProcessBase()
34 {
35 }
36 
37 HostProcessWindows::HostProcessWindows(lldb::process_t process)
38     : HostNativeProcessBase(process)
39 {
40 }
41 
42 HostProcessWindows::~HostProcessWindows()
43 {
44     Close();
45 }
46 
47 Error HostProcessWindows::Terminate()
48 {
49     Error error;
50     if (m_process == nullptr)
51         error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
52 
53     if (!::TerminateProcess(m_process, 0))
54         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
55 
56     return error;
57 }
58 
59 Error HostProcessWindows::GetMainModule(FileSpec &file_spec) const
60 {
61     Error error;
62     if (m_process == nullptr)
63         error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
64 
65     char path[MAX_PATH] = { 0 };
66     if (::GetProcessImageFileName(m_process, path, llvm::array_lengthof(path)))
67         file_spec.SetFile(path, false);
68     else
69         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
70 
71     return error;
72 }
73 
74 lldb::pid_t HostProcessWindows::GetProcessId() const
75 {
76     return (m_process == LLDB_INVALID_PROCESS) ? -1 : ::GetProcessId(m_process);
77 }
78 
79 bool HostProcessWindows::IsRunning() const
80 {
81     if (m_process == nullptr)
82         return false;
83 
84     DWORD code = 0;
85     if (!::GetExitCodeProcess(m_process, &code))
86         return false;
87 
88     return (code == STILL_ACTIVE);
89 }
90 
91 HostThread
92 HostProcessWindows::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals)
93 {
94     HostThread monitor_thread;
95     MonitorInfo *info = new MonitorInfo;
96     info->callback = callback;
97     info->baton = callback_baton;
98 
99     // Since the life of this HostProcessWindows instance and the life of the process may be different, duplicate the handle so that
100     // the monitor thread can have ownership over its own copy of the handle.
101     HostThread result;
102     if (::DuplicateHandle(GetCurrentProcess(), m_process, GetCurrentProcess(), &info->process_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
103         result = ThreadLauncher::LaunchThread("ChildProcessMonitor", HostProcessWindows::MonitorThread, info, nullptr);
104     return result;
105 }
106 
107 lldb::thread_result_t
108 HostProcessWindows::MonitorThread(void *thread_arg)
109 {
110     DWORD exit_code;
111 
112     MonitorInfo *info = static_cast<MonitorInfo *>(thread_arg);
113     if (info)
114     {
115         DWORD wait_result = ::WaitForSingleObject(info->process_handle, INFINITE);
116         ::GetExitCodeProcess(info->process_handle, &exit_code);
117         info->callback(info->baton, ::GetProcessId(info->process_handle), true, 0, exit_code);
118 
119         delete (info);
120     }
121     return 0;
122 }
123 
124 void HostProcessWindows::Close()
125 {
126     if (m_process != LLDB_INVALID_PROCESS)
127         ::CloseHandle(m_process);
128     m_process = nullptr;
129 }
130