forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			147 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "lldb/Host/HostProcess.h"
 | |
| #include "lldb/Host/windows/ProcessLauncherWindows.h"
 | |
| #include "lldb/Target/ProcessLaunchInfo.h"
 | |
| 
 | |
| #include "llvm/ADT/SmallVector.h"
 | |
| #include "llvm/Support/ConvertUTF.h"
 | |
| 
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| 
 | |
| namespace
 | |
| {
 | |
| void
 | |
| CreateEnvironmentBuffer(const Args &env, std::vector<char> &buffer)
 | |
| {
 | |
|     if (env.GetArgumentCount() == 0)
 | |
|         return;
 | |
| 
 | |
|     // Environment buffer is a null terminated list of null terminated strings
 | |
|     for (int i = 0; i < env.GetArgumentCount(); ++i)
 | |
|     {
 | |
|         std::wstring warg;
 | |
|         if (llvm::ConvertUTF8toWide(env.GetArgumentAtIndex(i), warg))
 | |
|         {
 | |
|             buffer.insert(buffer.end(), (char *)warg.c_str(), (char *)(warg.c_str() + warg.size() + 1));
 | |
|         }
 | |
|     }
 | |
|     // One null wchar_t (to end the block) is two null bytes
 | |
|     buffer.push_back(0);
 | |
|     buffer.push_back(0);
 | |
| }
 | |
| }
 | |
| 
 | |
| HostProcess
 | |
| ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
 | |
| {
 | |
|     error.Clear();
 | |
| 
 | |
|     std::string executable;
 | |
|     std::string commandLine;
 | |
|     std::vector<char> environment;
 | |
|     STARTUPINFO startupinfo = {0};
 | |
|     PROCESS_INFORMATION pi = {0};
 | |
| 
 | |
|     HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
 | |
|     HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO);
 | |
|     HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO);
 | |
| 
 | |
|     startupinfo.cb = sizeof(startupinfo);
 | |
|     startupinfo.dwFlags |= STARTF_USESTDHANDLES;
 | |
|     startupinfo.hStdError  = stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE);
 | |
|     startupinfo.hStdInput  = stdin_handle  ? stdin_handle  : ::GetStdHandle(STD_INPUT_HANDLE);
 | |
|     startupinfo.hStdOutput = stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE);
 | |
| 
 | |
|     const char *hide_console_var = getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
 | |
|     if (hide_console_var && llvm::StringRef(hide_console_var).equals_lower("true"))
 | |
|     {
 | |
|         startupinfo.dwFlags |= STARTF_USESHOWWINDOW;
 | |
|         startupinfo.wShowWindow = SW_HIDE;
 | |
|     }
 | |
| 
 | |
|     DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
 | |
|     if (launch_info.GetFlags().Test(eLaunchFlagDebug))
 | |
|         flags |= DEBUG_ONLY_THIS_PROCESS;
 | |
| 
 | |
|     auto &env = const_cast<Args &>(launch_info.GetEnvironmentEntries());
 | |
|     LPVOID env_block = nullptr;
 | |
|     ::CreateEnvironmentBuffer(env, environment);
 | |
|     if (!environment.empty())
 | |
|         env_block = environment.data();
 | |
| 
 | |
|     executable = launch_info.GetExecutableFile().GetPath();
 | |
|     launch_info.GetArguments().GetQuotedCommandString(commandLine);
 | |
| 
 | |
|     std::wstring wexecutable, wcommandLine, wworkingDirectory;
 | |
|     llvm::ConvertUTF8toWide(executable, wexecutable);
 | |
|     llvm::ConvertUTF8toWide(commandLine, wcommandLine);
 | |
|     llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), wworkingDirectory);
 | |
| 
 | |
|     wcommandLine.resize(PATH_MAX); // Needs to be over-allocated because CreateProcessW can modify it
 | |
|     BOOL result = ::CreateProcessW(wexecutable.c_str(), &wcommandLine[0], NULL, NULL, TRUE, flags, env_block,
 | |
|                                    wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(), &startupinfo, &pi);
 | |
|     if (result)
 | |
|     {
 | |
|         // Do not call CloseHandle on pi.hProcess, since we want to pass that back through the HostProcess.
 | |
|         ::CloseHandle(pi.hThread);
 | |
|     }
 | |
| 
 | |
|     if (stdin_handle)
 | |
|         ::CloseHandle(stdin_handle);
 | |
|     if (stdout_handle)
 | |
|         ::CloseHandle(stdout_handle);
 | |
|     if (stderr_handle)
 | |
|         ::CloseHandle(stderr_handle);
 | |
| 
 | |
|     if (!result)
 | |
|         error.SetError(::GetLastError(), eErrorTypeWin32);
 | |
|     return HostProcess(pi.hProcess);
 | |
| }
 | |
| 
 | |
| HANDLE
 | |
| ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd)
 | |
| {
 | |
|     const FileAction *action = launch_info.GetFileActionForFD(fd);
 | |
|     if (action == nullptr)
 | |
|         return NULL;
 | |
|     SECURITY_ATTRIBUTES secattr = {0};
 | |
|     secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
 | |
|     secattr.bInheritHandle = TRUE;
 | |
| 
 | |
|     const char *path = action->GetPath();
 | |
|     DWORD access = 0;
 | |
|     DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
 | |
|     DWORD create = 0;
 | |
|     DWORD flags = 0;
 | |
|     if (fd == STDIN_FILENO)
 | |
|     {
 | |
|         access = GENERIC_READ;
 | |
|         create = OPEN_EXISTING;
 | |
|         flags = FILE_ATTRIBUTE_READONLY;
 | |
|     }
 | |
|     if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
 | |
|     {
 | |
|         access = GENERIC_WRITE;
 | |
|         create = CREATE_ALWAYS;
 | |
|         if (fd == STDERR_FILENO)
 | |
|             flags = FILE_FLAG_WRITE_THROUGH;
 | |
|     }
 | |
| 
 | |
|     std::wstring wpath;
 | |
|     llvm::ConvertUTF8toWide(path, wpath);
 | |
|     HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create, flags, NULL);
 | |
|     return (result == INVALID_HANDLE_VALUE) ? NULL : result;
 | |
| }
 |