xref: /openbsd-src/gnu/llvm/lldb/source/Host/macosx/objcxx/Host.mm (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrick//===-- Host.mm -------------------------------------------------*- C++ -*-===//
2061da546Spatrick//
3061da546Spatrick// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick// See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick//
7061da546Spatrick//===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick#include "lldb/Host/Host.h"
10be691f3bSpatrick#include "PosixSpawnResponsible.h"
11061da546Spatrick
12061da546Spatrick#include <AvailabilityMacros.h>
13dda28197Spatrick#include <TargetConditionals.h>
14061da546Spatrick
15dda28197Spatrick#if TARGET_OS_OSX
16061da546Spatrick#define __XPC_PRIVATE_H__
17061da546Spatrick#include <xpc/xpc.h>
18061da546Spatrick
19061da546Spatrick#define LaunchUsingXPCRightName "com.apple.lldb.RootDebuggingXPCService"
20061da546Spatrick
21061da546Spatrick// These XPC messaging keys are used for communication between Host.mm and the
22061da546Spatrick// XPC service.
23061da546Spatrick#define LauncherXPCServiceAuthKey "auth-key"
24061da546Spatrick#define LauncherXPCServiceArgPrefxKey "arg"
25061da546Spatrick#define LauncherXPCServiceEnvPrefxKey "env"
26061da546Spatrick#define LauncherXPCServiceCPUTypeKey "cpuType"
27061da546Spatrick#define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags"
28061da546Spatrick#define LauncherXPCServiceStdInPathKeyKey "stdInPath"
29061da546Spatrick#define LauncherXPCServiceStdOutPathKeyKey "stdOutPath"
30061da546Spatrick#define LauncherXPCServiceStdErrPathKeyKey "stdErrPath"
31061da546Spatrick#define LauncherXPCServiceChildPIDKey "childPID"
32061da546Spatrick#define LauncherXPCServiceErrorTypeKey "errorType"
33061da546Spatrick#define LauncherXPCServiceCodeTypeKey "errorCode"
34061da546Spatrick
35*f6aab3d8Srobert#include <bsm/audit.h>
36*f6aab3d8Srobert#include <bsm/audit_session.h>
37061da546Spatrick#endif
38061da546Spatrick
39061da546Spatrick#include "llvm/Support/Host.h"
40061da546Spatrick
41061da546Spatrick#include <asl.h>
42061da546Spatrick#include <crt_externs.h>
43be691f3bSpatrick#include <cstdio>
44be691f3bSpatrick#include <cstdlib>
45be691f3bSpatrick#include <dlfcn.h>
46061da546Spatrick#include <grp.h>
47061da546Spatrick#include <libproc.h>
48061da546Spatrick#include <pwd.h>
49061da546Spatrick#include <spawn.h>
50061da546Spatrick#include <sys/proc.h>
51061da546Spatrick#include <sys/stat.h>
52061da546Spatrick#include <sys/sysctl.h>
53061da546Spatrick#include <sys/types.h>
54061da546Spatrick#include <unistd.h>
55061da546Spatrick
56061da546Spatrick#include "lldb/Host/ConnectionFileDescriptor.h"
57061da546Spatrick#include "lldb/Host/FileSystem.h"
58061da546Spatrick#include "lldb/Host/HostInfo.h"
59061da546Spatrick#include "lldb/Host/ProcessLaunchInfo.h"
60061da546Spatrick#include "lldb/Host/ThreadLauncher.h"
61061da546Spatrick#include "lldb/Utility/ArchSpec.h"
62*f6aab3d8Srobert#include "lldb/Utility/LLDBLog.h"
63061da546Spatrick#include "lldb/Utility/DataBufferHeap.h"
64061da546Spatrick#include "lldb/Utility/DataExtractor.h"
65061da546Spatrick#include "lldb/Utility/Endian.h"
66061da546Spatrick#include "lldb/Utility/FileSpec.h"
67061da546Spatrick#include "lldb/Utility/Log.h"
68061da546Spatrick#include "lldb/Utility/NameMatches.h"
69061da546Spatrick#include "lldb/Utility/ProcessInfo.h"
70061da546Spatrick#include "lldb/Utility/StreamString.h"
71061da546Spatrick#include "lldb/Utility/StructuredData.h"
72061da546Spatrick#include "lldb/lldb-defines.h"
73061da546Spatrick
74061da546Spatrick#include "llvm/ADT/ScopeExit.h"
75061da546Spatrick#include "llvm/Support/Errno.h"
76061da546Spatrick#include "llvm/Support/FileSystem.h"
77061da546Spatrick
78061da546Spatrick#include "../cfcpp/CFCBundle.h"
79061da546Spatrick#include "../cfcpp/CFCMutableArray.h"
80061da546Spatrick#include "../cfcpp/CFCMutableDictionary.h"
81061da546Spatrick#include "../cfcpp/CFCReleaser.h"
82061da546Spatrick#include "../cfcpp/CFCString.h"
83061da546Spatrick
84061da546Spatrick#include <objc/objc-auto.h>
85*f6aab3d8Srobert#include <os/log.h>
86061da546Spatrick
87061da546Spatrick#include <CoreFoundation/CoreFoundation.h>
88061da546Spatrick#include <Foundation/Foundation.h>
89061da546Spatrick
90061da546Spatrick#ifndef _POSIX_SPAWN_DISABLE_ASLR
91061da546Spatrick#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
92061da546Spatrick#endif
93061da546Spatrick
94061da546Spatrickextern "C" {
95061da546Spatrickint __pthread_chdir(const char *path);
96061da546Spatrickint __pthread_fchdir(int fildes);
97061da546Spatrick}
98061da546Spatrick
99061da546Spatrickusing namespace lldb;
100061da546Spatrickusing namespace lldb_private;
101061da546Spatrick
102*f6aab3d8Srobertstatic os_log_t g_os_log;
103*f6aab3d8Srobertstatic std::once_flag g_os_log_once;
104*f6aab3d8Srobert
105*f6aab3d8Srobertvoid Host::SystemLog(llvm::StringRef message) {
106*f6aab3d8Srobert  if (__builtin_available(macos 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
107*f6aab3d8Srobert    std::call_once(g_os_log_once, []() {
108*f6aab3d8Srobert      g_os_log = os_log_create("com.apple.dt.lldb", "lldb");
109*f6aab3d8Srobert    });
110*f6aab3d8Srobert    os_log(g_os_log, "%{public}s", message.str().c_str());
111*f6aab3d8Srobert  } else {
112*f6aab3d8Srobert    llvm::errs() << message;
113*f6aab3d8Srobert  }
114*f6aab3d8Srobert}
115*f6aab3d8Srobert
116061da546Spatrickbool Host::GetBundleDirectory(const FileSpec &file,
117061da546Spatrick                              FileSpec &bundle_directory) {
118061da546Spatrick#if defined(__APPLE__)
119061da546Spatrick  if (FileSystem::Instance().IsDirectory(file)) {
120061da546Spatrick    char path[PATH_MAX];
121061da546Spatrick    if (file.GetPath(path, sizeof(path))) {
122061da546Spatrick      CFCBundle bundle(path);
123061da546Spatrick      if (bundle.GetPath(path, sizeof(path))) {
124061da546Spatrick        bundle_directory.SetFile(path, FileSpec::Style::native);
125061da546Spatrick        return true;
126061da546Spatrick      }
127061da546Spatrick    }
128061da546Spatrick  }
129061da546Spatrick#endif
130061da546Spatrick  bundle_directory.Clear();
131061da546Spatrick  return false;
132061da546Spatrick}
133061da546Spatrick
134061da546Spatrickbool Host::ResolveExecutableInBundle(FileSpec &file) {
135061da546Spatrick#if defined(__APPLE__)
136061da546Spatrick  if (FileSystem::Instance().IsDirectory(file)) {
137061da546Spatrick    char path[PATH_MAX];
138061da546Spatrick    if (file.GetPath(path, sizeof(path))) {
139061da546Spatrick      CFCBundle bundle(path);
140061da546Spatrick      CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL());
141061da546Spatrick      if (url.get()) {
142061da546Spatrick        if (::CFURLGetFileSystemRepresentation(url.get(), YES, (UInt8 *)path,
143061da546Spatrick                                               sizeof(path))) {
144061da546Spatrick          file.SetFile(path, FileSpec::Style::native);
145061da546Spatrick          return true;
146061da546Spatrick        }
147061da546Spatrick      }
148061da546Spatrick    }
149061da546Spatrick  }
150061da546Spatrick#endif
151061da546Spatrick  return false;
152061da546Spatrick}
153061da546Spatrick
154dda28197Spatrick#if TARGET_OS_OSX
155dda28197Spatrick
156*f6aab3d8Srobertstatic void *AcceptPIDFromInferior(const char *connect_url) {
157061da546Spatrick  ConnectionFileDescriptor file_conn;
158061da546Spatrick  Status error;
159061da546Spatrick  if (file_conn.Connect(connect_url, &error) == eConnectionStatusSuccess) {
160061da546Spatrick    char pid_str[256];
161061da546Spatrick    ::memset(pid_str, 0, sizeof(pid_str));
162061da546Spatrick    ConnectionStatus status;
163061da546Spatrick    const size_t pid_str_len = file_conn.Read(
164061da546Spatrick        pid_str, sizeof(pid_str), std::chrono::seconds(0), status, NULL);
165061da546Spatrick    if (pid_str_len > 0) {
166061da546Spatrick      int pid = atoi(pid_str);
167061da546Spatrick      return (void *)(intptr_t)pid;
168061da546Spatrick    }
169061da546Spatrick  }
170061da546Spatrick  return NULL;
171061da546Spatrick}
172061da546Spatrick
173061da546Spatrickconst char *applscript_in_new_tty = "tell application \"Terminal\"\n"
174061da546Spatrick                                    "   activate\n"
175061da546Spatrick                                    "	do script \"/bin/bash -c '%s';exit\"\n"
176061da546Spatrick                                    "end tell\n";
177061da546Spatrick
178061da546Spatrickconst char *applscript_in_existing_tty = "\
179061da546Spatrickset the_shell_script to \"/bin/bash -c '%s';exit\"\n\
180061da546Spatricktell application \"Terminal\"\n\
181061da546Spatrick	repeat with the_window in (get windows)\n\
182061da546Spatrick		repeat with the_tab in tabs of the_window\n\
183061da546Spatrick			set the_tty to tty in the_tab\n\
184061da546Spatrick			if the_tty contains \"%s\" then\n\
185061da546Spatrick				if the_tab is not busy then\n\
186061da546Spatrick					set selected of the_tab to true\n\
187061da546Spatrick					set frontmost of the_window to true\n\
188061da546Spatrick					do script the_shell_script in the_tab\n\
189061da546Spatrick					return\n\
190061da546Spatrick				end if\n\
191061da546Spatrick			end if\n\
192061da546Spatrick		end repeat\n\
193061da546Spatrick	end repeat\n\
194061da546Spatrick	do script the_shell_script\n\
195061da546Spatrickend tell\n";
196061da546Spatrick
197061da546Spatrickstatic Status
198061da546SpatrickLaunchInNewTerminalWithAppleScript(const char *exe_path,
199061da546Spatrick                                   ProcessLaunchInfo &launch_info) {
200061da546Spatrick  Status error;
201061da546Spatrick  char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
202061da546Spatrick  if (::mktemp(unix_socket_name) == NULL) {
203061da546Spatrick    error.SetErrorString("failed to make temporary path for a unix socket");
204061da546Spatrick    return error;
205061da546Spatrick  }
206061da546Spatrick
207061da546Spatrick  StreamString command;
208061da546Spatrick  FileSpec darwin_debug_file_spec = HostInfo::GetSupportExeDir();
209061da546Spatrick  if (!darwin_debug_file_spec) {
210061da546Spatrick    error.SetErrorString("can't locate the 'darwin-debug' executable");
211061da546Spatrick    return error;
212061da546Spatrick  }
213061da546Spatrick
214*f6aab3d8Srobert  darwin_debug_file_spec.SetFilename("darwin-debug");
215061da546Spatrick
216061da546Spatrick  if (!FileSystem::Instance().Exists(darwin_debug_file_spec)) {
217061da546Spatrick    error.SetErrorStringWithFormat(
218061da546Spatrick        "the 'darwin-debug' executable doesn't exists at '%s'",
219061da546Spatrick        darwin_debug_file_spec.GetPath().c_str());
220061da546Spatrick    return error;
221061da546Spatrick  }
222061da546Spatrick
223061da546Spatrick  char launcher_path[PATH_MAX];
224061da546Spatrick  darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
225061da546Spatrick
226061da546Spatrick  const ArchSpec &arch_spec = launch_info.GetArchitecture();
227061da546Spatrick  // Only set the architecture if it is valid and if it isn't Haswell (x86_64h).
228061da546Spatrick  if (arch_spec.IsValid() &&
229061da546Spatrick      arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h)
230061da546Spatrick    command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());
231061da546Spatrick
232*f6aab3d8Srobert  command.Printf(R"(\"%s\" --unix-socket=%s)", launcher_path, unix_socket_name);
233061da546Spatrick
234061da546Spatrick  if (arch_spec.IsValid())
235061da546Spatrick    command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
236061da546Spatrick
237061da546Spatrick  FileSpec working_dir{launch_info.GetWorkingDirectory()};
238061da546Spatrick  if (working_dir)
239*f6aab3d8Srobert    command.Printf(R"( --working-dir \"%s\")", working_dir.GetPath().c_str());
240061da546Spatrick  else {
241061da546Spatrick    char cwd[PATH_MAX];
242061da546Spatrick    if (getcwd(cwd, PATH_MAX))
243*f6aab3d8Srobert      command.Printf(R"( --working-dir \"%s\")", cwd);
244061da546Spatrick  }
245061da546Spatrick
246061da546Spatrick  if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
247061da546Spatrick    command.PutCString(" --disable-aslr");
248061da546Spatrick
249061da546Spatrick  // We are launching on this host in a terminal. So compare the environment on
250061da546Spatrick  // the host to what is supplied in the launch_info. Any items that aren't in
251061da546Spatrick  // the host environment need to be sent to darwin-debug. If we send all
252061da546Spatrick  // environment entries, we might blow the max command line length, so we only
253061da546Spatrick  // send user modified entries.
254061da546Spatrick  Environment host_env = Host::GetEnvironment();
255061da546Spatrick
256061da546Spatrick  for (const auto &KV : launch_info.GetEnvironment()) {
257061da546Spatrick    auto host_entry = host_env.find(KV.first());
258061da546Spatrick    if (host_entry == host_env.end() || host_entry->second != KV.second)
259*f6aab3d8Srobert      command.Format(R"( --env=\"{0}\")", Environment::compose(KV));
260061da546Spatrick  }
261061da546Spatrick
262061da546Spatrick  command.PutCString(" -- ");
263061da546Spatrick
264061da546Spatrick  const char **argv = launch_info.GetArguments().GetConstArgumentVector();
265061da546Spatrick  if (argv) {
266061da546Spatrick    for (size_t i = 0; argv[i] != NULL; ++i) {
267061da546Spatrick      if (i == 0)
268*f6aab3d8Srobert        command.Printf(R"( \"%s\")", exe_path);
269061da546Spatrick      else
270*f6aab3d8Srobert        command.Printf(R"( \"%s\")", argv[i]);
271061da546Spatrick    }
272061da546Spatrick  } else {
273*f6aab3d8Srobert    command.Printf(R"( \"%s\")", exe_path);
274061da546Spatrick  }
275061da546Spatrick  command.PutCString(" ; echo Process exited with status $?");
276061da546Spatrick  if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))
277061da546Spatrick    command.PutCString(" ; exit");
278061da546Spatrick
279061da546Spatrick  StreamString applescript_source;
280061da546Spatrick
281061da546Spatrick  applescript_source.Printf(applscript_in_new_tty,
282061da546Spatrick                            command.GetString().str().c_str());
283*f6aab3d8Srobert
284061da546Spatrick  NSAppleScript *applescript = [[NSAppleScript alloc]
285061da546Spatrick      initWithSource:[NSString stringWithCString:applescript_source.GetString()
286061da546Spatrick                                                     .str()
287061da546Spatrick                                                     .c_str()
288061da546Spatrick                                        encoding:NSUTF8StringEncoding]];
289061da546Spatrick
290061da546Spatrick  lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
291061da546Spatrick
292061da546Spatrick  Status lldb_error;
293061da546Spatrick  // Sleep and wait a bit for debugserver to start to listen...
294061da546Spatrick  ConnectionFileDescriptor file_conn;
295061da546Spatrick  char connect_url[128];
296061da546Spatrick  ::snprintf(connect_url, sizeof(connect_url), "unix-accept://%s",
297061da546Spatrick             unix_socket_name);
298061da546Spatrick
299061da546Spatrick  // Spawn a new thread to accept incoming connection on the connect_url
300061da546Spatrick  // so we can grab the pid from the inferior. We have to do this because we
301061da546Spatrick  // are sending an AppleScript that will launch a process in Terminal.app,
302061da546Spatrick  // in a shell and the shell will fork/exec a couple of times before we get
303061da546Spatrick  // to the process that we wanted to launch. So when our process actually
304061da546Spatrick  // gets launched, we will handshake with it and get the process ID for it.
305061da546Spatrick  llvm::Expected<HostThread> accept_thread = ThreadLauncher::LaunchThread(
306*f6aab3d8Srobert      unix_socket_name, [&] { return AcceptPIDFromInferior(connect_url); });
307061da546Spatrick
308061da546Spatrick  if (!accept_thread)
309061da546Spatrick    return Status(accept_thread.takeError());
310061da546Spatrick
311061da546Spatrick  [applescript executeAndReturnError:nil];
312061da546Spatrick
313061da546Spatrick  thread_result_t accept_thread_result = NULL;
314061da546Spatrick  lldb_error = accept_thread->Join(&accept_thread_result);
315061da546Spatrick  if (lldb_error.Success() && accept_thread_result) {
316061da546Spatrick    pid = (intptr_t)accept_thread_result;
317061da546Spatrick  }
318061da546Spatrick
319061da546Spatrick  llvm::sys::fs::remove(unix_socket_name);
320061da546Spatrick  [applescript release];
321061da546Spatrick  if (pid != LLDB_INVALID_PROCESS_ID)
322061da546Spatrick    launch_info.SetProcessID(pid);
323061da546Spatrick  return error;
324061da546Spatrick}
325061da546Spatrick
326dda28197Spatrick#endif // TARGET_OS_OSX
327061da546Spatrick
328061da546Spatrickbool Host::OpenFileInExternalEditor(const FileSpec &file_spec,
329061da546Spatrick                                    uint32_t line_no) {
330dda28197Spatrick#if !TARGET_OS_OSX
331061da546Spatrick  return false;
332dda28197Spatrick#else // !TARGET_OS_OSX
333061da546Spatrick  // We attach this to an 'odoc' event to specify a particular selection
334061da546Spatrick  typedef struct {
335061da546Spatrick    int16_t reserved0; // must be zero
336061da546Spatrick    int16_t fLineNumber;
337061da546Spatrick    int32_t fSelStart;
338061da546Spatrick    int32_t fSelEnd;
339061da546Spatrick    uint32_t reserved1; // must be zero
340061da546Spatrick    uint32_t reserved2; // must be zero
341061da546Spatrick  } BabelAESelInfo;
342061da546Spatrick
343*f6aab3d8Srobert  Log *log = GetLog(LLDBLog::Host);
344061da546Spatrick  char file_path[PATH_MAX];
345061da546Spatrick  file_spec.GetPath(file_path, PATH_MAX);
346061da546Spatrick  CFCString file_cfstr(file_path, kCFStringEncodingUTF8);
347061da546Spatrick  CFCReleaser<CFURLRef> file_URL(::CFURLCreateWithFileSystemPath(
348061da546Spatrick      NULL, file_cfstr.get(), kCFURLPOSIXPathStyle, false));
349061da546Spatrick
350061da546Spatrick  LLDB_LOGF(log,
351061da546Spatrick            "Sending source file: \"%s\" and line: %d to external editor.\n",
352061da546Spatrick            file_path, line_no);
353061da546Spatrick
354061da546Spatrick  long error;
355061da546Spatrick  BabelAESelInfo file_and_line_info = {
356061da546Spatrick      0,                      // reserved0
357061da546Spatrick      (int16_t)(line_no - 1), // fLineNumber (zero based line number)
358061da546Spatrick      1,                      // fSelStart
359061da546Spatrick      1024,                   // fSelEnd
360061da546Spatrick      0,                      // reserved1
361061da546Spatrick      0                       // reserved2
362061da546Spatrick  };
363061da546Spatrick
364061da546Spatrick  AEKeyDesc file_and_line_desc;
365061da546Spatrick
366061da546Spatrick  error = ::AECreateDesc(typeUTF8Text, &file_and_line_info,
367061da546Spatrick                         sizeof(file_and_line_info),
368061da546Spatrick                         &(file_and_line_desc.descContent));
369061da546Spatrick
370061da546Spatrick  if (error != noErr) {
371061da546Spatrick    LLDB_LOGF(log, "Error creating AEDesc: %ld.\n", error);
372061da546Spatrick    return false;
373061da546Spatrick  }
374061da546Spatrick
375061da546Spatrick  file_and_line_desc.descKey = keyAEPosition;
376061da546Spatrick
377061da546Spatrick  static std::string g_app_name;
378061da546Spatrick  static FSRef g_app_fsref;
379061da546Spatrick
380061da546Spatrick  LSApplicationParameters app_params;
381061da546Spatrick  ::memset(&app_params, 0, sizeof(app_params));
382061da546Spatrick  app_params.flags =
383061da546Spatrick      kLSLaunchDefaults | kLSLaunchDontAddToRecents | kLSLaunchDontSwitch;
384061da546Spatrick
385061da546Spatrick  char *external_editor = ::getenv("LLDB_EXTERNAL_EDITOR");
386061da546Spatrick
387061da546Spatrick  if (external_editor) {
388061da546Spatrick    LLDB_LOGF(log, "Looking for external editor \"%s\".\n", external_editor);
389061da546Spatrick
390061da546Spatrick    if (g_app_name.empty() ||
391061da546Spatrick        strcmp(g_app_name.c_str(), external_editor) != 0) {
392061da546Spatrick      CFCString editor_name(external_editor, kCFStringEncodingUTF8);
393061da546Spatrick      error = ::LSFindApplicationForInfo(kLSUnknownCreator, NULL,
394061da546Spatrick                                         editor_name.get(), &g_app_fsref, NULL);
395061da546Spatrick
396061da546Spatrick      // If we found the app, then store away the name so we don't have to
397061da546Spatrick      // re-look it up.
398061da546Spatrick      if (error != noErr) {
399061da546Spatrick        LLDB_LOGF(log,
400061da546Spatrick                  "Could not find External Editor application, error: %ld.\n",
401061da546Spatrick                  error);
402061da546Spatrick        return false;
403061da546Spatrick      }
404061da546Spatrick    }
405061da546Spatrick    app_params.application = &g_app_fsref;
406061da546Spatrick  }
407061da546Spatrick
408061da546Spatrick  ProcessSerialNumber psn;
409061da546Spatrick  CFCReleaser<CFArrayRef> file_array(
410061da546Spatrick      CFArrayCreate(NULL, (const void **)file_URL.ptr_address(false), 1, NULL));
411061da546Spatrick  error = ::LSOpenURLsWithRole(file_array.get(), kLSRolesAll,
412061da546Spatrick                               &file_and_line_desc, &app_params, &psn, 1);
413061da546Spatrick
414061da546Spatrick  AEDisposeDesc(&(file_and_line_desc.descContent));
415061da546Spatrick
416061da546Spatrick  if (error != noErr) {
417061da546Spatrick    LLDB_LOGF(log, "LSOpenURLsWithRole failed, error: %ld.\n", error);
418061da546Spatrick
419061da546Spatrick    return false;
420061da546Spatrick  }
421061da546Spatrick
422061da546Spatrick  return true;
423dda28197Spatrick#endif // TARGET_OS_OSX
424061da546Spatrick}
425061da546Spatrick
426*f6aab3d8Srobertbool Host::IsInteractiveGraphicSession() {
427*f6aab3d8Srobert#if !TARGET_OS_OSX
428*f6aab3d8Srobert  return false;
429*f6aab3d8Srobert#else
430*f6aab3d8Srobert  auditinfo_addr_t info;
431*f6aab3d8Srobert  getaudit_addr(&info, sizeof(info));
432*f6aab3d8Srobert  return info.ai_flags & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS;
433*f6aab3d8Srobert#endif
434*f6aab3d8Srobert}
435*f6aab3d8Srobert
436061da546SpatrickEnvironment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); }
437061da546Spatrick
438061da546Spatrickstatic bool GetMacOSXProcessCPUType(ProcessInstanceInfo &process_info) {
439061da546Spatrick  if (process_info.ProcessIDIsValid()) {
440061da546Spatrick    // Make a new mib to stay thread safe
441061da546Spatrick    int mib[CTL_MAXNAME] = {
442061da546Spatrick        0,
443061da546Spatrick    };
444061da546Spatrick    size_t mib_len = CTL_MAXNAME;
445061da546Spatrick    if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len))
446061da546Spatrick      return false;
447061da546Spatrick
448061da546Spatrick    mib[mib_len] = process_info.GetProcessID();
449061da546Spatrick    mib_len++;
450061da546Spatrick
451061da546Spatrick    cpu_type_t cpu, sub = 0;
452061da546Spatrick    size_t len = sizeof(cpu);
453061da546Spatrick    if (::sysctl(mib, mib_len, &cpu, &len, 0, 0) == 0) {
454061da546Spatrick      switch (cpu) {
455061da546Spatrick      case CPU_TYPE_I386:
456061da546Spatrick        sub = CPU_SUBTYPE_I386_ALL;
457061da546Spatrick        break;
458061da546Spatrick      case CPU_TYPE_X86_64:
459061da546Spatrick        sub = CPU_SUBTYPE_X86_64_ALL;
460061da546Spatrick        break;
461061da546Spatrick
462061da546Spatrick#if defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64_ALL)
463061da546Spatrick      case CPU_TYPE_ARM64:
464061da546Spatrick        sub = CPU_SUBTYPE_ARM64_ALL;
465061da546Spatrick        break;
466061da546Spatrick#endif
467061da546Spatrick
468061da546Spatrick#if defined(CPU_TYPE_ARM64_32) && defined(CPU_SUBTYPE_ARM64_32_ALL)
469061da546Spatrick      case CPU_TYPE_ARM64_32:
470061da546Spatrick        sub = CPU_SUBTYPE_ARM64_32_ALL;
471061da546Spatrick        break;
472061da546Spatrick#endif
473061da546Spatrick
474061da546Spatrick      case CPU_TYPE_ARM: {
475061da546Spatrick        // Note that we fetched the cpu type from the PROCESS but we can't get a
476061da546Spatrick        // cpusubtype of the
477061da546Spatrick        // process -- we can only get the host's cpu subtype.
478061da546Spatrick        uint32_t cpusubtype = 0;
479061da546Spatrick        len = sizeof(cpusubtype);
480061da546Spatrick        if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
481061da546Spatrick          sub = cpusubtype;
482061da546Spatrick
483061da546Spatrick        bool host_cpu_is_64bit;
484061da546Spatrick        uint32_t is64bit_capable;
485061da546Spatrick        size_t is64bit_capable_len = sizeof(is64bit_capable);
486061da546Spatrick        host_cpu_is_64bit =
487061da546Spatrick            sysctlbyname("hw.cpu64bit_capable", &is64bit_capable,
488061da546Spatrick                         &is64bit_capable_len, NULL, 0) == 0;
489061da546Spatrick
490061da546Spatrick        // if the host is an armv8 device, its cpusubtype will be in
491061da546Spatrick        // CPU_SUBTYPE_ARM64 numbering
492061da546Spatrick        // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value
493061da546Spatrick        // instead.
494061da546Spatrick
495061da546Spatrick        if (host_cpu_is_64bit) {
496061da546Spatrick          sub = CPU_SUBTYPE_ARM_V7;
497061da546Spatrick        }
498061da546Spatrick      } break;
499061da546Spatrick
500061da546Spatrick      default:
501061da546Spatrick        break;
502061da546Spatrick      }
503061da546Spatrick      process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, sub);
504061da546Spatrick      return true;
505061da546Spatrick    }
506061da546Spatrick  }
507061da546Spatrick  process_info.GetArchitecture().Clear();
508061da546Spatrick  return false;
509061da546Spatrick}
510061da546Spatrick
511061da546Spatrickstatic bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
512061da546Spatrick                                 ProcessInstanceInfo &process_info) {
513061da546Spatrick  if (process_info.ProcessIDIsValid()) {
514061da546Spatrick    int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2,
515061da546Spatrick                            (int)process_info.GetProcessID()};
516061da546Spatrick
517061da546Spatrick    size_t arg_data_size = 0;
518061da546Spatrick    if (::sysctl(proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) ||
519061da546Spatrick        arg_data_size == 0)
520061da546Spatrick      arg_data_size = 8192;
521061da546Spatrick
522061da546Spatrick    // Add a few bytes to the calculated length, I know we need to add at least
523061da546Spatrick    // one byte
524061da546Spatrick    // to this number otherwise we get junk back, so add 128 just in case...
525061da546Spatrick    DataBufferHeap arg_data(arg_data_size + 128, 0);
526061da546Spatrick    arg_data_size = arg_data.GetByteSize();
527061da546Spatrick    if (::sysctl(proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size, NULL,
528061da546Spatrick                 0) == 0) {
529061da546Spatrick      DataExtractor data(arg_data.GetBytes(), arg_data_size,
530061da546Spatrick                         endian::InlHostByteOrder(), sizeof(void *));
531061da546Spatrick      lldb::offset_t offset = 0;
532061da546Spatrick      uint32_t argc = data.GetU32(&offset);
533061da546Spatrick      llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
534061da546Spatrick      const llvm::Triple::ArchType triple_arch = triple.getArch();
535061da546Spatrick      const bool check_for_ios_simulator =
536061da546Spatrick          (triple_arch == llvm::Triple::x86 ||
537061da546Spatrick           triple_arch == llvm::Triple::x86_64);
538061da546Spatrick      const char *cstr = data.GetCStr(&offset);
539061da546Spatrick      if (cstr) {
540061da546Spatrick        process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);
541061da546Spatrick
542061da546Spatrick        if (match_info_ptr == NULL ||
543061da546Spatrick            NameMatches(
544061da546Spatrick                process_info.GetExecutableFile().GetFilename().GetCString(),
545061da546Spatrick                match_info_ptr->GetNameMatchType(),
546061da546Spatrick                match_info_ptr->GetProcessInfo().GetName())) {
547061da546Spatrick          // Skip NULLs
548061da546Spatrick          while (true) {
549061da546Spatrick            const uint8_t *p = data.PeekData(offset, 1);
550061da546Spatrick            if ((p == NULL) || (*p != '\0'))
551061da546Spatrick              break;
552061da546Spatrick            ++offset;
553061da546Spatrick          }
554061da546Spatrick          // Now extract all arguments
555061da546Spatrick          Args &proc_args = process_info.GetArguments();
556061da546Spatrick          for (int i = 0; i < static_cast<int>(argc); ++i) {
557061da546Spatrick            cstr = data.GetCStr(&offset);
558061da546Spatrick            if (cstr)
559061da546Spatrick              proc_args.AppendArgument(llvm::StringRef(cstr));
560061da546Spatrick          }
561061da546Spatrick
562061da546Spatrick          Environment &proc_env = process_info.GetEnvironment();
563061da546Spatrick          while ((cstr = data.GetCStr(&offset))) {
564061da546Spatrick            if (cstr[0] == '\0')
565061da546Spatrick              break;
566061da546Spatrick
567061da546Spatrick            if (check_for_ios_simulator) {
568061da546Spatrick              if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) ==
569061da546Spatrick                  0)
570061da546Spatrick                process_info.GetArchitecture().GetTriple().setOS(
571061da546Spatrick                    llvm::Triple::IOS);
572061da546Spatrick              else
573061da546Spatrick                process_info.GetArchitecture().GetTriple().setOS(
574061da546Spatrick                    llvm::Triple::MacOSX);
575061da546Spatrick            }
576061da546Spatrick
577061da546Spatrick            proc_env.insert(cstr);
578061da546Spatrick          }
579061da546Spatrick          return true;
580061da546Spatrick        }
581061da546Spatrick      }
582061da546Spatrick    }
583061da546Spatrick  }
584061da546Spatrick  return false;
585061da546Spatrick}
586061da546Spatrick
587061da546Spatrickstatic bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) {
588061da546Spatrick  if (process_info.ProcessIDIsValid()) {
589061da546Spatrick    int mib[4];
590061da546Spatrick    mib[0] = CTL_KERN;
591061da546Spatrick    mib[1] = KERN_PROC;
592061da546Spatrick    mib[2] = KERN_PROC_PID;
593061da546Spatrick    mib[3] = process_info.GetProcessID();
594061da546Spatrick    struct kinfo_proc proc_kinfo;
595061da546Spatrick    size_t proc_kinfo_size = sizeof(struct kinfo_proc);
596061da546Spatrick
597061da546Spatrick    if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
598061da546Spatrick      if (proc_kinfo_size > 0) {
599061da546Spatrick        process_info.SetParentProcessID(proc_kinfo.kp_eproc.e_ppid);
600061da546Spatrick        process_info.SetUserID(proc_kinfo.kp_eproc.e_pcred.p_ruid);
601061da546Spatrick        process_info.SetGroupID(proc_kinfo.kp_eproc.e_pcred.p_rgid);
602061da546Spatrick        process_info.SetEffectiveUserID(proc_kinfo.kp_eproc.e_ucred.cr_uid);
603061da546Spatrick        if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
604061da546Spatrick          process_info.SetEffectiveGroupID(
605061da546Spatrick              proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
606061da546Spatrick        else
607061da546Spatrick          process_info.SetEffectiveGroupID(UINT32_MAX);
608061da546Spatrick        return true;
609061da546Spatrick      }
610061da546Spatrick    }
611061da546Spatrick  }
612061da546Spatrick  process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
613061da546Spatrick  process_info.SetUserID(UINT32_MAX);
614061da546Spatrick  process_info.SetGroupID(UINT32_MAX);
615061da546Spatrick  process_info.SetEffectiveUserID(UINT32_MAX);
616061da546Spatrick  process_info.SetEffectiveGroupID(UINT32_MAX);
617061da546Spatrick  return false;
618061da546Spatrick}
619061da546Spatrick
620dda28197Spatrickuint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
621061da546Spatrick                                 ProcessInstanceInfoList &process_infos) {
622061da546Spatrick  std::vector<struct kinfo_proc> kinfos;
623061da546Spatrick
624061da546Spatrick  int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
625061da546Spatrick
626061da546Spatrick  size_t pid_data_size = 0;
627061da546Spatrick  if (::sysctl(mib, 3, nullptr, &pid_data_size, nullptr, 0) != 0)
628061da546Spatrick    return 0;
629061da546Spatrick
630061da546Spatrick  // Add a few extra in case a few more show up
631061da546Spatrick  const size_t estimated_pid_count =
632061da546Spatrick      (pid_data_size / sizeof(struct kinfo_proc)) + 10;
633061da546Spatrick
634061da546Spatrick  kinfos.resize(estimated_pid_count);
635061da546Spatrick  pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
636061da546Spatrick
637061da546Spatrick  if (::sysctl(mib, 3, &kinfos[0], &pid_data_size, nullptr, 0) != 0)
638061da546Spatrick    return 0;
639061da546Spatrick
640061da546Spatrick  const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
641061da546Spatrick
642061da546Spatrick  bool all_users = match_info.GetMatchAllUsers();
643061da546Spatrick  const lldb::pid_t our_pid = getpid();
644061da546Spatrick  const uid_t our_uid = getuid();
645061da546Spatrick  for (size_t i = 0; i < actual_pid_count; i++) {
646061da546Spatrick    const struct kinfo_proc &kinfo = kinfos[i];
647061da546Spatrick
648061da546Spatrick    bool kinfo_user_matches = false;
649061da546Spatrick    if (all_users)
650061da546Spatrick      kinfo_user_matches = true;
651061da546Spatrick    else
652061da546Spatrick      kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
653061da546Spatrick
654061da546Spatrick    // Special case, if lldb is being run as root we can attach to anything.
655061da546Spatrick    if (our_uid == 0)
656061da546Spatrick      kinfo_user_matches = true;
657061da546Spatrick
658061da546Spatrick    if (!kinfo_user_matches || // Make sure the user is acceptable
659061da546Spatrick        static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) ==
660061da546Spatrick            our_pid ||                   // Skip this process
661061da546Spatrick        kinfo.kp_proc.p_pid == 0 ||      // Skip kernel (kernel pid is zero)
662061da546Spatrick        kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains...
663061da546Spatrick        kinfo.kp_proc.p_flag & P_TRACED ||   // Being debugged?
664dda28197Spatrick        kinfo.kp_proc.p_flag & P_WEXIT)
665061da546Spatrick      continue;
666061da546Spatrick
667061da546Spatrick    ProcessInstanceInfo process_info;
668061da546Spatrick    process_info.SetProcessID(kinfo.kp_proc.p_pid);
669061da546Spatrick    process_info.SetParentProcessID(kinfo.kp_eproc.e_ppid);
670061da546Spatrick    process_info.SetUserID(kinfo.kp_eproc.e_pcred.p_ruid);
671061da546Spatrick    process_info.SetGroupID(kinfo.kp_eproc.e_pcred.p_rgid);
672061da546Spatrick    process_info.SetEffectiveUserID(kinfo.kp_eproc.e_ucred.cr_uid);
673061da546Spatrick    if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
674061da546Spatrick      process_info.SetEffectiveGroupID(kinfo.kp_eproc.e_ucred.cr_groups[0]);
675061da546Spatrick    else
676061da546Spatrick      process_info.SetEffectiveGroupID(UINT32_MAX);
677061da546Spatrick
678061da546Spatrick    // Make sure our info matches before we go fetch the name and cpu type
679061da546Spatrick    if (!match_info.UserIDsMatch(process_info) ||
680061da546Spatrick        !match_info.ProcessIDsMatch(process_info))
681061da546Spatrick      continue;
682061da546Spatrick
683061da546Spatrick    // Get CPU type first so we can know to look for iOS simulator is we have
684061da546Spatrick    // x86 or x86_64
685061da546Spatrick    if (GetMacOSXProcessCPUType(process_info)) {
686061da546Spatrick      if (GetMacOSXProcessArgs(&match_info, process_info)) {
687061da546Spatrick        if (match_info.Matches(process_info))
688dda28197Spatrick          process_infos.push_back(process_info);
689061da546Spatrick      }
690061da546Spatrick    }
691061da546Spatrick  }
692dda28197Spatrick  return process_infos.size();
693061da546Spatrick}
694061da546Spatrick
695061da546Spatrickbool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
696061da546Spatrick  process_info.SetProcessID(pid);
697061da546Spatrick  bool success = false;
698061da546Spatrick
699061da546Spatrick  // Get CPU type first so we can know to look for iOS simulator is we have x86
700061da546Spatrick  // or x86_64
701061da546Spatrick  if (GetMacOSXProcessCPUType(process_info))
702061da546Spatrick    success = true;
703061da546Spatrick
704061da546Spatrick  if (GetMacOSXProcessArgs(NULL, process_info))
705061da546Spatrick    success = true;
706061da546Spatrick
707061da546Spatrick  if (GetMacOSXProcessUserAndGroup(process_info))
708061da546Spatrick    success = true;
709061da546Spatrick
710061da546Spatrick  if (success)
711061da546Spatrick    return true;
712061da546Spatrick
713061da546Spatrick  process_info.Clear();
714061da546Spatrick  return false;
715061da546Spatrick}
716061da546Spatrick
717dda28197Spatrick#if TARGET_OS_OSX
718061da546Spatrickstatic void PackageXPCArguments(xpc_object_t message, const char *prefix,
719061da546Spatrick                                const Args &args) {
720061da546Spatrick  size_t count = args.GetArgumentCount();
721061da546Spatrick  char buf[50]; // long enough for 'argXXX'
722061da546Spatrick  memset(buf, 0, 50);
723061da546Spatrick  sprintf(buf, "%sCount", prefix);
724061da546Spatrick  xpc_dictionary_set_int64(message, buf, count);
725061da546Spatrick  for (size_t i = 0; i < count; i++) {
726061da546Spatrick    memset(buf, 0, 50);
727061da546Spatrick    sprintf(buf, "%s%zi", prefix, i);
728061da546Spatrick    xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
729061da546Spatrick  }
730061da546Spatrick}
731061da546Spatrick
732061da546Spatrickstatic void PackageXPCEnvironment(xpc_object_t message, llvm::StringRef prefix,
733061da546Spatrick                                  const Environment &env) {
734061da546Spatrick  xpc_dictionary_set_int64(message, (prefix + "Count").str().c_str(),
735061da546Spatrick                           env.size());
736061da546Spatrick  size_t i = 0;
737061da546Spatrick  for (const auto &KV : env) {
738061da546Spatrick    xpc_dictionary_set_string(message, (prefix + llvm::Twine(i)).str().c_str(),
739061da546Spatrick                              Environment::compose(KV).c_str());
740061da546Spatrick  }
741061da546Spatrick}
742061da546Spatrick
743061da546Spatrick/*
744061da546Spatrick A valid authorizationRef means that
745061da546Spatrick    - there is the LaunchUsingXPCRightName rights in the /etc/authorization
746061da546Spatrick    - we have successfully copied the rights to be send over the XPC wire
747061da546Spatrick Once obtained, it will be valid for as long as the process lives.
748061da546Spatrick */
749061da546Spatrickstatic AuthorizationRef authorizationRef = NULL;
750061da546Spatrickstatic Status getXPCAuthorization(ProcessLaunchInfo &launch_info) {
751061da546Spatrick  Status error;
752*f6aab3d8Srobert  Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));
753061da546Spatrick
754061da546Spatrick  if ((launch_info.GetUserID() == 0) && !authorizationRef) {
755061da546Spatrick    OSStatus createStatus =
756061da546Spatrick        AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
757061da546Spatrick                            kAuthorizationFlagDefaults, &authorizationRef);
758061da546Spatrick    if (createStatus != errAuthorizationSuccess) {
759061da546Spatrick      error.SetError(1, eErrorTypeGeneric);
760061da546Spatrick      error.SetErrorString("Can't create authorizationRef.");
761061da546Spatrick      LLDB_LOG(log, "error: {0}", error);
762061da546Spatrick      return error;
763061da546Spatrick    }
764061da546Spatrick
765061da546Spatrick    OSStatus rightsStatus =
766061da546Spatrick        AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
767061da546Spatrick    if (rightsStatus != errAuthorizationSuccess) {
768061da546Spatrick      // No rights in the security database, Create it with the right prompt.
769061da546Spatrick      CFStringRef prompt =
770061da546Spatrick          CFSTR("Xcode is trying to take control of a root process.");
771061da546Spatrick      CFStringRef keys[] = {CFSTR("en")};
772061da546Spatrick      CFTypeRef values[] = {prompt};
773061da546Spatrick      CFDictionaryRef promptDict = CFDictionaryCreate(
774061da546Spatrick          kCFAllocatorDefault, (const void **)keys, (const void **)values, 1,
775061da546Spatrick          &kCFCopyStringDictionaryKeyCallBacks,
776061da546Spatrick          &kCFTypeDictionaryValueCallBacks);
777061da546Spatrick
778061da546Spatrick      CFStringRef keys1[] = {CFSTR("class"), CFSTR("group"), CFSTR("comment"),
779061da546Spatrick                             CFSTR("default-prompt"), CFSTR("shared")};
780061da546Spatrick      CFTypeRef values1[] = {CFSTR("user"), CFSTR("admin"),
781061da546Spatrick                             CFSTR(LaunchUsingXPCRightName), promptDict,
782061da546Spatrick                             kCFBooleanFalse};
783061da546Spatrick      CFDictionaryRef dict = CFDictionaryCreate(
784061da546Spatrick          kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5,
785061da546Spatrick          &kCFCopyStringDictionaryKeyCallBacks,
786061da546Spatrick          &kCFTypeDictionaryValueCallBacks);
787061da546Spatrick      rightsStatus = AuthorizationRightSet(
788061da546Spatrick          authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
789061da546Spatrick      CFRelease(promptDict);
790061da546Spatrick      CFRelease(dict);
791061da546Spatrick    }
792061da546Spatrick
793061da546Spatrick    OSStatus copyRightStatus = errAuthorizationDenied;
794061da546Spatrick    if (rightsStatus == errAuthorizationSuccess) {
795061da546Spatrick      AuthorizationItem item1 = {LaunchUsingXPCRightName, 0, NULL, 0};
796061da546Spatrick      AuthorizationItem items[] = {item1};
797061da546Spatrick      AuthorizationRights requestedRights = {1, items};
798061da546Spatrick      AuthorizationFlags authorizationFlags =
799061da546Spatrick          kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
800061da546Spatrick      copyRightStatus = AuthorizationCopyRights(
801061da546Spatrick          authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment,
802061da546Spatrick          authorizationFlags, NULL);
803061da546Spatrick    }
804061da546Spatrick
805061da546Spatrick    if (copyRightStatus != errAuthorizationSuccess) {
806061da546Spatrick      // Eventually when the commandline supports running as root and the user
807061da546Spatrick      // is not
808061da546Spatrick      // logged in in the current audit session, we will need the trick in gdb
809061da546Spatrick      // where
810061da546Spatrick      // we ask the user to type in the root passwd in the terminal.
811061da546Spatrick      error.SetError(2, eErrorTypeGeneric);
812061da546Spatrick      error.SetErrorStringWithFormat(
813061da546Spatrick          "Launching as root needs root authorization.");
814061da546Spatrick      LLDB_LOG(log, "error: {0}", error);
815061da546Spatrick
816061da546Spatrick      if (authorizationRef) {
817061da546Spatrick        AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
818061da546Spatrick        authorizationRef = NULL;
819061da546Spatrick      }
820061da546Spatrick    }
821061da546Spatrick  }
822061da546Spatrick
823061da546Spatrick  return error;
824061da546Spatrick}
825061da546Spatrick#endif
826061da546Spatrick
827061da546Spatrickstatic short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {
828061da546Spatrick  short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
829061da546Spatrick
830061da546Spatrick  if (launch_info.GetFlags().Test(eLaunchFlagExec))
831061da546Spatrick    flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
832061da546Spatrick
833061da546Spatrick  if (launch_info.GetFlags().Test(eLaunchFlagDebug))
834061da546Spatrick    flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
835061da546Spatrick
836061da546Spatrick  if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
837061da546Spatrick    flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
838061da546Spatrick
839061da546Spatrick  if (launch_info.GetLaunchInSeparateProcessGroup())
840061da546Spatrick    flags |= POSIX_SPAWN_SETPGROUP;
841061da546Spatrick
842061da546Spatrick#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
843061da546Spatrick#if defined(__x86_64__) || defined(__i386__)
844061da546Spatrick  static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
845061da546Spatrick  if (g_use_close_on_exec_flag == eLazyBoolCalculate) {
846061da546Spatrick    g_use_close_on_exec_flag = eLazyBoolNo;
847061da546Spatrick
848061da546Spatrick    llvm::VersionTuple version = HostInfo::GetOSVersion();
849061da546Spatrick    if (version > llvm::VersionTuple(10, 7)) {
850061da546Spatrick      // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or
851061da546Spatrick      // earlier
852061da546Spatrick      g_use_close_on_exec_flag = eLazyBoolYes;
853061da546Spatrick    }
854061da546Spatrick  }
855061da546Spatrick#else
856061da546Spatrick  static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
857061da546Spatrick#endif // defined(__x86_64__) || defined(__i386__)
858061da546Spatrick  // Close all files exception those with file actions if this is supported.
859061da546Spatrick  if (g_use_close_on_exec_flag == eLazyBoolYes)
860061da546Spatrick    flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
861061da546Spatrick#endif // ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
862061da546Spatrick  return flags;
863061da546Spatrick}
864061da546Spatrick
865061da546Spatrickstatic Status LaunchProcessXPC(const char *exe_path,
866061da546Spatrick                               ProcessLaunchInfo &launch_info,
867061da546Spatrick                               lldb::pid_t &pid) {
868dda28197Spatrick#if TARGET_OS_OSX
869061da546Spatrick  Status error = getXPCAuthorization(launch_info);
870061da546Spatrick  if (error.Fail())
871061da546Spatrick    return error;
872061da546Spatrick
873*f6aab3d8Srobert  Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));
874061da546Spatrick
875061da546Spatrick  uid_t requested_uid = launch_info.GetUserID();
876061da546Spatrick  const char *xpc_service = nil;
877061da546Spatrick  bool send_auth = false;
878061da546Spatrick  AuthorizationExternalForm extForm;
879061da546Spatrick  if (requested_uid == 0) {
880061da546Spatrick    if (AuthorizationMakeExternalForm(authorizationRef, &extForm) ==
881061da546Spatrick        errAuthorizationSuccess) {
882061da546Spatrick      send_auth = true;
883061da546Spatrick    } else {
884061da546Spatrick      error.SetError(3, eErrorTypeGeneric);
885061da546Spatrick      error.SetErrorStringWithFormat("Launching root via XPC needs to "
886061da546Spatrick                                     "externalize authorization reference.");
887061da546Spatrick      LLDB_LOG(log, "error: {0}", error);
888061da546Spatrick      return error;
889061da546Spatrick    }
890061da546Spatrick    xpc_service = LaunchUsingXPCRightName;
891061da546Spatrick  } else {
892061da546Spatrick    error.SetError(4, eErrorTypeGeneric);
893061da546Spatrick    error.SetErrorStringWithFormat(
894061da546Spatrick        "Launching via XPC is only currently available for root.");
895061da546Spatrick    LLDB_LOG(log, "error: {0}", error);
896061da546Spatrick    return error;
897061da546Spatrick  }
898061da546Spatrick
899061da546Spatrick  xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
900061da546Spatrick
901061da546Spatrick  xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
902061da546Spatrick    xpc_type_t type = xpc_get_type(event);
903061da546Spatrick
904061da546Spatrick    if (type == XPC_TYPE_ERROR) {
905061da546Spatrick      if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
906061da546Spatrick        // The service has either canceled itself, crashed, or been terminated.
907061da546Spatrick        // The XPC connection is still valid and sending a message to it will
908061da546Spatrick        // re-launch the service.
909061da546Spatrick        // If the service is state-full, this is the time to initialize the new
910061da546Spatrick        // service.
911061da546Spatrick        return;
912061da546Spatrick      } else if (event == XPC_ERROR_CONNECTION_INVALID) {
913061da546Spatrick        // The service is invalid. Either the service name supplied to
914061da546Spatrick        // xpc_connection_create() is incorrect
915061da546Spatrick        // or we (this process) have canceled the service; we can do any cleanup
916061da546Spatrick        // of application state at this point.
917061da546Spatrick        // printf("Service disconnected");
918061da546Spatrick        return;
919061da546Spatrick      } else {
920061da546Spatrick        // printf("Unexpected error from service: %s",
921061da546Spatrick        // xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
922061da546Spatrick      }
923061da546Spatrick
924061da546Spatrick    } else {
925061da546Spatrick      // printf("Received unexpected event in handler");
926061da546Spatrick    }
927061da546Spatrick  });
928061da546Spatrick
929061da546Spatrick  xpc_connection_set_finalizer_f(conn, xpc_finalizer_t(xpc_release));
930061da546Spatrick  xpc_connection_resume(conn);
931061da546Spatrick  xpc_object_t message = xpc_dictionary_create(nil, nil, 0);
932061da546Spatrick
933061da546Spatrick  if (send_auth) {
934061da546Spatrick    xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes,
935061da546Spatrick                            sizeof(AuthorizationExternalForm));
936061da546Spatrick  }
937061da546Spatrick
938061da546Spatrick  PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey,
939061da546Spatrick                      launch_info.GetArguments());
940061da546Spatrick  PackageXPCEnvironment(message, LauncherXPCServiceEnvPrefxKey,
941061da546Spatrick                        launch_info.GetEnvironment());
942061da546Spatrick
943061da546Spatrick  // Posix spawn stuff.
944061da546Spatrick  xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey,
945061da546Spatrick                           launch_info.GetArchitecture().GetMachOCPUType());
946061da546Spatrick  xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey,
947061da546Spatrick                           GetPosixspawnFlags(launch_info));
948061da546Spatrick  const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
949061da546Spatrick  if (file_action && !file_action->GetPath().empty()) {
950061da546Spatrick    xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey,
951061da546Spatrick                              file_action->GetPath().str().c_str());
952061da546Spatrick  }
953061da546Spatrick  file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
954061da546Spatrick  if (file_action && !file_action->GetPath().empty()) {
955061da546Spatrick    xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey,
956061da546Spatrick                              file_action->GetPath().str().c_str());
957061da546Spatrick  }
958061da546Spatrick  file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
959061da546Spatrick  if (file_action && !file_action->GetPath().empty()) {
960061da546Spatrick    xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey,
961061da546Spatrick                              file_action->GetPath().str().c_str());
962061da546Spatrick  }
963061da546Spatrick
964061da546Spatrick  xpc_object_t reply =
965061da546Spatrick      xpc_connection_send_message_with_reply_sync(conn, message);
966061da546Spatrick  xpc_type_t returnType = xpc_get_type(reply);
967061da546Spatrick  if (returnType == XPC_TYPE_DICTIONARY) {
968061da546Spatrick    pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
969061da546Spatrick    if (pid == 0) {
970061da546Spatrick      int errorType =
971061da546Spatrick          xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
972061da546Spatrick      int errorCode =
973061da546Spatrick          xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
974061da546Spatrick
975061da546Spatrick      error.SetError(errorCode, eErrorTypeGeneric);
976061da546Spatrick      error.SetErrorStringWithFormat(
977061da546Spatrick          "Problems with launching via XPC. Error type : %i, code : %i",
978061da546Spatrick          errorType, errorCode);
979061da546Spatrick      LLDB_LOG(log, "error: {0}", error);
980061da546Spatrick
981061da546Spatrick      if (authorizationRef) {
982061da546Spatrick        AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
983061da546Spatrick        authorizationRef = NULL;
984061da546Spatrick      }
985061da546Spatrick    }
986061da546Spatrick  } else if (returnType == XPC_TYPE_ERROR) {
987061da546Spatrick    error.SetError(5, eErrorTypeGeneric);
988061da546Spatrick    error.SetErrorStringWithFormat(
989061da546Spatrick        "Problems with launching via XPC. XPC error : %s",
990061da546Spatrick        xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
991061da546Spatrick    LLDB_LOG(log, "error: {0}", error);
992061da546Spatrick  }
993061da546Spatrick
994061da546Spatrick  return error;
995061da546Spatrick#else
996061da546Spatrick  Status error;
997061da546Spatrick  return error;
998061da546Spatrick#endif
999061da546Spatrick}
1000061da546Spatrick
1001061da546Spatrickstatic bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
1002061da546Spatrick                                    Log *log, Status &error) {
1003061da546Spatrick  if (info == NULL)
1004061da546Spatrick    return false;
1005061da546Spatrick
1006061da546Spatrick  posix_spawn_file_actions_t *file_actions =
1007061da546Spatrick      static_cast<posix_spawn_file_actions_t *>(_file_actions);
1008061da546Spatrick
1009061da546Spatrick  switch (info->GetAction()) {
1010061da546Spatrick  case FileAction::eFileActionNone:
1011061da546Spatrick    error.Clear();
1012061da546Spatrick    break;
1013061da546Spatrick
1014061da546Spatrick  case FileAction::eFileActionClose:
1015061da546Spatrick    if (info->GetFD() == -1)
1016061da546Spatrick      error.SetErrorString(
1017061da546Spatrick          "invalid fd for posix_spawn_file_actions_addclose(...)");
1018061da546Spatrick    else {
1019061da546Spatrick      error.SetError(
1020061da546Spatrick          ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),
1021061da546Spatrick          eErrorTypePOSIX);
1022061da546Spatrick      if (error.Fail())
1023061da546Spatrick        LLDB_LOG(log,
1024061da546Spatrick                 "error: {0}, posix_spawn_file_actions_addclose "
1025061da546Spatrick                 "(action={1}, fd={2})",
1026061da546Spatrick                 error, file_actions, info->GetFD());
1027061da546Spatrick    }
1028061da546Spatrick    break;
1029061da546Spatrick
1030061da546Spatrick  case FileAction::eFileActionDuplicate:
1031061da546Spatrick    if (info->GetFD() == -1)
1032061da546Spatrick      error.SetErrorString(
1033061da546Spatrick          "invalid fd for posix_spawn_file_actions_adddup2(...)");
1034061da546Spatrick    else if (info->GetActionArgument() == -1)
1035061da546Spatrick      error.SetErrorString(
1036061da546Spatrick          "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
1037061da546Spatrick    else {
1038061da546Spatrick      error.SetError(
1039061da546Spatrick          ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),
1040061da546Spatrick                                             info->GetActionArgument()),
1041061da546Spatrick          eErrorTypePOSIX);
1042061da546Spatrick      if (error.Fail())
1043061da546Spatrick        LLDB_LOG(log,
1044061da546Spatrick                 "error: {0}, posix_spawn_file_actions_adddup2 "
1045061da546Spatrick                 "(action={1}, fd={2}, dup_fd={3})",
1046061da546Spatrick                 error, file_actions, info->GetFD(), info->GetActionArgument());
1047061da546Spatrick    }
1048061da546Spatrick    break;
1049061da546Spatrick
1050061da546Spatrick  case FileAction::eFileActionOpen:
1051061da546Spatrick    if (info->GetFD() == -1)
1052061da546Spatrick      error.SetErrorString(
1053061da546Spatrick          "invalid fd in posix_spawn_file_actions_addopen(...)");
1054061da546Spatrick    else {
1055061da546Spatrick      int oflag = info->GetActionArgument();
1056061da546Spatrick
1057061da546Spatrick      mode_t mode = 0;
1058061da546Spatrick
1059061da546Spatrick      if (oflag & O_CREAT)
1060061da546Spatrick        mode = 0640;
1061061da546Spatrick
1062061da546Spatrick      error.SetError(::posix_spawn_file_actions_addopen(
1063061da546Spatrick                         file_actions, info->GetFD(),
1064061da546Spatrick                         info->GetPath().str().c_str(), oflag, mode),
1065061da546Spatrick                     eErrorTypePOSIX);
1066061da546Spatrick      if (error.Fail())
1067061da546Spatrick        LLDB_LOG(log,
1068061da546Spatrick                 "error: {0}, posix_spawn_file_actions_addopen (action={1}, "
1069061da546Spatrick                 "fd={2}, path='{3}', oflag={4}, mode={5})",
1070061da546Spatrick                 error, file_actions, info->GetFD(), info->GetPath(), oflag,
1071061da546Spatrick                 mode);
1072061da546Spatrick    }
1073061da546Spatrick    break;
1074061da546Spatrick  }
1075061da546Spatrick  return error.Success();
1076061da546Spatrick}
1077061da546Spatrick
1078061da546Spatrickstatic Status LaunchProcessPosixSpawn(const char *exe_path,
1079061da546Spatrick                                      const ProcessLaunchInfo &launch_info,
1080061da546Spatrick                                      lldb::pid_t &pid) {
1081061da546Spatrick  Status error;
1082*f6aab3d8Srobert  Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));
1083061da546Spatrick
1084061da546Spatrick  posix_spawnattr_t attr;
1085061da546Spatrick  error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX);
1086061da546Spatrick
1087061da546Spatrick  if (error.Fail()) {
1088061da546Spatrick    LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error);
1089061da546Spatrick    return error;
1090061da546Spatrick  }
1091061da546Spatrick
1092061da546Spatrick  // Make sure we clean up the posix spawn attributes before exiting this scope.
1093061da546Spatrick  auto cleanup_attr =
1094061da546Spatrick      llvm::make_scope_exit([&]() { posix_spawnattr_destroy(&attr); });
1095061da546Spatrick
1096061da546Spatrick  sigset_t no_signals;
1097061da546Spatrick  sigset_t all_signals;
1098061da546Spatrick  sigemptyset(&no_signals);
1099061da546Spatrick  sigfillset(&all_signals);
1100061da546Spatrick  ::posix_spawnattr_setsigmask(&attr, &no_signals);
1101061da546Spatrick  ::posix_spawnattr_setsigdefault(&attr, &all_signals);
1102061da546Spatrick
1103061da546Spatrick  short flags = GetPosixspawnFlags(launch_info);
1104061da546Spatrick
1105061da546Spatrick  error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);
1106061da546Spatrick  if (error.Fail()) {
1107061da546Spatrick    LLDB_LOG(log,
1108061da546Spatrick             "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",
1109061da546Spatrick             error, flags);
1110061da546Spatrick    return error;
1111061da546Spatrick  }
1112061da546Spatrick
1113be691f3bSpatrick  bool is_graphical = true;
1114be691f3bSpatrick
1115be691f3bSpatrick#if TARGET_OS_OSX
1116be691f3bSpatrick  SecuritySessionId session_id;
1117be691f3bSpatrick  SessionAttributeBits session_attributes;
1118be691f3bSpatrick  OSStatus status =
1119be691f3bSpatrick      SessionGetInfo(callerSecuritySession, &session_id, &session_attributes);
1120be691f3bSpatrick  if (status == errSessionSuccess)
1121be691f3bSpatrick    is_graphical = session_attributes & sessionHasGraphicAccess;
1122be691f3bSpatrick#endif
1123be691f3bSpatrick
1124be691f3bSpatrick  //  When lldb is ran through a graphical session, make the debuggee process
1125be691f3bSpatrick  //  responsible for its own TCC permissions instead of inheriting them from
1126be691f3bSpatrick  //  its parent.
1127be691f3bSpatrick  if (is_graphical && launch_info.GetFlags().Test(eLaunchFlagDebug) &&
1128be691f3bSpatrick      !launch_info.GetFlags().Test(eLaunchFlagInheritTCCFromParent)) {
1129be691f3bSpatrick    error.SetError(setup_posix_spawn_responsible_flag(&attr), eErrorTypePOSIX);
1130be691f3bSpatrick    if (error.Fail()) {
1131be691f3bSpatrick      LLDB_LOG(log, "error: {0}, setup_posix_spawn_responsible_flag(&attr)",
1132be691f3bSpatrick               error);
1133be691f3bSpatrick      return error;
1134be691f3bSpatrick    }
1135be691f3bSpatrick  }
1136be691f3bSpatrick
1137be691f3bSpatrick  // Don't set the binpref if a shell was provided. After all, that's only
1138be691f3bSpatrick  // going to affect what version of the shell is launched, not what fork of
1139be691f3bSpatrick  // the binary is launched.  We insert "arch --arch <ARCH> as part of the
1140be691f3bSpatrick  // shell invocation to do that job on OSX.
1141be691f3bSpatrick  if (launch_info.GetShell() == FileSpec()) {
1142be691f3bSpatrick    const ArchSpec &arch_spec = launch_info.GetArchitecture();
1143be691f3bSpatrick    cpu_type_t cpu_type = arch_spec.GetMachOCPUType();
1144be691f3bSpatrick    cpu_type_t cpu_subtype = arch_spec.GetMachOCPUSubType();
1145be691f3bSpatrick    const bool set_cpu_type =
1146be691f3bSpatrick        cpu_type != 0 && cpu_type != static_cast<cpu_type_t>(UINT32_MAX) &&
1147be691f3bSpatrick        cpu_type != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE);
1148be691f3bSpatrick    const bool set_cpu_subtype =
1149be691f3bSpatrick        cpu_subtype != 0 &&
1150be691f3bSpatrick        cpu_subtype != static_cast<cpu_subtype_t>(UINT32_MAX) &&
1151be691f3bSpatrick        cpu_subtype != CPU_SUBTYPE_X86_64_H;
1152be691f3bSpatrick    if (set_cpu_type) {
1153be691f3bSpatrick      size_t ocount = 0;
1154be691f3bSpatrick      typedef int (*posix_spawnattr_setarchpref_np_t)(
1155be691f3bSpatrick          posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *);
1156be691f3bSpatrick      posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn =
1157be691f3bSpatrick          (posix_spawnattr_setarchpref_np_t)dlsym(
1158be691f3bSpatrick              RTLD_DEFAULT, "posix_spawnattr_setarchpref_np");
1159be691f3bSpatrick      if (set_cpu_subtype && posix_spawnattr_setarchpref_np_fn) {
1160be691f3bSpatrick        error.SetError((*posix_spawnattr_setarchpref_np_fn)(
1161be691f3bSpatrick                           &attr, 1, &cpu_type, &cpu_subtype, &ocount),
1162be691f3bSpatrick                       eErrorTypePOSIX);
1163be691f3bSpatrick        if (error.Fail())
1164be691f3bSpatrick          LLDB_LOG(log,
1165be691f3bSpatrick                   "error: {0}, ::posix_spawnattr_setarchpref_np ( &attr, 1, "
1166be691f3bSpatrick                   "cpu_type = {1:x}, cpu_subtype = {1:x}, count => {2} )",
1167be691f3bSpatrick                   error, cpu_type, cpu_subtype, ocount);
1168be691f3bSpatrick
1169be691f3bSpatrick        if (error.Fail() || ocount != 1)
1170be691f3bSpatrick          return error;
1171be691f3bSpatrick      } else {
1172be691f3bSpatrick        error.SetError(
1173be691f3bSpatrick            ::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount),
1174be691f3bSpatrick            eErrorTypePOSIX);
1175be691f3bSpatrick        if (error.Fail())
1176be691f3bSpatrick          LLDB_LOG(log,
1177be691f3bSpatrick                   "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
1178be691f3bSpatrick                   "cpu_type = {1:x}, count => {2} )",
1179be691f3bSpatrick                   error, cpu_type, ocount);
1180be691f3bSpatrick        if (error.Fail() || ocount != 1)
1181be691f3bSpatrick          return error;
1182be691f3bSpatrick      }
1183be691f3bSpatrick    }
1184be691f3bSpatrick  }
1185be691f3bSpatrick
1186061da546Spatrick  const char *tmp_argv[2];
1187061da546Spatrick  char *const *argv = const_cast<char *const *>(
1188061da546Spatrick      launch_info.GetArguments().GetConstArgumentVector());
1189061da546Spatrick  Environment::Envp envp = launch_info.GetEnvironment().getEnvp();
1190061da546Spatrick  if (argv == NULL) {
1191061da546Spatrick    // posix_spawn gets very unhappy if it doesn't have at least the program
1192061da546Spatrick    // name in argv[0]. One of the side affects I have noticed is the
1193061da546Spatrick    // environment
1194061da546Spatrick    // variables don't make it into the child process if "argv == NULL"!!!
1195061da546Spatrick    tmp_argv[0] = exe_path;
1196061da546Spatrick    tmp_argv[1] = NULL;
1197061da546Spatrick    argv = const_cast<char *const *>(tmp_argv);
1198061da546Spatrick  }
1199061da546Spatrick
1200061da546Spatrick  FileSpec working_dir{launch_info.GetWorkingDirectory()};
1201061da546Spatrick  if (working_dir) {
1202061da546Spatrick    // Set the working directory on this thread only
1203*f6aab3d8Srobert    std::string working_dir_path = working_dir.GetPath();
1204*f6aab3d8Srobert    if (__pthread_chdir(working_dir_path.c_str()) < 0) {
1205061da546Spatrick      if (errno == ENOENT) {
1206061da546Spatrick        error.SetErrorStringWithFormat("No such file or directory: %s",
1207*f6aab3d8Srobert                                       working_dir_path.c_str());
1208061da546Spatrick      } else if (errno == ENOTDIR) {
1209061da546Spatrick        error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
1210*f6aab3d8Srobert                                       working_dir_path.c_str());
1211061da546Spatrick      } else {
1212061da546Spatrick        error.SetErrorStringWithFormat("An unknown error occurred when "
1213061da546Spatrick                                       "changing directory for process "
1214061da546Spatrick                                       "execution.");
1215061da546Spatrick      }
1216061da546Spatrick      return error;
1217061da546Spatrick    }
1218061da546Spatrick  }
1219061da546Spatrick
1220061da546Spatrick  ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
1221061da546Spatrick  const size_t num_file_actions = launch_info.GetNumFileActions();
1222061da546Spatrick  if (num_file_actions > 0) {
1223061da546Spatrick    posix_spawn_file_actions_t file_actions;
1224061da546Spatrick    error.SetError(::posix_spawn_file_actions_init(&file_actions),
1225061da546Spatrick                   eErrorTypePOSIX);
1226061da546Spatrick    if (error.Fail()) {
1227061da546Spatrick      LLDB_LOG(log,
1228061da546Spatrick               "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",
1229061da546Spatrick               error);
1230061da546Spatrick      return error;
1231061da546Spatrick    }
1232061da546Spatrick
1233061da546Spatrick    // Make sure we clean up the posix file actions before exiting this scope.
1234061da546Spatrick    auto cleanup_fileact = llvm::make_scope_exit(
1235061da546Spatrick        [&]() { posix_spawn_file_actions_destroy(&file_actions); });
1236061da546Spatrick
1237061da546Spatrick    for (size_t i = 0; i < num_file_actions; ++i) {
1238061da546Spatrick      const FileAction *launch_file_action =
1239061da546Spatrick          launch_info.GetFileActionAtIndex(i);
1240061da546Spatrick      if (launch_file_action) {
1241061da546Spatrick        if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,
1242061da546Spatrick                                     error))
1243061da546Spatrick          return error;
1244061da546Spatrick      }
1245061da546Spatrick    }
1246061da546Spatrick
1247061da546Spatrick    error.SetError(
1248061da546Spatrick        ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
1249061da546Spatrick        eErrorTypePOSIX);
1250061da546Spatrick
1251061da546Spatrick    if (error.Fail()) {
1252061da546Spatrick      LLDB_LOG(log,
1253061da546Spatrick               "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
1254061da546Spatrick               "file_actions = {3}, "
1255061da546Spatrick               "attr = {4}, argv = {5}, envp = {6} )",
1256061da546Spatrick               error, result_pid, exe_path, &file_actions, &attr, argv,
1257061da546Spatrick               envp.get());
1258061da546Spatrick      if (log) {
1259061da546Spatrick        for (int ii = 0; argv[ii]; ++ii)
1260061da546Spatrick          LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
1261061da546Spatrick      }
1262061da546Spatrick    }
1263061da546Spatrick
1264061da546Spatrick  } else {
1265061da546Spatrick    error.SetError(
1266061da546Spatrick        ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
1267061da546Spatrick        eErrorTypePOSIX);
1268061da546Spatrick
1269061da546Spatrick    if (error.Fail()) {
1270061da546Spatrick      LLDB_LOG(log,
1271061da546Spatrick               "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
1272061da546Spatrick               "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
1273061da546Spatrick               error, result_pid, exe_path, &attr, argv, envp.get());
1274061da546Spatrick      if (log) {
1275061da546Spatrick        for (int ii = 0; argv[ii]; ++ii)
1276061da546Spatrick          LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
1277061da546Spatrick      }
1278061da546Spatrick    }
1279061da546Spatrick  }
1280061da546Spatrick  pid = result_pid;
1281061da546Spatrick
1282061da546Spatrick  if (working_dir) {
1283061da546Spatrick    // No more thread specific current working directory
1284061da546Spatrick    __pthread_fchdir(-1);
1285061da546Spatrick  }
1286061da546Spatrick
1287061da546Spatrick  return error;
1288061da546Spatrick}
1289061da546Spatrick
1290061da546Spatrickstatic bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) {
1291061da546Spatrick  bool result = false;
1292061da546Spatrick
1293dda28197Spatrick#if TARGET_OS_OSX
1294061da546Spatrick  bool launchingAsRoot = launch_info.GetUserID() == 0;
1295061da546Spatrick  bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
1296061da546Spatrick
1297061da546Spatrick  if (launchingAsRoot && !currentUserIsRoot) {
1298061da546Spatrick    // If current user is already root, we don't need XPC's help.
1299061da546Spatrick    result = true;
1300061da546Spatrick  }
1301061da546Spatrick#endif
1302061da546Spatrick
1303061da546Spatrick  return result;
1304061da546Spatrick}
1305061da546Spatrick
1306061da546SpatrickStatus Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
1307061da546Spatrick  Status error;
1308061da546Spatrick
1309061da546Spatrick  FileSystem &fs = FileSystem::Instance();
1310061da546Spatrick  FileSpec exe_spec(launch_info.GetExecutableFile());
1311061da546Spatrick
1312061da546Spatrick  if (!fs.Exists(exe_spec))
1313061da546Spatrick    FileSystem::Instance().Resolve(exe_spec);
1314061da546Spatrick
1315061da546Spatrick  if (!fs.Exists(exe_spec))
1316061da546Spatrick    FileSystem::Instance().ResolveExecutableLocation(exe_spec);
1317061da546Spatrick
1318061da546Spatrick  if (!fs.Exists(exe_spec)) {
1319061da546Spatrick    error.SetErrorStringWithFormatv("executable doesn't exist: '{0}'",
1320061da546Spatrick                                    exe_spec);
1321061da546Spatrick    return error;
1322061da546Spatrick  }
1323061da546Spatrick
1324061da546Spatrick  if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) {
1325dda28197Spatrick#if TARGET_OS_OSX
1326061da546Spatrick    return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(),
1327061da546Spatrick                                              launch_info);
1328061da546Spatrick#else
1329061da546Spatrick    error.SetErrorString("launching a process in a new terminal is not "
1330061da546Spatrick                         "supported on iOS devices");
1331061da546Spatrick    return error;
1332061da546Spatrick#endif
1333061da546Spatrick  }
1334061da546Spatrick
1335061da546Spatrick  lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
1336061da546Spatrick
1337*f6aab3d8Srobert  auto exe_path = exe_spec.GetPath();
1338061da546Spatrick
1339061da546Spatrick  if (ShouldLaunchUsingXPC(launch_info))
1340*f6aab3d8Srobert    error = LaunchProcessXPC(exe_path.c_str(), launch_info, pid);
1341061da546Spatrick  else
1342*f6aab3d8Srobert    error = LaunchProcessPosixSpawn(exe_path.c_str(), launch_info, pid);
1343061da546Spatrick
1344061da546Spatrick  if (pid != LLDB_INVALID_PROCESS_ID) {
1345061da546Spatrick    // If all went well, then set the process ID into the launch info
1346061da546Spatrick    launch_info.SetProcessID(pid);
1347061da546Spatrick
1348061da546Spatrick    // Make sure we reap any processes we spawn or we will have zombies.
1349061da546Spatrick    bool monitoring = launch_info.MonitorProcess();
1350061da546Spatrick    UNUSED_IF_ASSERT_DISABLED(monitoring);
1351061da546Spatrick    assert(monitoring);
1352061da546Spatrick  } else {
1353061da546Spatrick    // Invalid process ID, something didn't go well
1354061da546Spatrick    if (error.Success())
1355061da546Spatrick      error.SetErrorString("process launch failed for unknown reasons");
1356061da546Spatrick  }
1357061da546Spatrick  return error;
1358061da546Spatrick}
1359061da546Spatrick
1360061da546SpatrickStatus Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
1361061da546Spatrick  Status error;
1362061da546Spatrick  if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {
1363061da546Spatrick    FileSpec expand_tool_spec = HostInfo::GetSupportExeDir();
1364061da546Spatrick    if (!expand_tool_spec) {
1365061da546Spatrick      error.SetErrorString(
1366061da546Spatrick          "could not get support executable directory for lldb-argdumper tool");
1367061da546Spatrick      return error;
1368061da546Spatrick    }
1369061da546Spatrick    expand_tool_spec.AppendPathComponent("lldb-argdumper");
1370061da546Spatrick    if (!FileSystem::Instance().Exists(expand_tool_spec)) {
1371061da546Spatrick      error.SetErrorStringWithFormat(
1372061da546Spatrick          "could not find the lldb-argdumper tool: %s",
1373061da546Spatrick          expand_tool_spec.GetPath().c_str());
1374061da546Spatrick      return error;
1375061da546Spatrick    }
1376061da546Spatrick
1377061da546Spatrick    StreamString expand_tool_spec_stream;
1378061da546Spatrick    expand_tool_spec_stream.Printf("\"%s\"",
1379061da546Spatrick                                   expand_tool_spec.GetPath().c_str());
1380061da546Spatrick
1381061da546Spatrick    Args expand_command(expand_tool_spec_stream.GetData());
1382061da546Spatrick    expand_command.AppendArguments(launch_info.GetArguments());
1383061da546Spatrick
1384061da546Spatrick    int status;
1385061da546Spatrick    std::string output;
1386061da546Spatrick    FileSpec cwd(launch_info.GetWorkingDirectory());
1387061da546Spatrick    if (!FileSystem::Instance().Exists(cwd)) {
1388061da546Spatrick      char *wd = getcwd(nullptr, 0);
1389061da546Spatrick      if (wd == nullptr) {
1390061da546Spatrick        error.SetErrorStringWithFormat(
1391061da546Spatrick            "cwd does not exist; cannot launch with shell argument expansion");
1392061da546Spatrick        return error;
1393061da546Spatrick      } else {
1394061da546Spatrick        FileSpec working_dir(wd);
1395061da546Spatrick        free(wd);
1396061da546Spatrick        launch_info.SetWorkingDirectory(working_dir);
1397061da546Spatrick      }
1398061da546Spatrick    }
1399be691f3bSpatrick    bool run_in_shell = true;
1400061da546Spatrick    bool hide_stderr = true;
1401be691f3bSpatrick    Status e =
1402be691f3bSpatrick        RunShellCommand(expand_command, cwd, &status, nullptr, &output,
1403be691f3bSpatrick                        std::chrono::seconds(10), run_in_shell, hide_stderr);
1404061da546Spatrick
1405061da546Spatrick    if (e.Fail())
1406061da546Spatrick      return e;
1407061da546Spatrick
1408061da546Spatrick    if (status != 0) {
1409061da546Spatrick      error.SetErrorStringWithFormat("lldb-argdumper exited with error %d",
1410061da546Spatrick                                     status);
1411061da546Spatrick      return error;
1412061da546Spatrick    }
1413061da546Spatrick
1414061da546Spatrick    auto data_sp = StructuredData::ParseJSON(output);
1415061da546Spatrick    if (!data_sp) {
1416061da546Spatrick      error.SetErrorString("invalid JSON");
1417061da546Spatrick      return error;
1418061da546Spatrick    }
1419061da546Spatrick
1420061da546Spatrick    auto dict_sp = data_sp->GetAsDictionary();
1421061da546Spatrick    if (!data_sp) {
1422061da546Spatrick      error.SetErrorString("invalid JSON");
1423061da546Spatrick      return error;
1424061da546Spatrick    }
1425061da546Spatrick
1426061da546Spatrick    auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
1427061da546Spatrick    if (!args_sp) {
1428061da546Spatrick      error.SetErrorString("invalid JSON");
1429061da546Spatrick      return error;
1430061da546Spatrick    }
1431061da546Spatrick
1432061da546Spatrick    auto args_array_sp = args_sp->GetAsArray();
1433061da546Spatrick    if (!args_array_sp) {
1434061da546Spatrick      error.SetErrorString("invalid JSON");
1435061da546Spatrick      return error;
1436061da546Spatrick    }
1437061da546Spatrick
1438061da546Spatrick    launch_info.GetArguments().Clear();
1439061da546Spatrick
1440061da546Spatrick    for (size_t i = 0; i < args_array_sp->GetSize(); i++) {
1441061da546Spatrick      auto item_sp = args_array_sp->GetItemAtIndex(i);
1442061da546Spatrick      if (!item_sp)
1443061da546Spatrick        continue;
1444061da546Spatrick      auto str_sp = item_sp->GetAsString();
1445061da546Spatrick      if (!str_sp)
1446061da546Spatrick        continue;
1447061da546Spatrick
1448061da546Spatrick      launch_info.GetArguments().AppendArgument(str_sp->GetValue());
1449061da546Spatrick    }
1450061da546Spatrick  }
1451061da546Spatrick
1452061da546Spatrick  return error;
1453061da546Spatrick}
1454061da546Spatrick
1455061da546Spatrickllvm::Expected<HostThread> Host::StartMonitoringChildProcess(
1456*f6aab3d8Srobert    const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) {
1457061da546Spatrick  unsigned long mask = DISPATCH_PROC_EXIT;
1458061da546Spatrick
1459*f6aab3d8Srobert  Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));
1460061da546Spatrick
1461061da546Spatrick  dispatch_source_t source = ::dispatch_source_create(
1462061da546Spatrick      DISPATCH_SOURCE_TYPE_PROC, pid, mask,
1463061da546Spatrick      ::dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1464061da546Spatrick
1465061da546Spatrick  LLDB_LOGF(log,
1466*f6aab3d8Srobert            "Host::StartMonitoringChildProcess(callback, pid=%i) source = %p\n",
1467*f6aab3d8Srobert            static_cast<int>(pid), static_cast<void *>(source));
1468061da546Spatrick
1469061da546Spatrick  if (source) {
1470061da546Spatrick    Host::MonitorChildProcessCallback callback_copy = callback;
1471061da546Spatrick    ::dispatch_source_set_cancel_handler(source, ^{
1472061da546Spatrick      dispatch_release(source);
1473061da546Spatrick    });
1474061da546Spatrick    ::dispatch_source_set_event_handler(source, ^{
1475061da546Spatrick
1476061da546Spatrick      int status = 0;
1477061da546Spatrick      int wait_pid = 0;
1478061da546Spatrick      wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, 0);
1479061da546Spatrick      if (wait_pid >= 0) {
1480061da546Spatrick        int signal = 0;
1481061da546Spatrick        int exit_status = 0;
1482061da546Spatrick        const char *status_cstr = NULL;
1483*f6aab3d8Srobert        if (WIFEXITED(status)) {
1484061da546Spatrick          exit_status = WEXITSTATUS(status);
1485061da546Spatrick          status_cstr = "EXITED";
1486061da546Spatrick        } else if (WIFSIGNALED(status)) {
1487061da546Spatrick          signal = WTERMSIG(status);
1488061da546Spatrick          status_cstr = "SIGNALED";
1489061da546Spatrick          exit_status = -1;
1490061da546Spatrick        } else {
1491*f6aab3d8Srobert          llvm_unreachable("Unknown status");
1492061da546Spatrick        }
1493061da546Spatrick
1494061da546Spatrick        LLDB_LOGF(log,
1495061da546Spatrick                  "::waitpid (pid = %llu, &status, 0) => pid = %i, status "
1496061da546Spatrick                  "= 0x%8.8x (%s), signal = %i, exit_status = %i",
1497061da546Spatrick                  pid, wait_pid, status, status_cstr, signal, exit_status);
1498061da546Spatrick
1499061da546Spatrick        if (callback_copy)
1500*f6aab3d8Srobert          callback_copy(pid, signal, exit_status);
1501061da546Spatrick
1502061da546Spatrick        ::dispatch_source_cancel(source);
1503061da546Spatrick      }
1504061da546Spatrick    });
1505061da546Spatrick
1506061da546Spatrick    ::dispatch_resume(source);
1507061da546Spatrick  }
1508061da546Spatrick  return HostThread();
1509061da546Spatrick}
1510