]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Host/windows/Host.cpp
Vendor import of lldb trunk r256945:
[FreeBSD/FreeBSD.git] / source / Host / windows / Host.cpp
1 //===-- source/Host/windows/Host.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 // C Includes
11 #include <stdio.h>
12 #include "lldb/Host/windows/windows.h"
13 #include "lldb/Host/windows/AutoHandle.h"
14
15 // C++ Includes
16 // Other libraries and framework includes
17 // Project includes
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Target/Process.h"
21
22 #include "lldb/Host/Host.h"
23 #include "lldb/Host/HostInfo.h"
24 #include "lldb/Core/DataBufferHeap.h"
25 #include "lldb/Core/DataExtractor.h"
26 #include "lldb/Core/StreamFile.h"
27 #include "lldb/Core/StructuredData.h"
28
29 // Windows includes
30 #include <TlHelp32.h>
31
32 using namespace lldb;
33 using namespace lldb_private;
34
35 namespace
36 {
37     bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
38     {
39         // Open the PE File as a binary file, and parse just enough information to determine the
40         // machine type.
41         File imageBinary(
42             executable.GetPath().c_str(),
43             File::eOpenOptionRead,
44             lldb::eFilePermissionsUserRead);
45         imageBinary.SeekFromStart(0x3c);
46         int32_t peOffset = 0;
47         uint32_t peHead = 0;
48         uint16_t machineType = 0;
49         size_t readSize = sizeof(peOffset);
50         imageBinary.Read(&peOffset, readSize);
51         imageBinary.SeekFromStart(peOffset);
52         imageBinary.Read(&peHead, readSize);
53         if (peHead != 0x00004550) // "PE\0\0", little-endian
54             return false;       // Error: Can't find PE header
55         readSize = 2;
56         imageBinary.Read(&machineType, readSize);
57         triple.setVendor(llvm::Triple::PC);
58         triple.setOS(llvm::Triple::Win32);
59         triple.setArch(llvm::Triple::UnknownArch);
60         if (machineType == 0x8664)
61             triple.setArch(llvm::Triple::x86_64);
62         else if (machineType == 0x14c)
63             triple.setArch(llvm::Triple::x86);
64
65         return true;
66     }
67
68     bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
69     {
70         // Get the process image path.  MAX_PATH isn't long enough, paths can actually be up to 32KB.
71         std::vector<char> buffer(32768);
72         DWORD dwSize = buffer.size();
73         if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize))
74             return false;
75         path.assign(&buffer[0]);
76         return true;
77     }
78
79     void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
80     {
81         // We may not have permissions to read the path from the process.  So start off by
82         // setting the executable file to whatever Toolhelp32 gives us, and then try to
83         // enhance this with more detailed information, but fail gracefully.
84         std::string executable;
85         llvm::Triple triple;
86         triple.setVendor(llvm::Triple::PC);
87         triple.setOS(llvm::Triple::Win32);
88         triple.setArch(llvm::Triple::UnknownArch);
89         if (GetExecutableForProcess(handle, executable))
90         {
91             FileSpec executableFile(executable.c_str(), false);
92             process.SetExecutableFile(executableFile, true);
93             GetTripleForProcess(executableFile, triple);
94         }
95         process.SetArchitecture(ArchSpec(triple));
96
97         // TODO(zturner): Add the ability to get the process user name.
98     }
99 }
100
101 lldb::DataBufferSP
102 Host::GetAuxvData(lldb_private::Process *process)
103 {
104     return 0;
105 }
106
107 lldb::tid_t
108 Host::GetCurrentThreadID()
109 {
110     return lldb::tid_t(::GetCurrentThreadId());
111 }
112
113 lldb::thread_t
114 Host::GetCurrentThread ()
115 {
116     return lldb::thread_t(::GetCurrentThread());
117 }
118
119 lldb::thread_key_t
120 Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
121 {
122     return TlsAlloc();
123 }
124
125 void*
126 Host::ThreadLocalStorageGet(lldb::thread_key_t key)
127 {
128     return ::TlsGetValue (key);
129 }
130
131 void
132 Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
133 {
134    ::TlsSetValue (key, value);
135 }
136
137 void
138 Host::Kill(lldb::pid_t pid, int signo)
139 {
140     TerminateProcess((HANDLE) pid, 1);
141 }
142
143
144 const char *
145 Host::GetSignalAsCString(int signo)
146 {
147     return NULL;
148 }
149
150 FileSpec
151 Host::GetModuleFileSpecForHostAddress (const void *host_addr)
152 {
153     FileSpec module_filespec;
154
155     HMODULE hmodule = NULL;
156     if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
157         return module_filespec;
158
159     std::vector<char> buffer(MAX_PATH);
160     DWORD chars_copied = 0;
161     do {
162         chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size());
163         if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
164             buffer.resize(buffer.size() * 2);
165     } while (chars_copied >= buffer.size());
166
167     module_filespec.SetFile(&buffer[0], false);
168     return module_filespec;
169 }
170
171 uint32_t
172 Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
173 {
174     process_infos.Clear();
175
176     AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
177     if (!snapshot.IsValid())
178         return 0;
179
180     PROCESSENTRY32 pe = {0};
181     pe.dwSize = sizeof(PROCESSENTRY32);
182     if (Process32First(snapshot.get(), &pe))
183     {
184         do
185         {
186             AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
187
188             ProcessInstanceInfo process;
189             process.SetExecutableFile(FileSpec(pe.szExeFile, false), true);
190             process.SetProcessID(pe.th32ProcessID);
191             process.SetParentProcessID(pe.th32ParentProcessID);
192             GetProcessExecutableAndTriple(handle, process);
193
194             if (match_info.MatchAllProcesses() || match_info.Matches(process))
195                 process_infos.Append(process);
196         } while (Process32Next(snapshot.get(), &pe));
197     }
198     return process_infos.GetSize();
199 }
200
201 bool
202 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
203 {
204     process_info.Clear();
205
206     AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
207                       nullptr);
208     if (!handle.IsValid())
209         return false;
210     
211     process_info.SetProcessID(pid);
212     GetProcessExecutableAndTriple(handle, process_info);
213
214     // Need to read the PEB to get parent process and command line arguments.
215     return true;
216 }
217
218 HostThread
219 Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
220 {
221     return HostThread();
222 }
223
224 Error
225 Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
226 {
227     Error error;
228     if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
229     {
230         FileSpec expand_tool_spec;
231         if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
232         {
233             error.SetErrorString("could not find support executable directory for the lldb-argdumper tool");
234             return error;
235         }
236         expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
237         if (!expand_tool_spec.Exists())
238         {
239             error.SetErrorString("could not find the lldb-argdumper tool");
240             return error;
241         }
242         
243         std::string quoted_cmd_string;
244         launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
245         std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
246         StreamString expand_command;
247         
248         expand_command.Printf("\"%s\" %s",
249                               expand_tool_spec.GetPath().c_str(),
250                               quoted_cmd_string.c_str());
251         
252         int status;
253         std::string output;
254         RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
255         
256         if (status != 0)
257         {
258             error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
259             return error;
260         }
261         
262         auto data_sp = StructuredData::ParseJSON(output);
263         if (!data_sp)
264         {
265             error.SetErrorString("invalid JSON");
266             return error;
267         }
268         
269         auto dict_sp = data_sp->GetAsDictionary();
270         if (!data_sp)
271         {
272             error.SetErrorString("invalid JSON");
273             return error;
274         }
275         
276         auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
277         if (!args_sp)
278         {
279             error.SetErrorString("invalid JSON");
280             return error;
281         }
282         
283         auto args_array_sp = args_sp->GetAsArray();
284         if (!args_array_sp)
285         {
286             error.SetErrorString("invalid JSON");
287             return error;
288         }
289         
290         launch_info.GetArguments().Clear();
291         
292         for (size_t i = 0;
293              i < args_array_sp->GetSize();
294              i++)
295         {
296             auto item_sp = args_array_sp->GetItemAtIndex(i);
297             if (!item_sp)
298                 continue;
299             auto str_sp = item_sp->GetAsString();
300             if (!str_sp)
301                 continue;
302             
303             launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
304         }
305     }
306     
307     return error;
308 }
309
310 size_t
311 Host::GetEnvironment(StringList &env)
312 {
313     // The environment block on Windows is a contiguous buffer of NULL terminated strings,
314     // where the end of the environment block is indicated by two consecutive NULLs.
315     LPCH environment_block = ::GetEnvironmentStrings();
316     env.Clear();
317     while (*environment_block != '\0')
318     {
319         llvm::StringRef current_var(environment_block);
320         if (current_var[0] != '=')
321             env.AppendString(current_var);
322
323         environment_block += current_var.size()+1;
324     }
325     return env.GetSize();
326 }