12c77eefeSRaphael Isemann//===-- Host.mm -------------------------------------------------*- C++ -*-===// 22c77eefeSRaphael Isemann// 32946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62c77eefeSRaphael Isemann// 72c77eefeSRaphael Isemann//===----------------------------------------------------------------------===// 82c77eefeSRaphael Isemann 92c77eefeSRaphael Isemann#include "lldb/Host/Host.h" 10041c7b84SJonas Devlieghere#include "PosixSpawnResponsible.h" 112c77eefeSRaphael Isemann 122c77eefeSRaphael Isemann#include <AvailabilityMacros.h> 13f203100eSVedant Kumar#include <TargetConditionals.h> 142c77eefeSRaphael Isemann 15f203100eSVedant Kumar#if TARGET_OS_OSX 162c77eefeSRaphael Isemann#define __XPC_PRIVATE_H__ 172c77eefeSRaphael Isemann#include <xpc/xpc.h> 182c77eefeSRaphael Isemann 192c77eefeSRaphael Isemann#define LaunchUsingXPCRightName "com.apple.lldb.RootDebuggingXPCService" 202c77eefeSRaphael Isemann 212c77eefeSRaphael Isemann// These XPC messaging keys are used for communication between Host.mm and the 222c77eefeSRaphael Isemann// XPC service. 232c77eefeSRaphael Isemann#define LauncherXPCServiceAuthKey "auth-key" 242c77eefeSRaphael Isemann#define LauncherXPCServiceArgPrefxKey "arg" 252c77eefeSRaphael Isemann#define LauncherXPCServiceEnvPrefxKey "env" 262c77eefeSRaphael Isemann#define LauncherXPCServiceCPUTypeKey "cpuType" 272c77eefeSRaphael Isemann#define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags" 282c77eefeSRaphael Isemann#define LauncherXPCServiceStdInPathKeyKey "stdInPath" 292c77eefeSRaphael Isemann#define LauncherXPCServiceStdOutPathKeyKey "stdOutPath" 302c77eefeSRaphael Isemann#define LauncherXPCServiceStdErrPathKeyKey "stdErrPath" 312c77eefeSRaphael Isemann#define LauncherXPCServiceChildPIDKey "childPID" 322c77eefeSRaphael Isemann#define LauncherXPCServiceErrorTypeKey "errorType" 332c77eefeSRaphael Isemann#define LauncherXPCServiceCodeTypeKey "errorCode" 342c77eefeSRaphael Isemann 35b945b62cSJonas Devlieghere#include <bsm/audit.h> 36b945b62cSJonas Devlieghere#include <bsm/audit_session.h> 372c77eefeSRaphael Isemann#endif 382c77eefeSRaphael Isemann 39d768bf99SArchibald Elliott#include "llvm/TargetParser/Host.h" 402c77eefeSRaphael Isemann 412c77eefeSRaphael Isemann#include <asl.h> 422c77eefeSRaphael Isemann#include <crt_externs.h> 4376e47d48SRaphael Isemann#include <cstdio> 4476e47d48SRaphael Isemann#include <cstdlib> 4598e50a7dSJonas Devlieghere#include <dlfcn.h> 462c77eefeSRaphael Isemann#include <grp.h> 472c77eefeSRaphael Isemann#include <libproc.h> 482c77eefeSRaphael Isemann#include <pwd.h> 492c77eefeSRaphael Isemann#include <spawn.h> 502c77eefeSRaphael Isemann#include <sys/proc.h> 512c77eefeSRaphael Isemann#include <sys/stat.h> 522c77eefeSRaphael Isemann#include <sys/sysctl.h> 532c77eefeSRaphael Isemann#include <sys/types.h> 542c77eefeSRaphael Isemann#include <unistd.h> 552c77eefeSRaphael Isemann 562c77eefeSRaphael Isemann#include "lldb/Host/ConnectionFileDescriptor.h" 572c22c800SJonas Devlieghere#include "lldb/Host/FileSystem.h" 582c77eefeSRaphael Isemann#include "lldb/Host/HostInfo.h" 59eef758e9SPavel Labath#include "lldb/Host/ProcessLaunchInfo.h" 602c77eefeSRaphael Isemann#include "lldb/Host/ThreadLauncher.h" 612c77eefeSRaphael Isemann#include "lldb/Utility/ArchSpec.h" 62c34698a8SPavel Labath#include "lldb/Utility/LLDBLog.h" 632c77eefeSRaphael Isemann#include "lldb/Utility/DataBufferHeap.h" 642c77eefeSRaphael Isemann#include "lldb/Utility/DataExtractor.h" 652c77eefeSRaphael Isemann#include "lldb/Utility/Endian.h" 662c77eefeSRaphael Isemann#include "lldb/Utility/FileSpec.h" 672c77eefeSRaphael Isemann#include "lldb/Utility/Log.h" 682c77eefeSRaphael Isemann#include "lldb/Utility/NameMatches.h" 69805e7106SZachary Turner#include "lldb/Utility/ProcessInfo.h" 702c77eefeSRaphael Isemann#include "lldb/Utility/StreamString.h" 712c77eefeSRaphael Isemann#include "lldb/Utility/StructuredData.h" 722c77eefeSRaphael Isemann#include "lldb/lldb-defines.h" 732c77eefeSRaphael Isemann 74e0ea8d87SJonas Devlieghere#include "llvm/ADT/ScopeExit.h" 752c77eefeSRaphael Isemann#include "llvm/Support/Errno.h" 76e0ea8d87SJonas Devlieghere#include "llvm/Support/FileSystem.h" 772c77eefeSRaphael Isemann 7807570f55SJason Molenda#include "../cfcpp/CFCBundle.h" 7907570f55SJason Molenda#include "../cfcpp/CFCMutableArray.h" 8007570f55SJason Molenda#include "../cfcpp/CFCMutableDictionary.h" 8107570f55SJason Molenda#include "../cfcpp/CFCReleaser.h" 8207570f55SJason Molenda#include "../cfcpp/CFCString.h" 832c77eefeSRaphael Isemann 842c77eefeSRaphael Isemann#include <objc/objc-auto.h> 851e5d5261SJonas Devlieghere#include <os/log.h> 862c77eefeSRaphael Isemann 872c77eefeSRaphael Isemann#include <CoreFoundation/CoreFoundation.h> 882c77eefeSRaphael Isemann#include <Foundation/Foundation.h> 892c77eefeSRaphael Isemann 902c77eefeSRaphael Isemann#ifndef _POSIX_SPAWN_DISABLE_ASLR 912c77eefeSRaphael Isemann#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 922c77eefeSRaphael Isemann#endif 932c77eefeSRaphael Isemann 942c77eefeSRaphael Isemannextern "C" { 952c77eefeSRaphael Isemannint __pthread_chdir(const char *path); 962c77eefeSRaphael Isemannint __pthread_fchdir(int fildes); 972c77eefeSRaphael Isemann} 982c77eefeSRaphael Isemann 992c77eefeSRaphael Isemannusing namespace lldb; 1002c77eefeSRaphael Isemannusing namespace lldb_private; 1012c77eefeSRaphael Isemann 1021e5d5261SJonas Devliegherestatic os_log_t g_os_log; 1031e5d5261SJonas Devliegherestatic std::once_flag g_os_log_once; 1041e5d5261SJonas Devlieghere 105528f5ba7SJonas Devliegherevoid Host::SystemLog(Severity severity, llvm::StringRef message) { 1061e5d5261SJonas Devlieghere if (__builtin_available(macos 10.12, iOS 10, tvOS 10, watchOS 3, *)) { 1071e5d5261SJonas Devlieghere std::call_once(g_os_log_once, []() { 1081e5d5261SJonas Devlieghere g_os_log = os_log_create("com.apple.dt.lldb", "lldb"); 1091e5d5261SJonas Devlieghere }); 110528f5ba7SJonas Devlieghere switch (severity) { 111528f5ba7SJonas Devlieghere case lldb::eSeverityInfo: 112528f5ba7SJonas Devlieghere case lldb::eSeverityWarning: 1131e5d5261SJonas Devlieghere os_log(g_os_log, "%{public}s", message.str().c_str()); 114a7e9e3ebSJonas Devlieghere break; 115528f5ba7SJonas Devlieghere case lldb::eSeverityError: 116a7e9e3ebSJonas Devlieghere os_log_error(g_os_log, "%{public}s", message.str().c_str()); 117a7e9e3ebSJonas Devlieghere break; 118a7e9e3ebSJonas Devlieghere } 1191e5d5261SJonas Devlieghere } else { 1201e5d5261SJonas Devlieghere llvm::errs() << message; 1211e5d5261SJonas Devlieghere } 1221e5d5261SJonas Devlieghere} 1231e5d5261SJonas Devlieghere 1242c77eefeSRaphael Isemannbool Host::GetBundleDirectory(const FileSpec &file, 1252c77eefeSRaphael Isemann FileSpec &bundle_directory) { 1262c77eefeSRaphael Isemann#if defined(__APPLE__) 1273a58d898SJonas Devlieghere if (FileSystem::Instance().IsDirectory(file)) { 1282c77eefeSRaphael Isemann char path[PATH_MAX]; 1292c77eefeSRaphael Isemann if (file.GetPath(path, sizeof(path))) { 1302c77eefeSRaphael Isemann CFCBundle bundle(path); 1312c77eefeSRaphael Isemann if (bundle.GetPath(path, sizeof(path))) { 1328f3be7a3SJonas Devlieghere bundle_directory.SetFile(path, FileSpec::Style::native); 1332c77eefeSRaphael Isemann return true; 1342c77eefeSRaphael Isemann } 1352c77eefeSRaphael Isemann } 1362c77eefeSRaphael Isemann } 1372c77eefeSRaphael Isemann#endif 1382c77eefeSRaphael Isemann bundle_directory.Clear(); 1392c77eefeSRaphael Isemann return false; 1402c77eefeSRaphael Isemann} 1412c77eefeSRaphael Isemann 1422c77eefeSRaphael Isemannbool Host::ResolveExecutableInBundle(FileSpec &file) { 1432c77eefeSRaphael Isemann#if defined(__APPLE__) 1443a58d898SJonas Devlieghere if (FileSystem::Instance().IsDirectory(file)) { 1452c77eefeSRaphael Isemann char path[PATH_MAX]; 1462c77eefeSRaphael Isemann if (file.GetPath(path, sizeof(path))) { 1472c77eefeSRaphael Isemann CFCBundle bundle(path); 1482c77eefeSRaphael Isemann CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL()); 1492c77eefeSRaphael Isemann if (url.get()) { 1502c77eefeSRaphael Isemann if (::CFURLGetFileSystemRepresentation(url.get(), YES, (UInt8 *)path, 1512c77eefeSRaphael Isemann sizeof(path))) { 1528f3be7a3SJonas Devlieghere file.SetFile(path, FileSpec::Style::native); 1532c77eefeSRaphael Isemann return true; 1542c77eefeSRaphael Isemann } 1552c77eefeSRaphael Isemann } 1562c77eefeSRaphael Isemann } 1572c77eefeSRaphael Isemann } 1582c77eefeSRaphael Isemann#endif 1592c77eefeSRaphael Isemann return false; 1602c77eefeSRaphael Isemann} 1612c77eefeSRaphael Isemann 162f203100eSVedant Kumar#if TARGET_OS_OSX 163f203100eSVedant Kumar 164d0810779SPavel Labathstatic void *AcceptPIDFromInferior(const char *connect_url) { 1652c77eefeSRaphael Isemann ConnectionFileDescriptor file_conn; 1662c77eefeSRaphael Isemann Status error; 1672c77eefeSRaphael Isemann if (file_conn.Connect(connect_url, &error) == eConnectionStatusSuccess) { 1682c77eefeSRaphael Isemann char pid_str[256]; 1692c77eefeSRaphael Isemann ::memset(pid_str, 0, sizeof(pid_str)); 1702c77eefeSRaphael Isemann ConnectionStatus status; 1712c77eefeSRaphael Isemann const size_t pid_str_len = file_conn.Read( 1722c77eefeSRaphael Isemann pid_str, sizeof(pid_str), std::chrono::seconds(0), status, NULL); 1732c77eefeSRaphael Isemann if (pid_str_len > 0) { 1742c77eefeSRaphael Isemann int pid = atoi(pid_str); 1752c77eefeSRaphael Isemann return (void *)(intptr_t)pid; 1762c77eefeSRaphael Isemann } 1772c77eefeSRaphael Isemann } 1782c77eefeSRaphael Isemann return NULL; 1792c77eefeSRaphael Isemann} 1802c77eefeSRaphael Isemann 1812c77eefeSRaphael Isemannconst char *applscript_in_new_tty = "tell application \"Terminal\"\n" 1822c77eefeSRaphael Isemann " activate\n" 1832c77eefeSRaphael Isemann " do script \"/bin/bash -c '%s';exit\"\n" 1842c77eefeSRaphael Isemann "end tell\n"; 1852c77eefeSRaphael Isemann 1862c77eefeSRaphael Isemannconst char *applscript_in_existing_tty = "\ 1872c77eefeSRaphael Isemannset the_shell_script to \"/bin/bash -c '%s';exit\"\n\ 1882c77eefeSRaphael Isemanntell application \"Terminal\"\n\ 1892c77eefeSRaphael Isemann repeat with the_window in (get windows)\n\ 1902c77eefeSRaphael Isemann repeat with the_tab in tabs of the_window\n\ 1912c77eefeSRaphael Isemann set the_tty to tty in the_tab\n\ 1922c77eefeSRaphael Isemann if the_tty contains \"%s\" then\n\ 1932c77eefeSRaphael Isemann if the_tab is not busy then\n\ 1942c77eefeSRaphael Isemann set selected of the_tab to true\n\ 1952c77eefeSRaphael Isemann set frontmost of the_window to true\n\ 1962c77eefeSRaphael Isemann do script the_shell_script in the_tab\n\ 1972c77eefeSRaphael Isemann return\n\ 1982c77eefeSRaphael Isemann end if\n\ 1992c77eefeSRaphael Isemann end if\n\ 2002c77eefeSRaphael Isemann end repeat\n\ 2012c77eefeSRaphael Isemann end repeat\n\ 2022c77eefeSRaphael Isemann do script the_shell_script\n\ 2032c77eefeSRaphael Isemannend tell\n"; 2042c77eefeSRaphael Isemann 2052c77eefeSRaphael Isemannstatic Status 2062c77eefeSRaphael IsemannLaunchInNewTerminalWithAppleScript(const char *exe_path, 2072c77eefeSRaphael Isemann ProcessLaunchInfo &launch_info) { 2082c77eefeSRaphael Isemann Status error; 2092c77eefeSRaphael Isemann char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX"; 2102c77eefeSRaphael Isemann if (::mktemp(unix_socket_name) == NULL) { 2110642cd76SAdrian Prantl error = Status::FromErrorString( 2120642cd76SAdrian Prantl "failed to make temporary path for a unix socket"); 2132c77eefeSRaphael Isemann return error; 2142c77eefeSRaphael Isemann } 2152c77eefeSRaphael Isemann 2162c77eefeSRaphael Isemann StreamString command; 21760f028ffSPavel Labath FileSpec darwin_debug_file_spec = HostInfo::GetSupportExeDir(); 21860f028ffSPavel Labath if (!darwin_debug_file_spec) { 2190642cd76SAdrian Prantl error = 2200642cd76SAdrian Prantl Status::FromErrorString("can't locate the 'darwin-debug' executable"); 2212c77eefeSRaphael Isemann return error; 2222c77eefeSRaphael Isemann } 2232c77eefeSRaphael Isemann 224529a3d87SGreg Clayton darwin_debug_file_spec.SetFilename("darwin-debug"); 2252c77eefeSRaphael Isemann 226dbd7fabaSJonas Devlieghere if (!FileSystem::Instance().Exists(darwin_debug_file_spec)) { 2270642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 2282c77eefeSRaphael Isemann "the 'darwin-debug' executable doesn't exists at '%s'", 2292c77eefeSRaphael Isemann darwin_debug_file_spec.GetPath().c_str()); 2302c77eefeSRaphael Isemann return error; 2312c77eefeSRaphael Isemann } 2322c77eefeSRaphael Isemann 2332c77eefeSRaphael Isemann char launcher_path[PATH_MAX]; 2342c77eefeSRaphael Isemann darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path)); 2352c77eefeSRaphael Isemann 2362c77eefeSRaphael Isemann const ArchSpec &arch_spec = launch_info.GetArchitecture(); 2372c77eefeSRaphael Isemann // Only set the architecture if it is valid and if it isn't Haswell (x86_64h). 2382c77eefeSRaphael Isemann if (arch_spec.IsValid() && 2392c77eefeSRaphael Isemann arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h) 2402c77eefeSRaphael Isemann command.Printf("arch -arch %s ", arch_spec.GetArchitectureName()); 2412c77eefeSRaphael Isemann 2425205c177SJonas Devlieghere command.Printf(R"(\"%s\" --unix-socket=%s)", launcher_path, unix_socket_name); 2432c77eefeSRaphael Isemann 2442c77eefeSRaphael Isemann if (arch_spec.IsValid()) 2452c77eefeSRaphael Isemann command.Printf(" --arch=%s", arch_spec.GetArchitectureName()); 2462c77eefeSRaphael Isemann 2472c77eefeSRaphael Isemann FileSpec working_dir{launch_info.GetWorkingDirectory()}; 2482c77eefeSRaphael Isemann if (working_dir) 249529a3d87SGreg Clayton command.Printf(R"( --working-dir \"%s\")", working_dir.GetPath().c_str()); 2502c77eefeSRaphael Isemann else { 2512c77eefeSRaphael Isemann char cwd[PATH_MAX]; 2522c77eefeSRaphael Isemann if (getcwd(cwd, PATH_MAX)) 2535205c177SJonas Devlieghere command.Printf(R"( --working-dir \"%s\")", cwd); 2542c77eefeSRaphael Isemann } 2552c77eefeSRaphael Isemann 2562c77eefeSRaphael Isemann if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) 2572c77eefeSRaphael Isemann command.PutCString(" --disable-aslr"); 2582c77eefeSRaphael Isemann 2592c77eefeSRaphael Isemann // We are launching on this host in a terminal. So compare the environment on 2602c77eefeSRaphael Isemann // the host to what is supplied in the launch_info. Any items that aren't in 2612c77eefeSRaphael Isemann // the host environment need to be sent to darwin-debug. If we send all 2622c77eefeSRaphael Isemann // environment entries, we might blow the max command line length, so we only 2632c77eefeSRaphael Isemann // send user modified entries. 2642c77eefeSRaphael Isemann Environment host_env = Host::GetEnvironment(); 2652c77eefeSRaphael Isemann 2662c77eefeSRaphael Isemann for (const auto &KV : launch_info.GetEnvironment()) { 2672c77eefeSRaphael Isemann auto host_entry = host_env.find(KV.first()); 2682c77eefeSRaphael Isemann if (host_entry == host_env.end() || host_entry->second != KV.second) 2695205c177SJonas Devlieghere command.Format(R"( --env=\"{0}\")", Environment::compose(KV)); 2702c77eefeSRaphael Isemann } 2712c77eefeSRaphael Isemann 2722c77eefeSRaphael Isemann command.PutCString(" -- "); 2732c77eefeSRaphael Isemann 2742c77eefeSRaphael Isemann const char **argv = launch_info.GetArguments().GetConstArgumentVector(); 2752c77eefeSRaphael Isemann if (argv) { 2762c77eefeSRaphael Isemann for (size_t i = 0; argv[i] != NULL; ++i) { 2772c77eefeSRaphael Isemann if (i == 0) 2785205c177SJonas Devlieghere command.Printf(R"( \"%s\")", exe_path); 2792c77eefeSRaphael Isemann else 2805205c177SJonas Devlieghere command.Printf(R"( \"%s\")", argv[i]); 2812c77eefeSRaphael Isemann } 2822c77eefeSRaphael Isemann } else { 2835205c177SJonas Devlieghere command.Printf(R"( \"%s\")", exe_path); 2842c77eefeSRaphael Isemann } 2852c77eefeSRaphael Isemann command.PutCString(" ; echo Process exited with status $?"); 2862c77eefeSRaphael Isemann if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit)) 2872c77eefeSRaphael Isemann command.PutCString(" ; exit"); 2882c77eefeSRaphael Isemann 2892c77eefeSRaphael Isemann StreamString applescript_source; 2902c77eefeSRaphael Isemann 2912c77eefeSRaphael Isemann applescript_source.Printf(applscript_in_new_tty, 2922c77eefeSRaphael Isemann command.GetString().str().c_str()); 2935205c177SJonas Devlieghere 2942c77eefeSRaphael Isemann NSAppleScript *applescript = [[NSAppleScript alloc] 2952c77eefeSRaphael Isemann initWithSource:[NSString stringWithCString:applescript_source.GetString() 2962c77eefeSRaphael Isemann .str() 2972c77eefeSRaphael Isemann .c_str() 2982c77eefeSRaphael Isemann encoding:NSUTF8StringEncoding]]; 2992c77eefeSRaphael Isemann 3002c77eefeSRaphael Isemann lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 3012c77eefeSRaphael Isemann 3022c77eefeSRaphael Isemann Status lldb_error; 3032c77eefeSRaphael Isemann // Sleep and wait a bit for debugserver to start to listen... 3042c77eefeSRaphael Isemann ConnectionFileDescriptor file_conn; 3052c77eefeSRaphael Isemann char connect_url[128]; 3062c77eefeSRaphael Isemann ::snprintf(connect_url, sizeof(connect_url), "unix-accept://%s", 3072c77eefeSRaphael Isemann unix_socket_name); 3082c77eefeSRaphael Isemann 3092c77eefeSRaphael Isemann // Spawn a new thread to accept incoming connection on the connect_url 3102c77eefeSRaphael Isemann // so we can grab the pid from the inferior. We have to do this because we 3112c77eefeSRaphael Isemann // are sending an AppleScript that will launch a process in Terminal.app, 3122c77eefeSRaphael Isemann // in a shell and the shell will fork/exec a couple of times before we get 3132c77eefeSRaphael Isemann // to the process that we wanted to launch. So when our process actually 3142c77eefeSRaphael Isemann // gets launched, we will handshake with it and get the process ID for it. 315f39c2e18SJonas Devlieghere llvm::Expected<HostThread> accept_thread = ThreadLauncher::LaunchThread( 316d0810779SPavel Labath unix_socket_name, [&] { return AcceptPIDFromInferior(connect_url); }); 317f39c2e18SJonas Devlieghere 318f39c2e18SJonas Devlieghere if (!accept_thread) 319a0dd90ebSAdrian Prantl return Status::FromError(accept_thread.takeError()); 3202c77eefeSRaphael Isemann 3212c77eefeSRaphael Isemann [applescript executeAndReturnError:nil]; 3222c77eefeSRaphael Isemann 3232c77eefeSRaphael Isemann thread_result_t accept_thread_result = NULL; 324f39c2e18SJonas Devlieghere lldb_error = accept_thread->Join(&accept_thread_result); 3252c77eefeSRaphael Isemann if (lldb_error.Success() && accept_thread_result) { 3262c77eefeSRaphael Isemann pid = (intptr_t)accept_thread_result; 3272c77eefeSRaphael Isemann } 3282c77eefeSRaphael Isemann 3292c77eefeSRaphael Isemann llvm::sys::fs::remove(unix_socket_name); 3302c77eefeSRaphael Isemann [applescript release]; 3312c77eefeSRaphael Isemann if (pid != LLDB_INVALID_PROCESS_ID) 3322c77eefeSRaphael Isemann launch_info.SetProcessID(pid); 3332c77eefeSRaphael Isemann return error; 3342c77eefeSRaphael Isemann} 3352c77eefeSRaphael Isemann 336f203100eSVedant Kumar#endif // TARGET_OS_OSX 3372c77eefeSRaphael Isemann 338b12b35adSJonas Devliegherellvm::Error Host::OpenFileInExternalEditor(llvm::StringRef editor, 339b12b35adSJonas Devlieghere const FileSpec &file_spec, 3402c77eefeSRaphael Isemann uint32_t line_no) { 341f203100eSVedant Kumar#if !TARGET_OS_OSX 34213dbc16bSJonas Devlieghere return llvm::errorCodeToError( 34313dbc16bSJonas Devlieghere std::error_code(ENOTSUP, std::system_category())); 344f203100eSVedant Kumar#else // !TARGET_OS_OSX 34513dbc16bSJonas Devlieghere Log *log = GetLog(LLDBLog::Host); 34613dbc16bSJonas Devlieghere 34713dbc16bSJonas Devlieghere const std::string file_path = file_spec.GetPath(); 34813dbc16bSJonas Devlieghere 34913dbc16bSJonas Devlieghere LLDB_LOG(log, "Sending {0}:{1} to external editor", 35013dbc16bSJonas Devlieghere file_path.empty() ? "<invalid>" : file_path, line_no); 35113dbc16bSJonas Devlieghere 35213dbc16bSJonas Devlieghere if (file_path.empty()) 35313dbc16bSJonas Devlieghere return llvm::createStringError(llvm::inconvertibleErrorCode(), 35413dbc16bSJonas Devlieghere "no file specified"); 35513dbc16bSJonas Devlieghere 35613dbc16bSJonas Devlieghere CFCString file_cfstr(file_path.c_str(), kCFStringEncodingUTF8); 35713dbc16bSJonas Devlieghere CFCReleaser<CFURLRef> file_URL = ::CFURLCreateWithFileSystemPath( 35813dbc16bSJonas Devlieghere /*allocator=*/NULL, 35913dbc16bSJonas Devlieghere /*filePath*/ file_cfstr.get(), 36013dbc16bSJonas Devlieghere /*pathStyle=*/kCFURLPOSIXPathStyle, 36113dbc16bSJonas Devlieghere /*isDirectory=*/false); 36213dbc16bSJonas Devlieghere 36313dbc16bSJonas Devlieghere if (!file_URL.get()) 36413dbc16bSJonas Devlieghere return llvm::createStringError( 36513dbc16bSJonas Devlieghere llvm::inconvertibleErrorCode(), 36613dbc16bSJonas Devlieghere llvm::formatv("could not create CFURL from path \"{0}\"", file_path)); 36713dbc16bSJonas Devlieghere 36813dbc16bSJonas Devlieghere // Create a new Apple Event descriptor. 3692c77eefeSRaphael Isemann typedef struct { 3702c77eefeSRaphael Isemann int16_t reserved0; // must be zero 3712c77eefeSRaphael Isemann int16_t fLineNumber; 3722c77eefeSRaphael Isemann int32_t fSelStart; 3732c77eefeSRaphael Isemann int32_t fSelEnd; 3742c77eefeSRaphael Isemann uint32_t reserved1; // must be zero 3752c77eefeSRaphael Isemann uint32_t reserved2; // must be zero 3762c77eefeSRaphael Isemann } BabelAESelInfo; 3772c77eefeSRaphael Isemann 37813dbc16bSJonas Devlieghere // We attach this to an 'odoc' event to specify a particular selection. 3792c77eefeSRaphael Isemann BabelAESelInfo file_and_line_info = { 3802c77eefeSRaphael Isemann 0, // reserved0 3812c77eefeSRaphael Isemann (int16_t)(line_no - 1), // fLineNumber (zero based line number) 3822c77eefeSRaphael Isemann 1, // fSelStart 3832c77eefeSRaphael Isemann 1024, // fSelEnd 3842c77eefeSRaphael Isemann 0, // reserved1 3852c77eefeSRaphael Isemann 0 // reserved2 3862c77eefeSRaphael Isemann }; 3872c77eefeSRaphael Isemann 3882c77eefeSRaphael Isemann AEKeyDesc file_and_line_desc; 3892c77eefeSRaphael Isemann file_and_line_desc.descKey = keyAEPosition; 39013dbc16bSJonas Devlieghere long error = ::AECreateDesc(/*typeCode=*/typeUTF8Text, 39113dbc16bSJonas Devlieghere /*dataPtr=*/&file_and_line_info, 39213dbc16bSJonas Devlieghere /*dataSize=*/sizeof(file_and_line_info), 39313dbc16bSJonas Devlieghere /*result=*/&(file_and_line_desc.descContent)); 3942c77eefeSRaphael Isemann 39513dbc16bSJonas Devlieghere if (error != noErr) 39613dbc16bSJonas Devlieghere return llvm::createStringError( 39713dbc16bSJonas Devlieghere llvm::inconvertibleErrorCode(), 39813dbc16bSJonas Devlieghere llvm::formatv("creating Apple Event descriptor failed: error {0}", 39913dbc16bSJonas Devlieghere error)); 4002c77eefeSRaphael Isemann 40113dbc16bSJonas Devlieghere // Deallocate the descriptor on exit. 40213dbc16bSJonas Devlieghere auto on_exit = llvm::make_scope_exit( 40313dbc16bSJonas Devlieghere [&]() { AEDisposeDesc(&(file_and_line_desc.descContent)); }); 40413dbc16bSJonas Devlieghere 405b12b35adSJonas Devlieghere if (editor.empty()) { 406b12b35adSJonas Devlieghere if (const char *lldb_external_editor = ::getenv("LLDB_EXTERNAL_EDITOR")) 407b12b35adSJonas Devlieghere editor = lldb_external_editor; 408b12b35adSJonas Devlieghere } 40913dbc16bSJonas Devlieghere 410b12b35adSJonas Devlieghere std::optional<FSRef> app_fsref; 411b12b35adSJonas Devlieghere if (!editor.empty()) { 412b12b35adSJonas Devlieghere LLDB_LOG(log, "Looking for external editor: {0}", editor); 413b12b35adSJonas Devlieghere 414b12b35adSJonas Devlieghere app_fsref.emplace(); 415b12b35adSJonas Devlieghere CFCString editor_name(editor.data(), kCFStringEncodingUTF8); 41613dbc16bSJonas Devlieghere long app_error = ::LSFindApplicationForInfo( 41713dbc16bSJonas Devlieghere /*inCreator=*/kLSUnknownCreator, /*inBundleID=*/NULL, 418b12b35adSJonas Devlieghere /*inName=*/editor_name.get(), /*outAppRef=*/&(*app_fsref), 41913dbc16bSJonas Devlieghere /*outAppURL=*/NULL); 420b12b35adSJonas Devlieghere if (app_error != noErr) 421b12b35adSJonas Devlieghere return llvm::createStringError( 422b12b35adSJonas Devlieghere llvm::inconvertibleErrorCode(), 42313dbc16bSJonas Devlieghere llvm::formatv("could not find external editor \"{0}\": " 42413dbc16bSJonas Devlieghere "LSFindApplicationForInfo returned error {1}", 425b12b35adSJonas Devlieghere editor, app_error)); 42613dbc16bSJonas Devlieghere } 42713dbc16bSJonas Devlieghere 42813dbc16bSJonas Devlieghere // Build app launch parameters. 4292c77eefeSRaphael Isemann LSApplicationParameters app_params; 4302c77eefeSRaphael Isemann ::memset(&app_params, 0, sizeof(app_params)); 4312c77eefeSRaphael Isemann app_params.flags = 4322c77eefeSRaphael Isemann kLSLaunchDefaults | kLSLaunchDontAddToRecents | kLSLaunchDontSwitch; 433b12b35adSJonas Devlieghere if (app_fsref) 434b12b35adSJonas Devlieghere app_params.application = &(*app_fsref); 4352c77eefeSRaphael Isemann 4362c77eefeSRaphael Isemann ProcessSerialNumber psn; 43713dbc16bSJonas Devlieghere std::array<CFURLRef, 1> file_array = {file_URL.get()}; 43813dbc16bSJonas Devlieghere CFCReleaser<CFArrayRef> cf_array( 43913dbc16bSJonas Devlieghere CFArrayCreate(/*allocator=*/NULL, /*values=*/(const void **)&file_array, 44013dbc16bSJonas Devlieghere /*numValues*/ 1, /*callBacks=*/NULL)); 44113dbc16bSJonas Devlieghere error = ::LSOpenURLsWithRole( 44213dbc16bSJonas Devlieghere /*inURLs=*/cf_array.get(), /*inRole=*/kLSRolesEditor, 44313dbc16bSJonas Devlieghere /*inAEParam=*/&file_and_line_desc, 44413dbc16bSJonas Devlieghere /*inAppParams=*/&app_params, /*outPSNs=*/&psn, /*inMaxPSNCount=*/1); 4452c77eefeSRaphael Isemann 44613dbc16bSJonas Devlieghere if (error != noErr) 44713dbc16bSJonas Devlieghere return llvm::createStringError( 44813dbc16bSJonas Devlieghere llvm::inconvertibleErrorCode(), 44913dbc16bSJonas Devlieghere llvm::formatv("LSOpenURLsWithRole failed: error {0}", error)); 4502c77eefeSRaphael Isemann 45113dbc16bSJonas Devlieghere return llvm::Error::success(); 452f203100eSVedant Kumar#endif // TARGET_OS_OSX 4532c77eefeSRaphael Isemann} 4542c77eefeSRaphael Isemann 455b945b62cSJonas Devliegherebool Host::IsInteractiveGraphicSession() { 456b945b62cSJonas Devlieghere#if !TARGET_OS_OSX 457b945b62cSJonas Devlieghere return false; 458b945b62cSJonas Devlieghere#else 459b945b62cSJonas Devlieghere auditinfo_addr_t info; 460b945b62cSJonas Devlieghere getaudit_addr(&info, sizeof(info)); 461b945b62cSJonas Devlieghere return info.ai_flags & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS; 462b945b62cSJonas Devlieghere#endif 463b945b62cSJonas Devlieghere} 464b945b62cSJonas Devlieghere 4652c77eefeSRaphael IsemannEnvironment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); } 4662c77eefeSRaphael Isemann 4672c77eefeSRaphael Isemannstatic bool GetMacOSXProcessCPUType(ProcessInstanceInfo &process_info) { 4682c77eefeSRaphael Isemann if (process_info.ProcessIDIsValid()) { 4692c77eefeSRaphael Isemann // Make a new mib to stay thread safe 4702c77eefeSRaphael Isemann int mib[CTL_MAXNAME] = { 4712c77eefeSRaphael Isemann 0, 4722c77eefeSRaphael Isemann }; 4732c77eefeSRaphael Isemann size_t mib_len = CTL_MAXNAME; 4742c77eefeSRaphael Isemann if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len)) 4752c77eefeSRaphael Isemann return false; 4762c77eefeSRaphael Isemann 4772c77eefeSRaphael Isemann mib[mib_len] = process_info.GetProcessID(); 4782c77eefeSRaphael Isemann mib_len++; 4792c77eefeSRaphael Isemann 4802c77eefeSRaphael Isemann cpu_type_t cpu, sub = 0; 4812c77eefeSRaphael Isemann size_t len = sizeof(cpu); 4822c77eefeSRaphael Isemann if (::sysctl(mib, mib_len, &cpu, &len, 0, 0) == 0) { 4832c77eefeSRaphael Isemann switch (cpu) { 4842c77eefeSRaphael Isemann case CPU_TYPE_I386: 4852c77eefeSRaphael Isemann sub = CPU_SUBTYPE_I386_ALL; 4862c77eefeSRaphael Isemann break; 4872c77eefeSRaphael Isemann case CPU_TYPE_X86_64: 4882c77eefeSRaphael Isemann sub = CPU_SUBTYPE_X86_64_ALL; 4892c77eefeSRaphael Isemann break; 4902c77eefeSRaphael Isemann 4912c77eefeSRaphael Isemann#if defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64_ALL) 4922c77eefeSRaphael Isemann case CPU_TYPE_ARM64: 4932c77eefeSRaphael Isemann sub = CPU_SUBTYPE_ARM64_ALL; 4942c77eefeSRaphael Isemann break; 4952c77eefeSRaphael Isemann#endif 4962c77eefeSRaphael Isemann 4977dd7a360SJason Molenda#if defined(CPU_TYPE_ARM64_32) && defined(CPU_SUBTYPE_ARM64_32_ALL) 4987dd7a360SJason Molenda case CPU_TYPE_ARM64_32: 4997dd7a360SJason Molenda sub = CPU_SUBTYPE_ARM64_32_ALL; 5007dd7a360SJason Molenda break; 5017dd7a360SJason Molenda#endif 5027dd7a360SJason Molenda 5032c77eefeSRaphael Isemann case CPU_TYPE_ARM: { 5042c77eefeSRaphael Isemann // Note that we fetched the cpu type from the PROCESS but we can't get a 5052c77eefeSRaphael Isemann // cpusubtype of the 5062c77eefeSRaphael Isemann // process -- we can only get the host's cpu subtype. 5072c77eefeSRaphael Isemann uint32_t cpusubtype = 0; 5082c77eefeSRaphael Isemann len = sizeof(cpusubtype); 5092c77eefeSRaphael Isemann if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) 5102c77eefeSRaphael Isemann sub = cpusubtype; 5112c77eefeSRaphael Isemann 5122c77eefeSRaphael Isemann bool host_cpu_is_64bit; 5132c77eefeSRaphael Isemann uint32_t is64bit_capable; 5142c77eefeSRaphael Isemann size_t is64bit_capable_len = sizeof(is64bit_capable); 515a6682a41SJonas Devlieghere host_cpu_is_64bit = 516a6682a41SJonas Devlieghere sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, 517a6682a41SJonas Devlieghere &is64bit_capable_len, NULL, 0) == 0; 5182c77eefeSRaphael Isemann 5192c77eefeSRaphael Isemann // if the host is an armv8 device, its cpusubtype will be in 5202c77eefeSRaphael Isemann // CPU_SUBTYPE_ARM64 numbering 5212c77eefeSRaphael Isemann // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value 5222c77eefeSRaphael Isemann // instead. 5232c77eefeSRaphael Isemann 5242c77eefeSRaphael Isemann if (host_cpu_is_64bit) { 5252c77eefeSRaphael Isemann sub = CPU_SUBTYPE_ARM_V7; 5262c77eefeSRaphael Isemann } 5272c77eefeSRaphael Isemann } break; 5282c77eefeSRaphael Isemann 5292c77eefeSRaphael Isemann default: 5302c77eefeSRaphael Isemann break; 5312c77eefeSRaphael Isemann } 5322c77eefeSRaphael Isemann process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, sub); 5332c77eefeSRaphael Isemann return true; 5342c77eefeSRaphael Isemann } 5352c77eefeSRaphael Isemann } 5362c77eefeSRaphael Isemann process_info.GetArchitecture().Clear(); 5372c77eefeSRaphael Isemann return false; 5382c77eefeSRaphael Isemann} 5392c77eefeSRaphael Isemann 5402c77eefeSRaphael Isemannstatic bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr, 5412c77eefeSRaphael Isemann ProcessInstanceInfo &process_info) { 5422c77eefeSRaphael Isemann if (process_info.ProcessIDIsValid()) { 5432c77eefeSRaphael Isemann int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2, 5442c77eefeSRaphael Isemann (int)process_info.GetProcessID()}; 5452c77eefeSRaphael Isemann 5462c77eefeSRaphael Isemann size_t arg_data_size = 0; 5472c77eefeSRaphael Isemann if (::sysctl(proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) || 5482c77eefeSRaphael Isemann arg_data_size == 0) 5492c77eefeSRaphael Isemann arg_data_size = 8192; 5502c77eefeSRaphael Isemann 5512c77eefeSRaphael Isemann // Add a few bytes to the calculated length, I know we need to add at least 5522c77eefeSRaphael Isemann // one byte 5532c77eefeSRaphael Isemann // to this number otherwise we get junk back, so add 128 just in case... 5542c77eefeSRaphael Isemann DataBufferHeap arg_data(arg_data_size + 128, 0); 5552c77eefeSRaphael Isemann arg_data_size = arg_data.GetByteSize(); 5562c77eefeSRaphael Isemann if (::sysctl(proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size, NULL, 5572c77eefeSRaphael Isemann 0) == 0) { 5582c77eefeSRaphael Isemann DataExtractor data(arg_data.GetBytes(), arg_data_size, 5592c77eefeSRaphael Isemann endian::InlHostByteOrder(), sizeof(void *)); 5602c77eefeSRaphael Isemann lldb::offset_t offset = 0; 5612c77eefeSRaphael Isemann uint32_t argc = data.GetU32(&offset); 5622c77eefeSRaphael Isemann llvm::Triple &triple = process_info.GetArchitecture().GetTriple(); 5632c77eefeSRaphael Isemann const llvm::Triple::ArchType triple_arch = triple.getArch(); 5642c77eefeSRaphael Isemann const bool check_for_ios_simulator = 5652c77eefeSRaphael Isemann (triple_arch == llvm::Triple::x86 || 5662c77eefeSRaphael Isemann triple_arch == llvm::Triple::x86_64); 5672c77eefeSRaphael Isemann const char *cstr = data.GetCStr(&offset); 5682c77eefeSRaphael Isemann if (cstr) { 5698f3be7a3SJonas Devlieghere process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native); 5702c77eefeSRaphael Isemann 5712c77eefeSRaphael Isemann if (match_info_ptr == NULL || 5722c77eefeSRaphael Isemann NameMatches( 5732c77eefeSRaphael Isemann process_info.GetExecutableFile().GetFilename().GetCString(), 5742c77eefeSRaphael Isemann match_info_ptr->GetNameMatchType(), 5752c77eefeSRaphael Isemann match_info_ptr->GetProcessInfo().GetName())) { 5762c77eefeSRaphael Isemann // Skip NULLs 57709ad8c8fSJonas Devlieghere while (true) { 5782c77eefeSRaphael Isemann const uint8_t *p = data.PeekData(offset, 1); 5792c77eefeSRaphael Isemann if ((p == NULL) || (*p != '\0')) 5802c77eefeSRaphael Isemann break; 5812c77eefeSRaphael Isemann ++offset; 5822c77eefeSRaphael Isemann } 5832c77eefeSRaphael Isemann // Now extract all arguments 5842c77eefeSRaphael Isemann Args &proc_args = process_info.GetArguments(); 5852c77eefeSRaphael Isemann for (int i = 0; i < static_cast<int>(argc); ++i) { 5862c77eefeSRaphael Isemann cstr = data.GetCStr(&offset); 5872c77eefeSRaphael Isemann if (cstr) 5882c77eefeSRaphael Isemann proc_args.AppendArgument(llvm::StringRef(cstr)); 5892c77eefeSRaphael Isemann } 5902c77eefeSRaphael Isemann 5912c77eefeSRaphael Isemann Environment &proc_env = process_info.GetEnvironment(); 5922c77eefeSRaphael Isemann while ((cstr = data.GetCStr(&offset))) { 5932c77eefeSRaphael Isemann if (cstr[0] == '\0') 5942c77eefeSRaphael Isemann break; 5952c77eefeSRaphael Isemann 5962c77eefeSRaphael Isemann if (check_for_ios_simulator) { 5972c77eefeSRaphael Isemann if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == 5982c77eefeSRaphael Isemann 0) 5992c77eefeSRaphael Isemann process_info.GetArchitecture().GetTriple().setOS( 6002c77eefeSRaphael Isemann llvm::Triple::IOS); 6012c77eefeSRaphael Isemann else 6022c77eefeSRaphael Isemann process_info.GetArchitecture().GetTriple().setOS( 6032c77eefeSRaphael Isemann llvm::Triple::MacOSX); 6042c77eefeSRaphael Isemann } 6052c77eefeSRaphael Isemann 6062c77eefeSRaphael Isemann proc_env.insert(cstr); 6072c77eefeSRaphael Isemann } 6082c77eefeSRaphael Isemann return true; 6092c77eefeSRaphael Isemann } 6102c77eefeSRaphael Isemann } 6112c77eefeSRaphael Isemann } 6122c77eefeSRaphael Isemann } 6132c77eefeSRaphael Isemann return false; 6142c77eefeSRaphael Isemann} 6152c77eefeSRaphael Isemann 6162c77eefeSRaphael Isemannstatic bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { 6172c77eefeSRaphael Isemann if (process_info.ProcessIDIsValid()) { 6182c77eefeSRaphael Isemann int mib[4]; 6192c77eefeSRaphael Isemann mib[0] = CTL_KERN; 6202c77eefeSRaphael Isemann mib[1] = KERN_PROC; 6212c77eefeSRaphael Isemann mib[2] = KERN_PROC_PID; 6222c77eefeSRaphael Isemann mib[3] = process_info.GetProcessID(); 6232c77eefeSRaphael Isemann struct kinfo_proc proc_kinfo; 6242c77eefeSRaphael Isemann size_t proc_kinfo_size = sizeof(struct kinfo_proc); 6252c77eefeSRaphael Isemann 6262c77eefeSRaphael Isemann if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) { 6272c77eefeSRaphael Isemann if (proc_kinfo_size > 0) { 6282c77eefeSRaphael Isemann process_info.SetParentProcessID(proc_kinfo.kp_eproc.e_ppid); 6292c77eefeSRaphael Isemann process_info.SetUserID(proc_kinfo.kp_eproc.e_pcred.p_ruid); 6302c77eefeSRaphael Isemann process_info.SetGroupID(proc_kinfo.kp_eproc.e_pcred.p_rgid); 6312c77eefeSRaphael Isemann process_info.SetEffectiveUserID(proc_kinfo.kp_eproc.e_ucred.cr_uid); 6322c77eefeSRaphael Isemann if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0) 6332c77eefeSRaphael Isemann process_info.SetEffectiveGroupID( 6342c77eefeSRaphael Isemann proc_kinfo.kp_eproc.e_ucred.cr_groups[0]); 6352c77eefeSRaphael Isemann else 6362c77eefeSRaphael Isemann process_info.SetEffectiveGroupID(UINT32_MAX); 6372c77eefeSRaphael Isemann return true; 6382c77eefeSRaphael Isemann } 6392c77eefeSRaphael Isemann } 6402c77eefeSRaphael Isemann } 6412c77eefeSRaphael Isemann process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID); 6422c77eefeSRaphael Isemann process_info.SetUserID(UINT32_MAX); 6432c77eefeSRaphael Isemann process_info.SetGroupID(UINT32_MAX); 6442c77eefeSRaphael Isemann process_info.SetEffectiveUserID(UINT32_MAX); 6452c77eefeSRaphael Isemann process_info.SetEffectiveGroupID(UINT32_MAX); 6462c77eefeSRaphael Isemann return false; 6472c77eefeSRaphael Isemann} 6482c77eefeSRaphael Isemann 6492451cbf0SJonas Devlieghereuint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, 6502c77eefeSRaphael Isemann ProcessInstanceInfoList &process_infos) { 6512c77eefeSRaphael Isemann std::vector<struct kinfo_proc> kinfos; 6522c77eefeSRaphael Isemann 6532c77eefeSRaphael Isemann int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; 6542c77eefeSRaphael Isemann 6552c77eefeSRaphael Isemann size_t pid_data_size = 0; 65634fb64d6SJonas Devlieghere if (::sysctl(mib, 3, nullptr, &pid_data_size, nullptr, 0) != 0) 6572c77eefeSRaphael Isemann return 0; 6582c77eefeSRaphael Isemann 6592c77eefeSRaphael Isemann // Add a few extra in case a few more show up 6602c77eefeSRaphael Isemann const size_t estimated_pid_count = 6612c77eefeSRaphael Isemann (pid_data_size / sizeof(struct kinfo_proc)) + 10; 6622c77eefeSRaphael Isemann 6632c77eefeSRaphael Isemann kinfos.resize(estimated_pid_count); 6642c77eefeSRaphael Isemann pid_data_size = kinfos.size() * sizeof(struct kinfo_proc); 6652c77eefeSRaphael Isemann 66634fb64d6SJonas Devlieghere if (::sysctl(mib, 3, &kinfos[0], &pid_data_size, nullptr, 0) != 0) 6672c77eefeSRaphael Isemann return 0; 6682c77eefeSRaphael Isemann 6692c77eefeSRaphael Isemann const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc)); 6702c77eefeSRaphael Isemann 6712c77eefeSRaphael Isemann bool all_users = match_info.GetMatchAllUsers(); 6722c77eefeSRaphael Isemann const lldb::pid_t our_pid = getpid(); 6732c77eefeSRaphael Isemann const uid_t our_uid = getuid(); 6742c77eefeSRaphael Isemann for (size_t i = 0; i < actual_pid_count; i++) { 6752c77eefeSRaphael Isemann const struct kinfo_proc &kinfo = kinfos[i]; 6762c77eefeSRaphael Isemann 6772c77eefeSRaphael Isemann bool kinfo_user_matches = false; 6782c77eefeSRaphael Isemann if (all_users) 6792c77eefeSRaphael Isemann kinfo_user_matches = true; 6802c77eefeSRaphael Isemann else 6812c77eefeSRaphael Isemann kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid; 6822c77eefeSRaphael Isemann 6832c77eefeSRaphael Isemann // Special case, if lldb is being run as root we can attach to anything. 6842c77eefeSRaphael Isemann if (our_uid == 0) 6852c77eefeSRaphael Isemann kinfo_user_matches = true; 6862c77eefeSRaphael Isemann 687a6682a41SJonas Devlieghere if (!kinfo_user_matches || // Make sure the user is acceptable 6882c77eefeSRaphael Isemann static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) == 6892c77eefeSRaphael Isemann our_pid || // Skip this process 6902c77eefeSRaphael Isemann kinfo.kp_proc.p_pid == 0 || // Skip kernel (kernel pid is zero) 6912c77eefeSRaphael Isemann kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains... 6922c77eefeSRaphael Isemann kinfo.kp_proc.p_flag & P_TRACED || // Being debugged? 693b4fdddf9SDavide Italiano kinfo.kp_proc.p_flag & P_WEXIT) 6942c77eefeSRaphael Isemann continue; 6952c77eefeSRaphael Isemann 6962c77eefeSRaphael Isemann ProcessInstanceInfo process_info; 6972c77eefeSRaphael Isemann process_info.SetProcessID(kinfo.kp_proc.p_pid); 6982c77eefeSRaphael Isemann process_info.SetParentProcessID(kinfo.kp_eproc.e_ppid); 6992c77eefeSRaphael Isemann process_info.SetUserID(kinfo.kp_eproc.e_pcred.p_ruid); 7002c77eefeSRaphael Isemann process_info.SetGroupID(kinfo.kp_eproc.e_pcred.p_rgid); 7012c77eefeSRaphael Isemann process_info.SetEffectiveUserID(kinfo.kp_eproc.e_ucred.cr_uid); 7022c77eefeSRaphael Isemann if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0) 7032c77eefeSRaphael Isemann process_info.SetEffectiveGroupID(kinfo.kp_eproc.e_ucred.cr_groups[0]); 7042c77eefeSRaphael Isemann else 7052c77eefeSRaphael Isemann process_info.SetEffectiveGroupID(UINT32_MAX); 7062c77eefeSRaphael Isemann 7072c77eefeSRaphael Isemann // Make sure our info matches before we go fetch the name and cpu type 708a8b18baaSPavel Labath if (!match_info.UserIDsMatch(process_info) || 709a8b18baaSPavel Labath !match_info.ProcessIDsMatch(process_info)) 710a8b18baaSPavel Labath continue; 711a8b18baaSPavel Labath 7122c77eefeSRaphael Isemann // Get CPU type first so we can know to look for iOS simulator is we have 7132c77eefeSRaphael Isemann // x86 or x86_64 7142c77eefeSRaphael Isemann if (GetMacOSXProcessCPUType(process_info)) { 7152c77eefeSRaphael Isemann if (GetMacOSXProcessArgs(&match_info, process_info)) { 7162c77eefeSRaphael Isemann if (match_info.Matches(process_info)) 717638b06cfSJonas Devlieghere process_infos.push_back(process_info); 7182c77eefeSRaphael Isemann } 7192c77eefeSRaphael Isemann } 7202c77eefeSRaphael Isemann } 721638b06cfSJonas Devlieghere return process_infos.size(); 7222c77eefeSRaphael Isemann} 7232c77eefeSRaphael Isemann 7242c77eefeSRaphael Isemannbool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { 7252c77eefeSRaphael Isemann process_info.SetProcessID(pid); 7262c77eefeSRaphael Isemann bool success = false; 7272c77eefeSRaphael Isemann 7282c77eefeSRaphael Isemann // Get CPU type first so we can know to look for iOS simulator is we have x86 7292c77eefeSRaphael Isemann // or x86_64 7302c77eefeSRaphael Isemann if (GetMacOSXProcessCPUType(process_info)) 7312c77eefeSRaphael Isemann success = true; 7322c77eefeSRaphael Isemann 7332c77eefeSRaphael Isemann if (GetMacOSXProcessArgs(NULL, process_info)) 7342c77eefeSRaphael Isemann success = true; 7352c77eefeSRaphael Isemann 7362c77eefeSRaphael Isemann if (GetMacOSXProcessUserAndGroup(process_info)) 7372c77eefeSRaphael Isemann success = true; 7382c77eefeSRaphael Isemann 7392c77eefeSRaphael Isemann if (success) 7402c77eefeSRaphael Isemann return true; 7412c77eefeSRaphael Isemann 7422c77eefeSRaphael Isemann process_info.Clear(); 7432c77eefeSRaphael Isemann return false; 7442c77eefeSRaphael Isemann} 7452c77eefeSRaphael Isemann 746f203100eSVedant Kumar#if TARGET_OS_OSX 7472c77eefeSRaphael Isemannstatic void PackageXPCArguments(xpc_object_t message, const char *prefix, 7482c77eefeSRaphael Isemann const Args &args) { 7492c77eefeSRaphael Isemann size_t count = args.GetArgumentCount(); 7502c77eefeSRaphael Isemann char buf[50]; // long enough for 'argXXX' 751d03d98b7SDave Lee memset(buf, 0, sizeof(buf)); 752d03d98b7SDave Lee snprintf(buf, sizeof(buf), "%sCount", prefix); 7532c77eefeSRaphael Isemann xpc_dictionary_set_int64(message, buf, count); 7542c77eefeSRaphael Isemann for (size_t i = 0; i < count; i++) { 755d03d98b7SDave Lee memset(buf, 0, sizeof(buf)); 756d03d98b7SDave Lee snprintf(buf, sizeof(buf), "%s%zi", prefix, i); 7572c77eefeSRaphael Isemann xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i)); 7582c77eefeSRaphael Isemann } 7592c77eefeSRaphael Isemann} 7602c77eefeSRaphael Isemann 7612c77eefeSRaphael Isemannstatic void PackageXPCEnvironment(xpc_object_t message, llvm::StringRef prefix, 7622c77eefeSRaphael Isemann const Environment &env) { 7632c77eefeSRaphael Isemann xpc_dictionary_set_int64(message, (prefix + "Count").str().c_str(), 7642c77eefeSRaphael Isemann env.size()); 7652c77eefeSRaphael Isemann size_t i = 0; 7662c77eefeSRaphael Isemann for (const auto &KV : env) { 7672c77eefeSRaphael Isemann xpc_dictionary_set_string(message, (prefix + llvm::Twine(i)).str().c_str(), 7682c77eefeSRaphael Isemann Environment::compose(KV).c_str()); 7692c77eefeSRaphael Isemann } 7702c77eefeSRaphael Isemann} 7712c77eefeSRaphael Isemann 7722c77eefeSRaphael Isemann/* 7732c77eefeSRaphael Isemann A valid authorizationRef means that 7742c77eefeSRaphael Isemann - there is the LaunchUsingXPCRightName rights in the /etc/authorization 7752c77eefeSRaphael Isemann - we have successfully copied the rights to be send over the XPC wire 7762c77eefeSRaphael Isemann Once obtained, it will be valid for as long as the process lives. 7772c77eefeSRaphael Isemann */ 7782c77eefeSRaphael Isemannstatic AuthorizationRef authorizationRef = NULL; 7792c77eefeSRaphael Isemannstatic Status getXPCAuthorization(ProcessLaunchInfo &launch_info) { 7802c77eefeSRaphael Isemann Status error; 781a007a6d8SPavel Labath Log *log(GetLog(LLDBLog::Host | LLDBLog::Process)); 7822c77eefeSRaphael Isemann 7832c77eefeSRaphael Isemann if ((launch_info.GetUserID() == 0) && !authorizationRef) { 7842c77eefeSRaphael Isemann OSStatus createStatus = 7852c77eefeSRaphael Isemann AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, 7862c77eefeSRaphael Isemann kAuthorizationFlagDefaults, &authorizationRef); 7872c77eefeSRaphael Isemann if (createStatus != errAuthorizationSuccess) { 7880642cd76SAdrian Prantl error = Status(1, eErrorTypeGeneric); 7890642cd76SAdrian Prantl error = Status::FromErrorString("Can't create authorizationRef."); 7902c77eefeSRaphael Isemann LLDB_LOG(log, "error: {0}", error); 7912c77eefeSRaphael Isemann return error; 7922c77eefeSRaphael Isemann } 7932c77eefeSRaphael Isemann 7942c77eefeSRaphael Isemann OSStatus rightsStatus = 7952c77eefeSRaphael Isemann AuthorizationRightGet(LaunchUsingXPCRightName, NULL); 7962c77eefeSRaphael Isemann if (rightsStatus != errAuthorizationSuccess) { 7972c77eefeSRaphael Isemann // No rights in the security database, Create it with the right prompt. 7982c77eefeSRaphael Isemann CFStringRef prompt = 7992c77eefeSRaphael Isemann CFSTR("Xcode is trying to take control of a root process."); 8002c77eefeSRaphael Isemann CFStringRef keys[] = {CFSTR("en")}; 8012c77eefeSRaphael Isemann CFTypeRef values[] = {prompt}; 8022c77eefeSRaphael Isemann CFDictionaryRef promptDict = CFDictionaryCreate( 8032c77eefeSRaphael Isemann kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, 8042c77eefeSRaphael Isemann &kCFCopyStringDictionaryKeyCallBacks, 8052c77eefeSRaphael Isemann &kCFTypeDictionaryValueCallBacks); 8062c77eefeSRaphael Isemann 8072c77eefeSRaphael Isemann CFStringRef keys1[] = {CFSTR("class"), CFSTR("group"), CFSTR("comment"), 8082c77eefeSRaphael Isemann CFSTR("default-prompt"), CFSTR("shared")}; 8092c77eefeSRaphael Isemann CFTypeRef values1[] = {CFSTR("user"), CFSTR("admin"), 8102c77eefeSRaphael Isemann CFSTR(LaunchUsingXPCRightName), promptDict, 8112c77eefeSRaphael Isemann kCFBooleanFalse}; 8122c77eefeSRaphael Isemann CFDictionaryRef dict = CFDictionaryCreate( 8132c77eefeSRaphael Isemann kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5, 8142c77eefeSRaphael Isemann &kCFCopyStringDictionaryKeyCallBacks, 8152c77eefeSRaphael Isemann &kCFTypeDictionaryValueCallBacks); 8162c77eefeSRaphael Isemann rightsStatus = AuthorizationRightSet( 8172c77eefeSRaphael Isemann authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL); 8182c77eefeSRaphael Isemann CFRelease(promptDict); 8192c77eefeSRaphael Isemann CFRelease(dict); 8202c77eefeSRaphael Isemann } 8212c77eefeSRaphael Isemann 8222c77eefeSRaphael Isemann OSStatus copyRightStatus = errAuthorizationDenied; 8232c77eefeSRaphael Isemann if (rightsStatus == errAuthorizationSuccess) { 8242c77eefeSRaphael Isemann AuthorizationItem item1 = {LaunchUsingXPCRightName, 0, NULL, 0}; 8252c77eefeSRaphael Isemann AuthorizationItem items[] = {item1}; 8262c77eefeSRaphael Isemann AuthorizationRights requestedRights = {1, items}; 8272c77eefeSRaphael Isemann AuthorizationFlags authorizationFlags = 8282c77eefeSRaphael Isemann kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; 8292c77eefeSRaphael Isemann copyRightStatus = AuthorizationCopyRights( 8302c77eefeSRaphael Isemann authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment, 8312c77eefeSRaphael Isemann authorizationFlags, NULL); 8322c77eefeSRaphael Isemann } 8332c77eefeSRaphael Isemann 8342c77eefeSRaphael Isemann if (copyRightStatus != errAuthorizationSuccess) { 8352c77eefeSRaphael Isemann // Eventually when the commandline supports running as root and the user 8362c77eefeSRaphael Isemann // is not 837678e3ee1SFangrui Song // logged in to the current audit session, we will need the trick in gdb 8382c77eefeSRaphael Isemann // where 8392c77eefeSRaphael Isemann // we ask the user to type in the root passwd in the terminal. 8400642cd76SAdrian Prantl error = Status(2, eErrorTypeGeneric); 8410642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 8422c77eefeSRaphael Isemann "Launching as root needs root authorization."); 8432c77eefeSRaphael Isemann LLDB_LOG(log, "error: {0}", error); 8442c77eefeSRaphael Isemann 8452c77eefeSRaphael Isemann if (authorizationRef) { 8462c77eefeSRaphael Isemann AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); 8472c77eefeSRaphael Isemann authorizationRef = NULL; 8482c77eefeSRaphael Isemann } 8492c77eefeSRaphael Isemann } 8502c77eefeSRaphael Isemann } 8512c77eefeSRaphael Isemann 8522c77eefeSRaphael Isemann return error; 8532c77eefeSRaphael Isemann} 8542c77eefeSRaphael Isemann#endif 8552c77eefeSRaphael Isemann 8562c77eefeSRaphael Isemannstatic short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { 8572c77eefeSRaphael Isemann short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; 8582c77eefeSRaphael Isemann 8592c77eefeSRaphael Isemann if (launch_info.GetFlags().Test(eLaunchFlagExec)) 8602c77eefeSRaphael Isemann flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag 8612c77eefeSRaphael Isemann 8622c77eefeSRaphael Isemann if (launch_info.GetFlags().Test(eLaunchFlagDebug)) 8632c77eefeSRaphael Isemann flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag 8642c77eefeSRaphael Isemann 8652c77eefeSRaphael Isemann if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) 8662c77eefeSRaphael Isemann flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag 8672c77eefeSRaphael Isemann 8682c77eefeSRaphael Isemann if (launch_info.GetLaunchInSeparateProcessGroup()) 8692c77eefeSRaphael Isemann flags |= POSIX_SPAWN_SETPGROUP; 8702c77eefeSRaphael Isemann 8712c77eefeSRaphael Isemann#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT 8722c77eefeSRaphael Isemann#if defined(__x86_64__) || defined(__i386__) 8732c77eefeSRaphael Isemann static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate; 8742c77eefeSRaphael Isemann if (g_use_close_on_exec_flag == eLazyBoolCalculate) { 8752c77eefeSRaphael Isemann g_use_close_on_exec_flag = eLazyBoolNo; 8762c77eefeSRaphael Isemann 8776682979cSPavel Labath llvm::VersionTuple version = HostInfo::GetOSVersion(); 8786682979cSPavel Labath if (version > llvm::VersionTuple(10, 7)) { 8792c77eefeSRaphael Isemann // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or 8802c77eefeSRaphael Isemann // earlier 8812c77eefeSRaphael Isemann g_use_close_on_exec_flag = eLazyBoolYes; 8822c77eefeSRaphael Isemann } 8832c77eefeSRaphael Isemann } 8842c77eefeSRaphael Isemann#else 8852c77eefeSRaphael Isemann static LazyBool g_use_close_on_exec_flag = eLazyBoolYes; 8862c77eefeSRaphael Isemann#endif // defined(__x86_64__) || defined(__i386__) 8872c77eefeSRaphael Isemann // Close all files exception those with file actions if this is supported. 8882c77eefeSRaphael Isemann if (g_use_close_on_exec_flag == eLazyBoolYes) 8892c77eefeSRaphael Isemann flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; 8902c77eefeSRaphael Isemann#endif // ifdef POSIX_SPAWN_CLOEXEC_DEFAULT 8912c77eefeSRaphael Isemann return flags; 8922c77eefeSRaphael Isemann} 8932c77eefeSRaphael Isemann 894*c7605bfdSJonas Devliegherestatic void finalize_xpc(void *xpc_object) { 895*c7605bfdSJonas Devlieghere xpc_release((xpc_object_t)xpc_object); 896*c7605bfdSJonas Devlieghere} 897*c7605bfdSJonas Devlieghere 8982c77eefeSRaphael Isemannstatic Status LaunchProcessXPC(const char *exe_path, 8992c77eefeSRaphael Isemann ProcessLaunchInfo &launch_info, 9002c77eefeSRaphael Isemann lldb::pid_t &pid) { 901f203100eSVedant Kumar#if TARGET_OS_OSX 9022c77eefeSRaphael Isemann Status error = getXPCAuthorization(launch_info); 9032c77eefeSRaphael Isemann if (error.Fail()) 9042c77eefeSRaphael Isemann return error; 9052c77eefeSRaphael Isemann 906a007a6d8SPavel Labath Log *log(GetLog(LLDBLog::Host | LLDBLog::Process)); 9072c77eefeSRaphael Isemann 9082c77eefeSRaphael Isemann uid_t requested_uid = launch_info.GetUserID(); 9092c77eefeSRaphael Isemann const char *xpc_service = nil; 9102c77eefeSRaphael Isemann bool send_auth = false; 9112c77eefeSRaphael Isemann AuthorizationExternalForm extForm; 9122c77eefeSRaphael Isemann if (requested_uid == 0) { 9132c77eefeSRaphael Isemann if (AuthorizationMakeExternalForm(authorizationRef, &extForm) == 9142c77eefeSRaphael Isemann errAuthorizationSuccess) { 9152c77eefeSRaphael Isemann send_auth = true; 9162c77eefeSRaphael Isemann } else { 9170642cd76SAdrian Prantl error = Status(3, eErrorTypeGeneric); 9180642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 9190642cd76SAdrian Prantl "Launching root via XPC needs to " 9202c77eefeSRaphael Isemann "externalize authorization reference."); 9212c77eefeSRaphael Isemann LLDB_LOG(log, "error: {0}", error); 9222c77eefeSRaphael Isemann return error; 9232c77eefeSRaphael Isemann } 9242c77eefeSRaphael Isemann xpc_service = LaunchUsingXPCRightName; 9252c77eefeSRaphael Isemann } else { 9260642cd76SAdrian Prantl error = Status(4, eErrorTypeGeneric); 9270642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 9282c77eefeSRaphael Isemann "Launching via XPC is only currently available for root."); 9292c77eefeSRaphael Isemann LLDB_LOG(log, "error: {0}", error); 9302c77eefeSRaphael Isemann return error; 9312c77eefeSRaphael Isemann } 9322c77eefeSRaphael Isemann 9332c77eefeSRaphael Isemann xpc_connection_t conn = xpc_connection_create(xpc_service, NULL); 9342c77eefeSRaphael Isemann 9352c77eefeSRaphael Isemann xpc_connection_set_event_handler(conn, ^(xpc_object_t event) { 9362c77eefeSRaphael Isemann xpc_type_t type = xpc_get_type(event); 9372c77eefeSRaphael Isemann 9382c77eefeSRaphael Isemann if (type == XPC_TYPE_ERROR) { 9392c77eefeSRaphael Isemann if (event == XPC_ERROR_CONNECTION_INTERRUPTED) { 9402c77eefeSRaphael Isemann // The service has either canceled itself, crashed, or been terminated. 9412c77eefeSRaphael Isemann // The XPC connection is still valid and sending a message to it will 9422c77eefeSRaphael Isemann // re-launch the service. 9432c77eefeSRaphael Isemann // If the service is state-full, this is the time to initialize the new 9442c77eefeSRaphael Isemann // service. 9452c77eefeSRaphael Isemann return; 9462c77eefeSRaphael Isemann } else if (event == XPC_ERROR_CONNECTION_INVALID) { 9472c77eefeSRaphael Isemann // The service is invalid. Either the service name supplied to 9482c77eefeSRaphael Isemann // xpc_connection_create() is incorrect 9492c77eefeSRaphael Isemann // or we (this process) have canceled the service; we can do any cleanup 9502c77eefeSRaphael Isemann // of application state at this point. 9512c77eefeSRaphael Isemann // printf("Service disconnected"); 9522c77eefeSRaphael Isemann return; 9532c77eefeSRaphael Isemann } else { 9542c77eefeSRaphael Isemann // printf("Unexpected error from service: %s", 9552c77eefeSRaphael Isemann // xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); 9562c77eefeSRaphael Isemann } 9572c77eefeSRaphael Isemann 9582c77eefeSRaphael Isemann } else { 9592c77eefeSRaphael Isemann // printf("Received unexpected event in handler"); 9602c77eefeSRaphael Isemann } 9612c77eefeSRaphael Isemann }); 9622c77eefeSRaphael Isemann 963*c7605bfdSJonas Devlieghere xpc_connection_set_finalizer_f(conn, finalize_xpc); 9642c77eefeSRaphael Isemann xpc_connection_resume(conn); 9652c77eefeSRaphael Isemann xpc_object_t message = xpc_dictionary_create(nil, nil, 0); 9662c77eefeSRaphael Isemann 9672c77eefeSRaphael Isemann if (send_auth) { 9682c77eefeSRaphael Isemann xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes, 9692c77eefeSRaphael Isemann sizeof(AuthorizationExternalForm)); 9702c77eefeSRaphael Isemann } 9712c77eefeSRaphael Isemann 9722c77eefeSRaphael Isemann PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey, 9732c77eefeSRaphael Isemann launch_info.GetArguments()); 9742c77eefeSRaphael Isemann PackageXPCEnvironment(message, LauncherXPCServiceEnvPrefxKey, 9752c77eefeSRaphael Isemann launch_info.GetEnvironment()); 9762c77eefeSRaphael Isemann 9772c77eefeSRaphael Isemann // Posix spawn stuff. 9782c77eefeSRaphael Isemann xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey, 9792c77eefeSRaphael Isemann launch_info.GetArchitecture().GetMachOCPUType()); 9802c77eefeSRaphael Isemann xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey, 9812c77eefeSRaphael Isemann GetPosixspawnFlags(launch_info)); 9822c77eefeSRaphael Isemann const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO); 9832c77eefeSRaphael Isemann if (file_action && !file_action->GetPath().empty()) { 9842c77eefeSRaphael Isemann xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey, 9852c77eefeSRaphael Isemann file_action->GetPath().str().c_str()); 9862c77eefeSRaphael Isemann } 9872c77eefeSRaphael Isemann file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); 9882c77eefeSRaphael Isemann if (file_action && !file_action->GetPath().empty()) { 9892c77eefeSRaphael Isemann xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey, 9902c77eefeSRaphael Isemann file_action->GetPath().str().c_str()); 9912c77eefeSRaphael Isemann } 9922c77eefeSRaphael Isemann file_action = launch_info.GetFileActionForFD(STDERR_FILENO); 9932c77eefeSRaphael Isemann if (file_action && !file_action->GetPath().empty()) { 9942c77eefeSRaphael Isemann xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey, 9952c77eefeSRaphael Isemann file_action->GetPath().str().c_str()); 9962c77eefeSRaphael Isemann } 9972c77eefeSRaphael Isemann 9982c77eefeSRaphael Isemann xpc_object_t reply = 9992c77eefeSRaphael Isemann xpc_connection_send_message_with_reply_sync(conn, message); 10002c77eefeSRaphael Isemann xpc_type_t returnType = xpc_get_type(reply); 10012c77eefeSRaphael Isemann if (returnType == XPC_TYPE_DICTIONARY) { 10022c77eefeSRaphael Isemann pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey); 10032c77eefeSRaphael Isemann if (pid == 0) { 10042c77eefeSRaphael Isemann int errorType = 10052c77eefeSRaphael Isemann xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey); 10062c77eefeSRaphael Isemann int errorCode = 10072c77eefeSRaphael Isemann xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey); 10082c77eefeSRaphael Isemann 10090642cd76SAdrian Prantl error = Status(errorCode, eErrorTypeGeneric); 10100642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 10112c77eefeSRaphael Isemann "Problems with launching via XPC. Error type : %i, code : %i", 10122c77eefeSRaphael Isemann errorType, errorCode); 10132c77eefeSRaphael Isemann LLDB_LOG(log, "error: {0}", error); 10142c77eefeSRaphael Isemann 10152c77eefeSRaphael Isemann if (authorizationRef) { 10162c77eefeSRaphael Isemann AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); 10172c77eefeSRaphael Isemann authorizationRef = NULL; 10182c77eefeSRaphael Isemann } 10192c77eefeSRaphael Isemann } 10202c77eefeSRaphael Isemann } else if (returnType == XPC_TYPE_ERROR) { 10210642cd76SAdrian Prantl error = Status(5, eErrorTypeGeneric); 10220642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 10232c77eefeSRaphael Isemann "Problems with launching via XPC. XPC error : %s", 10242c77eefeSRaphael Isemann xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION)); 10252c77eefeSRaphael Isemann LLDB_LOG(log, "error: {0}", error); 10262c77eefeSRaphael Isemann } 10272c77eefeSRaphael Isemann 10282c77eefeSRaphael Isemann return error; 10292c77eefeSRaphael Isemann#else 10302c77eefeSRaphael Isemann Status error; 10312c77eefeSRaphael Isemann return error; 10322c77eefeSRaphael Isemann#endif 10332c77eefeSRaphael Isemann} 10342c77eefeSRaphael Isemann 10352c77eefeSRaphael Isemannstatic bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, 10362c77eefeSRaphael Isemann Log *log, Status &error) { 10372c77eefeSRaphael Isemann if (info == NULL) 10382c77eefeSRaphael Isemann return false; 10392c77eefeSRaphael Isemann 10402c77eefeSRaphael Isemann posix_spawn_file_actions_t *file_actions = 104165fdb342SRaphael Isemann static_cast<posix_spawn_file_actions_t *>(_file_actions); 10422c77eefeSRaphael Isemann 10432c77eefeSRaphael Isemann switch (info->GetAction()) { 10442c77eefeSRaphael Isemann case FileAction::eFileActionNone: 10452c77eefeSRaphael Isemann error.Clear(); 10462c77eefeSRaphael Isemann break; 10472c77eefeSRaphael Isemann 10482c77eefeSRaphael Isemann case FileAction::eFileActionClose: 10492c77eefeSRaphael Isemann if (info->GetFD() == -1) 10500642cd76SAdrian Prantl error = Status::FromErrorString( 10512c77eefeSRaphael Isemann "invalid fd for posix_spawn_file_actions_addclose(...)"); 10522c77eefeSRaphael Isemann else { 10530642cd76SAdrian Prantl error = Status( 10542c77eefeSRaphael Isemann ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), 10552c77eefeSRaphael Isemann eErrorTypePOSIX); 10562c77eefeSRaphael Isemann if (error.Fail()) 10572c77eefeSRaphael Isemann LLDB_LOG(log, 10582c77eefeSRaphael Isemann "error: {0}, posix_spawn_file_actions_addclose " 10592c77eefeSRaphael Isemann "(action={1}, fd={2})", 10602c77eefeSRaphael Isemann error, file_actions, info->GetFD()); 10612c77eefeSRaphael Isemann } 10622c77eefeSRaphael Isemann break; 10632c77eefeSRaphael Isemann 10642c77eefeSRaphael Isemann case FileAction::eFileActionDuplicate: 10652c77eefeSRaphael Isemann if (info->GetFD() == -1) 10660642cd76SAdrian Prantl error = Status::FromErrorString( 10672c77eefeSRaphael Isemann "invalid fd for posix_spawn_file_actions_adddup2(...)"); 10682c77eefeSRaphael Isemann else if (info->GetActionArgument() == -1) 10690642cd76SAdrian Prantl error = Status::FromErrorString( 10702c77eefeSRaphael Isemann "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); 10712c77eefeSRaphael Isemann else { 10720642cd76SAdrian Prantl error = 10730642cd76SAdrian Prantl Status(::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), 10742c77eefeSRaphael Isemann info->GetActionArgument()), 10752c77eefeSRaphael Isemann eErrorTypePOSIX); 10762c77eefeSRaphael Isemann if (error.Fail()) 10772c77eefeSRaphael Isemann LLDB_LOG(log, 10782c77eefeSRaphael Isemann "error: {0}, posix_spawn_file_actions_adddup2 " 10792c77eefeSRaphael Isemann "(action={1}, fd={2}, dup_fd={3})", 10802c77eefeSRaphael Isemann error, file_actions, info->GetFD(), info->GetActionArgument()); 10812c77eefeSRaphael Isemann } 10822c77eefeSRaphael Isemann break; 10832c77eefeSRaphael Isemann 10842c77eefeSRaphael Isemann case FileAction::eFileActionOpen: 10852c77eefeSRaphael Isemann if (info->GetFD() == -1) 10860642cd76SAdrian Prantl error = Status::FromErrorString( 10872c77eefeSRaphael Isemann "invalid fd in posix_spawn_file_actions_addopen(...)"); 10882c77eefeSRaphael Isemann else { 10892c77eefeSRaphael Isemann int oflag = info->GetActionArgument(); 10902c77eefeSRaphael Isemann 10912c77eefeSRaphael Isemann mode_t mode = 0; 10922c77eefeSRaphael Isemann 10932c77eefeSRaphael Isemann if (oflag & O_CREAT) 10942c77eefeSRaphael Isemann mode = 0640; 10952c77eefeSRaphael Isemann 10960642cd76SAdrian Prantl error = Status(::posix_spawn_file_actions_addopen( 10972c77eefeSRaphael Isemann file_actions, info->GetFD(), 10982c77eefeSRaphael Isemann info->GetPath().str().c_str(), oflag, mode), 10992c77eefeSRaphael Isemann eErrorTypePOSIX); 11002c77eefeSRaphael Isemann if (error.Fail()) 11012c77eefeSRaphael Isemann LLDB_LOG(log, 11022c77eefeSRaphael Isemann "error: {0}, posix_spawn_file_actions_addopen (action={1}, " 11032c77eefeSRaphael Isemann "fd={2}, path='{3}', oflag={4}, mode={5})", 11042c77eefeSRaphael Isemann error, file_actions, info->GetFD(), info->GetPath(), oflag, 11052c77eefeSRaphael Isemann mode); 11062c77eefeSRaphael Isemann } 11072c77eefeSRaphael Isemann break; 11082c77eefeSRaphael Isemann } 11092c77eefeSRaphael Isemann return error.Success(); 11102c77eefeSRaphael Isemann} 11112c77eefeSRaphael Isemann 11122c77eefeSRaphael Isemannstatic Status LaunchProcessPosixSpawn(const char *exe_path, 11132c77eefeSRaphael Isemann const ProcessLaunchInfo &launch_info, 11142c77eefeSRaphael Isemann lldb::pid_t &pid) { 11152c77eefeSRaphael Isemann Status error; 1116a007a6d8SPavel Labath Log *log(GetLog(LLDBLog::Host | LLDBLog::Process)); 11172c77eefeSRaphael Isemann 11182c77eefeSRaphael Isemann posix_spawnattr_t attr; 11190642cd76SAdrian Prantl error = Status(::posix_spawnattr_init(&attr), eErrorTypePOSIX); 11202c77eefeSRaphael Isemann 11212c77eefeSRaphael Isemann if (error.Fail()) { 11222c77eefeSRaphael Isemann LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error); 11232c77eefeSRaphael Isemann return error; 11242c77eefeSRaphael Isemann } 11252c77eefeSRaphael Isemann 11262c77eefeSRaphael Isemann // Make sure we clean up the posix spawn attributes before exiting this scope. 1127e0ea8d87SJonas Devlieghere auto cleanup_attr = 1128e0ea8d87SJonas Devlieghere llvm::make_scope_exit([&]() { posix_spawnattr_destroy(&attr); }); 11292c77eefeSRaphael Isemann 11302c77eefeSRaphael Isemann sigset_t no_signals; 11312c77eefeSRaphael Isemann sigset_t all_signals; 11322c77eefeSRaphael Isemann sigemptyset(&no_signals); 11332c77eefeSRaphael Isemann sigfillset(&all_signals); 11342c77eefeSRaphael Isemann ::posix_spawnattr_setsigmask(&attr, &no_signals); 11352c77eefeSRaphael Isemann ::posix_spawnattr_setsigdefault(&attr, &all_signals); 11362c77eefeSRaphael Isemann 11372c77eefeSRaphael Isemann short flags = GetPosixspawnFlags(launch_info); 11382c77eefeSRaphael Isemann 11390642cd76SAdrian Prantl error = Status(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX); 11402c77eefeSRaphael Isemann if (error.Fail()) { 11412c77eefeSRaphael Isemann LLDB_LOG(log, 11422c77eefeSRaphael Isemann "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )", 11432c77eefeSRaphael Isemann error, flags); 11442c77eefeSRaphael Isemann return error; 11452c77eefeSRaphael Isemann } 11462c77eefeSRaphael Isemann 1147041c7b84SJonas Devlieghere bool is_graphical = true; 1148041c7b84SJonas Devlieghere 1149041c7b84SJonas Devlieghere#if TARGET_OS_OSX 1150041c7b84SJonas Devlieghere SecuritySessionId session_id; 1151041c7b84SJonas Devlieghere SessionAttributeBits session_attributes; 1152041c7b84SJonas Devlieghere OSStatus status = 1153041c7b84SJonas Devlieghere SessionGetInfo(callerSecuritySession, &session_id, &session_attributes); 1154041c7b84SJonas Devlieghere if (status == errSessionSuccess) 1155041c7b84SJonas Devlieghere is_graphical = session_attributes & sessionHasGraphicAccess; 1156041c7b84SJonas Devlieghere#endif 1157041c7b84SJonas Devlieghere 1158249a1d4fSJonas Devlieghere // When lldb is ran through a graphical session, make the debuggee process 1159249a1d4fSJonas Devlieghere // responsible for its own TCC permissions instead of inheriting them from 1160249a1d4fSJonas Devlieghere // its parent. 1161249a1d4fSJonas Devlieghere if (is_graphical && launch_info.GetFlags().Test(eLaunchFlagDebug) && 1162249a1d4fSJonas Devlieghere !launch_info.GetFlags().Test(eLaunchFlagInheritTCCFromParent)) { 11630642cd76SAdrian Prantl error = Status(setup_posix_spawn_responsible_flag(&attr), eErrorTypePOSIX); 1164041c7b84SJonas Devlieghere if (error.Fail()) { 1165041c7b84SJonas Devlieghere LLDB_LOG(log, "error: {0}, setup_posix_spawn_responsible_flag(&attr)", 1166041c7b84SJonas Devlieghere error); 1167041c7b84SJonas Devlieghere return error; 1168041c7b84SJonas Devlieghere } 1169041c7b84SJonas Devlieghere } 1170041c7b84SJonas Devlieghere 117198e50a7dSJonas Devlieghere // Don't set the binpref if a shell was provided. After all, that's only 117298e50a7dSJonas Devlieghere // going to affect what version of the shell is launched, not what fork of 117398e50a7dSJonas Devlieghere // the binary is launched. We insert "arch --arch <ARCH> as part of the 117498e50a7dSJonas Devlieghere // shell invocation to do that job on OSX. 117598e50a7dSJonas Devlieghere if (launch_info.GetShell() == FileSpec()) { 117698e50a7dSJonas Devlieghere const ArchSpec &arch_spec = launch_info.GetArchitecture(); 117798e50a7dSJonas Devlieghere cpu_type_t cpu_type = arch_spec.GetMachOCPUType(); 117898e50a7dSJonas Devlieghere cpu_type_t cpu_subtype = arch_spec.GetMachOCPUSubType(); 117998e50a7dSJonas Devlieghere const bool set_cpu_type = 118098e50a7dSJonas Devlieghere cpu_type != 0 && cpu_type != static_cast<cpu_type_t>(UINT32_MAX) && 118198e50a7dSJonas Devlieghere cpu_type != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE); 118298e50a7dSJonas Devlieghere const bool set_cpu_subtype = 118398e50a7dSJonas Devlieghere cpu_subtype != 0 && 118498e50a7dSJonas Devlieghere cpu_subtype != static_cast<cpu_subtype_t>(UINT32_MAX) && 118598e50a7dSJonas Devlieghere cpu_subtype != CPU_SUBTYPE_X86_64_H; 118698e50a7dSJonas Devlieghere if (set_cpu_type) { 118798e50a7dSJonas Devlieghere size_t ocount = 0; 118898e50a7dSJonas Devlieghere typedef int (*posix_spawnattr_setarchpref_np_t)( 118998e50a7dSJonas Devlieghere posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *); 119098e50a7dSJonas Devlieghere posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn = 119198e50a7dSJonas Devlieghere (posix_spawnattr_setarchpref_np_t)dlsym( 119298e50a7dSJonas Devlieghere RTLD_DEFAULT, "posix_spawnattr_setarchpref_np"); 119398e50a7dSJonas Devlieghere if (set_cpu_subtype && posix_spawnattr_setarchpref_np_fn) { 11940642cd76SAdrian Prantl error = Status((*posix_spawnattr_setarchpref_np_fn)( 119598e50a7dSJonas Devlieghere &attr, 1, &cpu_type, &cpu_subtype, &ocount), 119698e50a7dSJonas Devlieghere eErrorTypePOSIX); 119798e50a7dSJonas Devlieghere if (error.Fail()) 119898e50a7dSJonas Devlieghere LLDB_LOG(log, 119998e50a7dSJonas Devlieghere "error: {0}, ::posix_spawnattr_setarchpref_np ( &attr, 1, " 120098e50a7dSJonas Devlieghere "cpu_type = {1:x}, cpu_subtype = {1:x}, count => {2} )", 120198e50a7dSJonas Devlieghere error, cpu_type, cpu_subtype, ocount); 120298e50a7dSJonas Devlieghere 120398e50a7dSJonas Devlieghere if (error.Fail() || ocount != 1) 120498e50a7dSJonas Devlieghere return error; 120598e50a7dSJonas Devlieghere } else { 12060642cd76SAdrian Prantl error = Status( 120798e50a7dSJonas Devlieghere ::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount), 120898e50a7dSJonas Devlieghere eErrorTypePOSIX); 120998e50a7dSJonas Devlieghere if (error.Fail()) 121098e50a7dSJonas Devlieghere LLDB_LOG(log, 121198e50a7dSJonas Devlieghere "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, " 121298e50a7dSJonas Devlieghere "cpu_type = {1:x}, count => {2} )", 121398e50a7dSJonas Devlieghere error, cpu_type, ocount); 121498e50a7dSJonas Devlieghere if (error.Fail() || ocount != 1) 121598e50a7dSJonas Devlieghere return error; 121698e50a7dSJonas Devlieghere } 121798e50a7dSJonas Devlieghere } 121898e50a7dSJonas Devlieghere } 121998e50a7dSJonas Devlieghere 12202c77eefeSRaphael Isemann const char *tmp_argv[2]; 12212c77eefeSRaphael Isemann char *const *argv = const_cast<char *const *>( 12222c77eefeSRaphael Isemann launch_info.GetArguments().GetConstArgumentVector()); 12232c77eefeSRaphael Isemann Environment::Envp envp = launch_info.GetEnvironment().getEnvp(); 12242c77eefeSRaphael Isemann if (argv == NULL) { 12252c77eefeSRaphael Isemann // posix_spawn gets very unhappy if it doesn't have at least the program 12262c77eefeSRaphael Isemann // name in argv[0]. One of the side affects I have noticed is the 12272c77eefeSRaphael Isemann // environment 12282c77eefeSRaphael Isemann // variables don't make it into the child process if "argv == NULL"!!! 12292c77eefeSRaphael Isemann tmp_argv[0] = exe_path; 12302c77eefeSRaphael Isemann tmp_argv[1] = NULL; 12312c77eefeSRaphael Isemann argv = const_cast<char *const *>(tmp_argv); 12322c77eefeSRaphael Isemann } 12332c77eefeSRaphael Isemann 12342c77eefeSRaphael Isemann FileSpec working_dir{launch_info.GetWorkingDirectory()}; 12352c77eefeSRaphael Isemann if (working_dir) { 12362c77eefeSRaphael Isemann // Set the working directory on this thread only 1237529a3d87SGreg Clayton std::string working_dir_path = working_dir.GetPath(); 1238529a3d87SGreg Clayton if (__pthread_chdir(working_dir_path.c_str()) < 0) { 12392c77eefeSRaphael Isemann if (errno == ENOENT) { 12400642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 12410642cd76SAdrian Prantl "No such file or directory: %s", working_dir_path.c_str()); 12422c77eefeSRaphael Isemann } else if (errno == ENOTDIR) { 12430642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 12440642cd76SAdrian Prantl "Path doesn't name a directory: %s", working_dir_path.c_str()); 12452c77eefeSRaphael Isemann } else { 12460642cd76SAdrian Prantl error = 12470642cd76SAdrian Prantl Status::FromErrorStringWithFormat("An unknown error occurred when " 12482c77eefeSRaphael Isemann "changing directory for process " 12492c77eefeSRaphael Isemann "execution."); 12502c77eefeSRaphael Isemann } 12512c77eefeSRaphael Isemann return error; 12522c77eefeSRaphael Isemann } 12532c77eefeSRaphael Isemann } 12542c77eefeSRaphael Isemann 12552c77eefeSRaphael Isemann ::pid_t result_pid = LLDB_INVALID_PROCESS_ID; 12562c77eefeSRaphael Isemann const size_t num_file_actions = launch_info.GetNumFileActions(); 12572c77eefeSRaphael Isemann if (num_file_actions > 0) { 12582c77eefeSRaphael Isemann posix_spawn_file_actions_t file_actions; 12590642cd76SAdrian Prantl error = 12600642cd76SAdrian Prantl Status(::posix_spawn_file_actions_init(&file_actions), eErrorTypePOSIX); 12612c77eefeSRaphael Isemann if (error.Fail()) { 12622c77eefeSRaphael Isemann LLDB_LOG(log, 12632c77eefeSRaphael Isemann "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )", 12642c77eefeSRaphael Isemann error); 12652c77eefeSRaphael Isemann return error; 12662c77eefeSRaphael Isemann } 12672c77eefeSRaphael Isemann 12682c77eefeSRaphael Isemann // Make sure we clean up the posix file actions before exiting this scope. 1269e0ea8d87SJonas Devlieghere auto cleanup_fileact = llvm::make_scope_exit( 1270e0ea8d87SJonas Devlieghere [&]() { posix_spawn_file_actions_destroy(&file_actions); }); 12712c77eefeSRaphael Isemann 12722c77eefeSRaphael Isemann for (size_t i = 0; i < num_file_actions; ++i) { 12732c77eefeSRaphael Isemann const FileAction *launch_file_action = 12742c77eefeSRaphael Isemann launch_info.GetFileActionAtIndex(i); 12752c77eefeSRaphael Isemann if (launch_file_action) { 12762c77eefeSRaphael Isemann if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, 12772c77eefeSRaphael Isemann error)) 12782c77eefeSRaphael Isemann return error; 12792c77eefeSRaphael Isemann } 12802c77eefeSRaphael Isemann } 12812c77eefeSRaphael Isemann 12820642cd76SAdrian Prantl error = Status( 12832c77eefeSRaphael Isemann ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), 12842c77eefeSRaphael Isemann eErrorTypePOSIX); 12852c77eefeSRaphael Isemann 12862c77eefeSRaphael Isemann if (error.Fail()) { 12872c77eefeSRaphael Isemann LLDB_LOG(log, 12882c77eefeSRaphael Isemann "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', " 12892c77eefeSRaphael Isemann "file_actions = {3}, " 12902c77eefeSRaphael Isemann "attr = {4}, argv = {5}, envp = {6} )", 12912c77eefeSRaphael Isemann error, result_pid, exe_path, &file_actions, &attr, argv, 12922c77eefeSRaphael Isemann envp.get()); 12932c77eefeSRaphael Isemann if (log) { 12942c77eefeSRaphael Isemann for (int ii = 0; argv[ii]; ++ii) 12952c77eefeSRaphael Isemann LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]); 12962c77eefeSRaphael Isemann } 12972c77eefeSRaphael Isemann } 12982c77eefeSRaphael Isemann 12992c77eefeSRaphael Isemann } else { 13000642cd76SAdrian Prantl error = 13010642cd76SAdrian Prantl Status(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), 13022c77eefeSRaphael Isemann eErrorTypePOSIX); 13032c77eefeSRaphael Isemann 13042c77eefeSRaphael Isemann if (error.Fail()) { 13052c77eefeSRaphael Isemann LLDB_LOG(log, 13062c77eefeSRaphael Isemann "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', " 13072c77eefeSRaphael Isemann "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )", 13082c77eefeSRaphael Isemann error, result_pid, exe_path, &attr, argv, envp.get()); 13092c77eefeSRaphael Isemann if (log) { 13102c77eefeSRaphael Isemann for (int ii = 0; argv[ii]; ++ii) 13112c77eefeSRaphael Isemann LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]); 13122c77eefeSRaphael Isemann } 13132c77eefeSRaphael Isemann } 13142c77eefeSRaphael Isemann } 13152c77eefeSRaphael Isemann pid = result_pid; 13162c77eefeSRaphael Isemann 13172c77eefeSRaphael Isemann if (working_dir) { 13182c77eefeSRaphael Isemann // No more thread specific current working directory 13192c77eefeSRaphael Isemann __pthread_fchdir(-1); 13202c77eefeSRaphael Isemann } 13212c77eefeSRaphael Isemann 13222c77eefeSRaphael Isemann return error; 13232c77eefeSRaphael Isemann} 13242c77eefeSRaphael Isemann 13252c77eefeSRaphael Isemannstatic bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) { 13262c77eefeSRaphael Isemann bool result = false; 13272c77eefeSRaphael Isemann 1328f203100eSVedant Kumar#if TARGET_OS_OSX 13292c77eefeSRaphael Isemann bool launchingAsRoot = launch_info.GetUserID() == 0; 13302c77eefeSRaphael Isemann bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0; 13312c77eefeSRaphael Isemann 13322c77eefeSRaphael Isemann if (launchingAsRoot && !currentUserIsRoot) { 13332c77eefeSRaphael Isemann // If current user is already root, we don't need XPC's help. 13342c77eefeSRaphael Isemann result = true; 13352c77eefeSRaphael Isemann } 13362c77eefeSRaphael Isemann#endif 13372c77eefeSRaphael Isemann 13382c77eefeSRaphael Isemann return result; 13392c77eefeSRaphael Isemann} 13402c77eefeSRaphael Isemann 13412c77eefeSRaphael IsemannStatus Host::LaunchProcess(ProcessLaunchInfo &launch_info) { 13422c77eefeSRaphael Isemann Status error; 1343046c3903SJonas Devlieghere 1344046c3903SJonas Devlieghere FileSystem &fs = FileSystem::Instance(); 13452c77eefeSRaphael Isemann FileSpec exe_spec(launch_info.GetExecutableFile()); 13462c77eefeSRaphael Isemann 1347046c3903SJonas Devlieghere if (!fs.Exists(exe_spec)) 13488f3be7a3SJonas Devlieghere FileSystem::Instance().Resolve(exe_spec); 1349046c3903SJonas Devlieghere 1350046c3903SJonas Devlieghere if (!fs.Exists(exe_spec)) 13512c22c800SJonas Devlieghere FileSystem::Instance().ResolveExecutableLocation(exe_spec); 1352046c3903SJonas Devlieghere 1353046c3903SJonas Devlieghere if (!fs.Exists(exe_spec)) { 13540642cd76SAdrian Prantl error = Status::FromErrorStringWithFormatv( 13550642cd76SAdrian Prantl "executable doesn't exist: '{0}'", exe_spec); 13562c77eefeSRaphael Isemann return error; 13572c77eefeSRaphael Isemann } 13582c77eefeSRaphael Isemann 13592c77eefeSRaphael Isemann if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) { 1360f203100eSVedant Kumar#if TARGET_OS_OSX 13612c77eefeSRaphael Isemann return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(), 13622c77eefeSRaphael Isemann launch_info); 13632c77eefeSRaphael Isemann#else 13640642cd76SAdrian Prantl error = 13650642cd76SAdrian Prantl Status::FromErrorString("launching a process in a new terminal is not " 13662c77eefeSRaphael Isemann "supported on iOS devices"); 13672c77eefeSRaphael Isemann return error; 13682c77eefeSRaphael Isemann#endif 13692c77eefeSRaphael Isemann } 13702c77eefeSRaphael Isemann 13712c77eefeSRaphael Isemann lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 13722c77eefeSRaphael Isemann 137359eb7052SJonas Devlieghere auto exe_path = exe_spec.GetPath(); 137446575176SJonas Devlieghere 137546575176SJonas Devlieghere if (ShouldLaunchUsingXPC(launch_info)) 137659eb7052SJonas Devlieghere error = LaunchProcessXPC(exe_path.c_str(), launch_info, pid); 137746575176SJonas Devlieghere else 137859eb7052SJonas Devlieghere error = LaunchProcessPosixSpawn(exe_path.c_str(), launch_info, pid); 13792c77eefeSRaphael Isemann 13802c77eefeSRaphael Isemann if (pid != LLDB_INVALID_PROCESS_ID) { 13812c77eefeSRaphael Isemann // If all went well, then set the process ID into the launch info 13822c77eefeSRaphael Isemann launch_info.SetProcessID(pid); 13832c77eefeSRaphael Isemann 13842c77eefeSRaphael Isemann // Make sure we reap any processes we spawn or we will have zombies. 13852c77eefeSRaphael Isemann bool monitoring = launch_info.MonitorProcess(); 13862c77eefeSRaphael Isemann UNUSED_IF_ASSERT_DISABLED(monitoring); 13872c77eefeSRaphael Isemann assert(monitoring); 13882c77eefeSRaphael Isemann } else { 13892c77eefeSRaphael Isemann // Invalid process ID, something didn't go well 13902c77eefeSRaphael Isemann if (error.Success()) 13910642cd76SAdrian Prantl error = 13920642cd76SAdrian Prantl Status::FromErrorString("process launch failed for unknown reasons"); 13932c77eefeSRaphael Isemann } 13942c77eefeSRaphael Isemann return error; 13952c77eefeSRaphael Isemann} 13962c77eefeSRaphael Isemann 13972c77eefeSRaphael IsemannStatus Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { 13982c77eefeSRaphael Isemann Status error; 13992c77eefeSRaphael Isemann if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) { 1400f918c056SKeith Smiley FileSpec expand_tool_spec; 1401f918c056SKeith Smiley Environment host_env = Host::GetEnvironment(); 1402f918c056SKeith Smiley std::string env_argdumper_path = host_env.lookup("LLDB_ARGDUMPER_PATH"); 1403f918c056SKeith Smiley if (!env_argdumper_path.empty()) { 1404f918c056SKeith Smiley expand_tool_spec.SetFile(env_argdumper_path, FileSpec::Style::native); 1405f918c056SKeith Smiley Log *log(GetLog(LLDBLog::Host | LLDBLog::Process)); 1406f918c056SKeith Smiley LLDB_LOGF(log, 1407f918c056SKeith Smiley "lldb-argdumper exe path set from environment variable: %s", 1408f918c056SKeith Smiley env_argdumper_path.c_str()); 1409f918c056SKeith Smiley } 1410f918c056SKeith Smiley bool argdumper_exists = FileSystem::Instance().Exists(env_argdumper_path); 1411f918c056SKeith Smiley if (!argdumper_exists) { 1412f918c056SKeith Smiley expand_tool_spec = HostInfo::GetSupportExeDir(); 141360f028ffSPavel Labath if (!expand_tool_spec) { 14140642cd76SAdrian Prantl error = Status::FromErrorString( 14150642cd76SAdrian Prantl "could not get support executable directory for " 1416f918c056SKeith Smiley "lldb-argdumper tool"); 14172c77eefeSRaphael Isemann return error; 14182c77eefeSRaphael Isemann } 14192c77eefeSRaphael Isemann expand_tool_spec.AppendPathComponent("lldb-argdumper"); 1420dbd7fabaSJonas Devlieghere if (!FileSystem::Instance().Exists(expand_tool_spec)) { 14210642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 14222c77eefeSRaphael Isemann "could not find the lldb-argdumper tool: %s", 14232c77eefeSRaphael Isemann expand_tool_spec.GetPath().c_str()); 14242c77eefeSRaphael Isemann return error; 14252c77eefeSRaphael Isemann } 1426f918c056SKeith Smiley } 14272c77eefeSRaphael Isemann 14282c77eefeSRaphael Isemann StreamString expand_tool_spec_stream; 14292c77eefeSRaphael Isemann expand_tool_spec_stream.Printf("\"%s\"", 14302c77eefeSRaphael Isemann expand_tool_spec.GetPath().c_str()); 14312c77eefeSRaphael Isemann 14322c77eefeSRaphael Isemann Args expand_command(expand_tool_spec_stream.GetData()); 14332c77eefeSRaphael Isemann expand_command.AppendArguments(launch_info.GetArguments()); 14342c77eefeSRaphael Isemann 14352c77eefeSRaphael Isemann int status; 14362c77eefeSRaphael Isemann std::string output; 14372c77eefeSRaphael Isemann FileSpec cwd(launch_info.GetWorkingDirectory()); 1438dbd7fabaSJonas Devlieghere if (!FileSystem::Instance().Exists(cwd)) { 14392c77eefeSRaphael Isemann char *wd = getcwd(nullptr, 0); 14402c77eefeSRaphael Isemann if (wd == nullptr) { 14410642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 14422c77eefeSRaphael Isemann "cwd does not exist; cannot launch with shell argument expansion"); 14432c77eefeSRaphael Isemann return error; 14442c77eefeSRaphael Isemann } else { 14458f3be7a3SJonas Devlieghere FileSpec working_dir(wd); 14462c77eefeSRaphael Isemann free(wd); 14472c77eefeSRaphael Isemann launch_info.SetWorkingDirectory(working_dir); 14482c77eefeSRaphael Isemann } 14492c77eefeSRaphael Isemann } 1450addb5148SMed Ismail Bennani bool run_in_shell = true; 1451b1a5d7d5SAdrian Prantl bool hide_stderr = true; 1452addb5148SMed Ismail Bennani Status e = 1453addb5148SMed Ismail Bennani RunShellCommand(expand_command, cwd, &status, nullptr, &output, 1454addb5148SMed Ismail Bennani std::chrono::seconds(10), run_in_shell, hide_stderr); 14552c77eefeSRaphael Isemann 14562a711814SJonas Devlieghere if (e.Fail()) 14572a711814SJonas Devlieghere return e; 1458a8c04469SJonas Devlieghere 14592c77eefeSRaphael Isemann if (status != 0) { 14600642cd76SAdrian Prantl error = Status::FromErrorStringWithFormat( 14610642cd76SAdrian Prantl "lldb-argdumper exited with error %d", status); 14622c77eefeSRaphael Isemann return error; 14632c77eefeSRaphael Isemann } 14642c77eefeSRaphael Isemann 14652c77eefeSRaphael Isemann auto data_sp = StructuredData::ParseJSON(output); 14662c77eefeSRaphael Isemann if (!data_sp) { 14670642cd76SAdrian Prantl error = Status::FromErrorString("invalid JSON"); 14682c77eefeSRaphael Isemann return error; 14692c77eefeSRaphael Isemann } 14702c77eefeSRaphael Isemann 14712c77eefeSRaphael Isemann auto dict_sp = data_sp->GetAsDictionary(); 14722c77eefeSRaphael Isemann if (!data_sp) { 14730642cd76SAdrian Prantl error = Status::FromErrorString("invalid JSON"); 14742c77eefeSRaphael Isemann return error; 14752c77eefeSRaphael Isemann } 14762c77eefeSRaphael Isemann 14772c77eefeSRaphael Isemann auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments"); 14782c77eefeSRaphael Isemann if (!args_sp) { 14790642cd76SAdrian Prantl error = Status::FromErrorString("invalid JSON"); 14802c77eefeSRaphael Isemann return error; 14812c77eefeSRaphael Isemann } 14822c77eefeSRaphael Isemann 14832c77eefeSRaphael Isemann auto args_array_sp = args_sp->GetAsArray(); 14842c77eefeSRaphael Isemann if (!args_array_sp) { 14850642cd76SAdrian Prantl error = Status::FromErrorString("invalid JSON"); 14862c77eefeSRaphael Isemann return error; 14872c77eefeSRaphael Isemann } 14882c77eefeSRaphael Isemann 14892c77eefeSRaphael Isemann launch_info.GetArguments().Clear(); 14902c77eefeSRaphael Isemann 14912c77eefeSRaphael Isemann for (size_t i = 0; i < args_array_sp->GetSize(); i++) { 14922c77eefeSRaphael Isemann auto item_sp = args_array_sp->GetItemAtIndex(i); 14932c77eefeSRaphael Isemann if (!item_sp) 14942c77eefeSRaphael Isemann continue; 14952c77eefeSRaphael Isemann auto str_sp = item_sp->GetAsString(); 14962c77eefeSRaphael Isemann if (!str_sp) 14972c77eefeSRaphael Isemann continue; 14982c77eefeSRaphael Isemann 14992c77eefeSRaphael Isemann launch_info.GetArguments().AppendArgument(str_sp->GetValue()); 15002c77eefeSRaphael Isemann } 15012c77eefeSRaphael Isemann } 15022c77eefeSRaphael Isemann 15032c77eefeSRaphael Isemann return error; 15042c77eefeSRaphael Isemann} 15052c77eefeSRaphael Isemann 15062734f5c8SJonas Devliegherellvm::Expected<HostThread> Host::StartMonitoringChildProcess( 150712c9c4a8SPavel Labath const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) { 15082c77eefeSRaphael Isemann unsigned long mask = DISPATCH_PROC_EXIT; 15092c77eefeSRaphael Isemann 1510a007a6d8SPavel Labath Log *log(GetLog(LLDBLog::Host | LLDBLog::Process)); 15112c77eefeSRaphael Isemann 15122c77eefeSRaphael Isemann dispatch_source_t source = ::dispatch_source_create( 15132c77eefeSRaphael Isemann DISPATCH_SOURCE_TYPE_PROC, pid, mask, 15142c77eefeSRaphael Isemann ::dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 15152c77eefeSRaphael Isemann 151663e5fb76SJonas Devlieghere LLDB_LOGF(log, 151712c9c4a8SPavel Labath "Host::StartMonitoringChildProcess(callback, pid=%i) source = %p\n", 151812c9c4a8SPavel Labath static_cast<int>(pid), static_cast<void *>(source)); 15192c77eefeSRaphael Isemann 15202c77eefeSRaphael Isemann if (source) { 15212c77eefeSRaphael Isemann Host::MonitorChildProcessCallback callback_copy = callback; 15222c77eefeSRaphael Isemann ::dispatch_source_set_cancel_handler(source, ^{ 15232c77eefeSRaphael Isemann dispatch_release(source); 15242c77eefeSRaphael Isemann }); 15252c77eefeSRaphael Isemann ::dispatch_source_set_event_handler(source, ^{ 15262c77eefeSRaphael Isemann 15272c77eefeSRaphael Isemann int status = 0; 15282c77eefeSRaphael Isemann int wait_pid = 0; 15292c77eefeSRaphael Isemann wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, 0); 15302c77eefeSRaphael Isemann if (wait_pid >= 0) { 15312c77eefeSRaphael Isemann int signal = 0; 15322c77eefeSRaphael Isemann int exit_status = 0; 15332c77eefeSRaphael Isemann const char *status_cstr = NULL; 153412c9c4a8SPavel Labath if (WIFEXITED(status)) { 15352c77eefeSRaphael Isemann exit_status = WEXITSTATUS(status); 15362c77eefeSRaphael Isemann status_cstr = "EXITED"; 15372c77eefeSRaphael Isemann } else if (WIFSIGNALED(status)) { 15382c77eefeSRaphael Isemann signal = WTERMSIG(status); 15392c77eefeSRaphael Isemann status_cstr = "SIGNALED"; 15402c77eefeSRaphael Isemann exit_status = -1; 15412c77eefeSRaphael Isemann } else { 154212c9c4a8SPavel Labath llvm_unreachable("Unknown status"); 15432c77eefeSRaphael Isemann } 15442c77eefeSRaphael Isemann 154563e5fb76SJonas Devlieghere LLDB_LOGF(log, 154663e5fb76SJonas Devlieghere "::waitpid (pid = %llu, &status, 0) => pid = %i, status " 15472c77eefeSRaphael Isemann "= 0x%8.8x (%s), signal = %i, exit_status = %i", 15482c77eefeSRaphael Isemann pid, wait_pid, status, status_cstr, signal, exit_status); 15492c77eefeSRaphael Isemann 15502c77eefeSRaphael Isemann if (callback_copy) 155112c9c4a8SPavel Labath callback_copy(pid, signal, exit_status); 15522c77eefeSRaphael Isemann 15532c77eefeSRaphael Isemann ::dispatch_source_cancel(source); 15542c77eefeSRaphael Isemann } 15552c77eefeSRaphael Isemann }); 15562c77eefeSRaphael Isemann 15572c77eefeSRaphael Isemann ::dispatch_resume(source); 15582c77eefeSRaphael Isemann } 15592c77eefeSRaphael Isemann return HostThread(); 15602c77eefeSRaphael Isemann} 1561