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 #include "llvm/Support/ConvertUTF.h"
18 
19 #include <Psapi.h>
20 
21 using namespace lldb_private;
22 
23 namespace
24 {
25 struct MonitorInfo
26 {
27     HostProcess::MonitorCallback callback;
28     void *baton;
29     HANDLE process_handle;
30 };
31 }
32 
33 HostProcessWindows::HostProcessWindows()
34     : HostNativeProcessBase()
35     , m_owns_handle(true)
36 {
37 }
38 
39 HostProcessWindows::HostProcessWindows(lldb::process_t process)
40     : HostNativeProcessBase(process)
41     , m_owns_handle(true)
42 {
43 }
44 
45 HostProcessWindows::~HostProcessWindows()
46 {
47     Close();
48 }
49 
50 void
51 HostProcessWindows::SetOwnsHandle(bool owns)
52 {
53     m_owns_handle = owns;
54 }
55 
56 Error HostProcessWindows::Terminate()
57 {
58     Error error;
59     if (m_process == nullptr)
60         error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
61 
62     if (!::TerminateProcess(m_process, 0))
63         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
64 
65     return error;
66 }
67 
68 Error HostProcessWindows::GetMainModule(FileSpec &file_spec) const
69 {
70     Error error;
71     if (m_process == nullptr)
72         error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
73 
74     std::vector<wchar_t> wpath(PATH_MAX);
75     if (::GetProcessImageFileNameW(m_process, wpath.data(), wpath.size()))
76     {
77         std::string path;
78         if (llvm::convertWideToUTF8(wpath.data(), path))
79             file_spec.SetFile(path, false);
80         else
81             error.SetErrorString("Error converting path to UTF-8");
82     }
83     else
84         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
85 
86     return error;
87 }
88 
89 lldb::pid_t HostProcessWindows::GetProcessId() const
90 {
91     return (m_process == LLDB_INVALID_PROCESS) ? -1 : ::GetProcessId(m_process);
92 }
93 
94 bool HostProcessWindows::IsRunning() const
95 {
96     if (m_process == nullptr)
97         return false;
98 
99     DWORD code = 0;
100     if (!::GetExitCodeProcess(m_process, &code))
101         return false;
102 
103     return (code == STILL_ACTIVE);
104 }
105 
106 HostThread
107 HostProcessWindows::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals)
108 {
109     HostThread monitor_thread;
110     MonitorInfo *info = new MonitorInfo;
111     info->callback = callback;
112     info->baton = callback_baton;
113 
114     // Since the life of this HostProcessWindows instance and the life of the process may be different, duplicate the handle so that
115     // the monitor thread can have ownership over its own copy of the handle.
116     HostThread result;
117     if (::DuplicateHandle(GetCurrentProcess(), m_process, GetCurrentProcess(), &info->process_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
118         result = ThreadLauncher::LaunchThread("ChildProcessMonitor", HostProcessWindows::MonitorThread, info, nullptr);
119     return result;
120 }
121 
122 lldb::thread_result_t
123 HostProcessWindows::MonitorThread(void *thread_arg)
124 {
125     DWORD exit_code;
126 
127     MonitorInfo *info = static_cast<MonitorInfo *>(thread_arg);
128     if (info)
129     {
130         ::WaitForSingleObject(info->process_handle, INFINITE);
131         ::GetExitCodeProcess(info->process_handle, &exit_code);
132         info->callback(info->baton, ::GetProcessId(info->process_handle), true, 0, exit_code);
133         ::CloseHandle(info->process_handle);
134         delete (info);
135     }
136     return 0;
137 }
138 
139 void HostProcessWindows::Close()
140 {
141     if (m_owns_handle && m_process != LLDB_INVALID_PROCESS)
142         ::CloseHandle(m_process);
143     m_process = nullptr;
144 }
145