xref: /openbsd-src/gnu/llvm/lldb/source/Host/macosx/objcxx/Host.mm (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1//===-- Host.mm -------------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Host/Host.h"
10
11#include <AvailabilityMacros.h>
12
13// On device doesn't have supporty for XPC.
14#if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__))
15#define NO_XPC_SERVICES 1
16#endif
17
18#if !defined(NO_XPC_SERVICES)
19#define __XPC_PRIVATE_H__
20#include <xpc/xpc.h>
21
22#define LaunchUsingXPCRightName "com.apple.lldb.RootDebuggingXPCService"
23
24// These XPC messaging keys are used for communication between Host.mm and the
25// XPC service.
26#define LauncherXPCServiceAuthKey "auth-key"
27#define LauncherXPCServiceArgPrefxKey "arg"
28#define LauncherXPCServiceEnvPrefxKey "env"
29#define LauncherXPCServiceCPUTypeKey "cpuType"
30#define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags"
31#define LauncherXPCServiceStdInPathKeyKey "stdInPath"
32#define LauncherXPCServiceStdOutPathKeyKey "stdOutPath"
33#define LauncherXPCServiceStdErrPathKeyKey "stdErrPath"
34#define LauncherXPCServiceChildPIDKey "childPID"
35#define LauncherXPCServiceErrorTypeKey "errorType"
36#define LauncherXPCServiceCodeTypeKey "errorCode"
37
38#endif
39
40#include "llvm/Support/Host.h"
41
42#include <asl.h>
43#include <crt_externs.h>
44#include <grp.h>
45#include <libproc.h>
46#include <pwd.h>
47#include <spawn.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <sys/proc.h>
51#include <sys/stat.h>
52#include <sys/sysctl.h>
53#include <sys/types.h>
54#include <unistd.h>
55
56#include "lldb/Host/ConnectionFileDescriptor.h"
57#include "lldb/Host/FileSystem.h"
58#include "lldb/Host/HostInfo.h"
59#include "lldb/Host/ProcessLaunchInfo.h"
60#include "lldb/Host/ThreadLauncher.h"
61#include "lldb/Utility/ArchSpec.h"
62#include "lldb/Utility/DataBufferHeap.h"
63#include "lldb/Utility/DataExtractor.h"
64#include "lldb/Utility/Endian.h"
65#include "lldb/Utility/FileSpec.h"
66#include "lldb/Utility/Log.h"
67#include "lldb/Utility/NameMatches.h"
68#include "lldb/Utility/ProcessInfo.h"
69#include "lldb/Utility/StreamString.h"
70#include "lldb/Utility/StructuredData.h"
71#include "lldb/lldb-defines.h"
72
73#include "llvm/ADT/ScopeExit.h"
74#include "llvm/Support/Errno.h"
75#include "llvm/Support/FileSystem.h"
76
77#include "../cfcpp/CFCBundle.h"
78#include "../cfcpp/CFCMutableArray.h"
79#include "../cfcpp/CFCMutableDictionary.h"
80#include "../cfcpp/CFCReleaser.h"
81#include "../cfcpp/CFCString.h"
82
83#include <objc/objc-auto.h>
84
85#include <CoreFoundation/CoreFoundation.h>
86#include <Foundation/Foundation.h>
87
88#ifndef _POSIX_SPAWN_DISABLE_ASLR
89#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
90#endif
91
92extern "C" {
93int __pthread_chdir(const char *path);
94int __pthread_fchdir(int fildes);
95}
96
97using namespace lldb;
98using namespace lldb_private;
99
100bool Host::GetBundleDirectory(const FileSpec &file,
101                              FileSpec &bundle_directory) {
102#if defined(__APPLE__)
103  if (FileSystem::Instance().IsDirectory(file)) {
104    char path[PATH_MAX];
105    if (file.GetPath(path, sizeof(path))) {
106      CFCBundle bundle(path);
107      if (bundle.GetPath(path, sizeof(path))) {
108        bundle_directory.SetFile(path, FileSpec::Style::native);
109        return true;
110      }
111    }
112  }
113#endif
114  bundle_directory.Clear();
115  return false;
116}
117
118bool Host::ResolveExecutableInBundle(FileSpec &file) {
119#if defined(__APPLE__)
120  if (FileSystem::Instance().IsDirectory(file)) {
121    char path[PATH_MAX];
122    if (file.GetPath(path, sizeof(path))) {
123      CFCBundle bundle(path);
124      CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL());
125      if (url.get()) {
126        if (::CFURLGetFileSystemRepresentation(url.get(), YES, (UInt8 *)path,
127                                               sizeof(path))) {
128          file.SetFile(path, FileSpec::Style::native);
129          return true;
130        }
131      }
132    }
133  }
134#endif
135  return false;
136}
137
138static void *AcceptPIDFromInferior(void *arg) {
139  const char *connect_url = (const char *)arg;
140  ConnectionFileDescriptor file_conn;
141  Status error;
142  if (file_conn.Connect(connect_url, &error) == eConnectionStatusSuccess) {
143    char pid_str[256];
144    ::memset(pid_str, 0, sizeof(pid_str));
145    ConnectionStatus status;
146    const size_t pid_str_len = file_conn.Read(
147        pid_str, sizeof(pid_str), std::chrono::seconds(0), status, NULL);
148    if (pid_str_len > 0) {
149      int pid = atoi(pid_str);
150      return (void *)(intptr_t)pid;
151    }
152  }
153  return NULL;
154}
155
156static bool WaitForProcessToSIGSTOP(const lldb::pid_t pid,
157                                    const int timeout_in_seconds) {
158  const int time_delta_usecs = 100000;
159  const int num_retries = timeout_in_seconds / time_delta_usecs;
160  for (int i = 0; i < num_retries; i++) {
161    struct proc_bsdinfo bsd_info;
162    int error = ::proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &bsd_info,
163                               PROC_PIDTBSDINFO_SIZE);
164
165    switch (error) {
166    case EINVAL:
167    case ENOTSUP:
168    case ESRCH:
169    case EPERM:
170      return false;
171
172    default:
173      break;
174
175    case 0:
176      if (bsd_info.pbi_status == SSTOP)
177        return true;
178    }
179    ::usleep(time_delta_usecs);
180  }
181  return false;
182}
183#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
184
185const char *applscript_in_new_tty = "tell application \"Terminal\"\n"
186                                    "   activate\n"
187                                    "	do script \"/bin/bash -c '%s';exit\"\n"
188                                    "end tell\n";
189
190const char *applscript_in_existing_tty = "\
191set the_shell_script to \"/bin/bash -c '%s';exit\"\n\
192tell application \"Terminal\"\n\
193	repeat with the_window in (get windows)\n\
194		repeat with the_tab in tabs of the_window\n\
195			set the_tty to tty in the_tab\n\
196			if the_tty contains \"%s\" then\n\
197				if the_tab is not busy then\n\
198					set selected of the_tab to true\n\
199					set frontmost of the_window to true\n\
200					do script the_shell_script in the_tab\n\
201					return\n\
202				end if\n\
203			end if\n\
204		end repeat\n\
205	end repeat\n\
206	do script the_shell_script\n\
207end tell\n";
208
209static Status
210LaunchInNewTerminalWithAppleScript(const char *exe_path,
211                                   ProcessLaunchInfo &launch_info) {
212  Status error;
213  char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
214  if (::mktemp(unix_socket_name) == NULL) {
215    error.SetErrorString("failed to make temporary path for a unix socket");
216    return error;
217  }
218
219  StreamString command;
220  FileSpec darwin_debug_file_spec = HostInfo::GetSupportExeDir();
221  if (!darwin_debug_file_spec) {
222    error.SetErrorString("can't locate the 'darwin-debug' executable");
223    return error;
224  }
225
226  darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
227
228  if (!FileSystem::Instance().Exists(darwin_debug_file_spec)) {
229    error.SetErrorStringWithFormat(
230        "the 'darwin-debug' executable doesn't exists at '%s'",
231        darwin_debug_file_spec.GetPath().c_str());
232    return error;
233  }
234
235  char launcher_path[PATH_MAX];
236  darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
237
238  const ArchSpec &arch_spec = launch_info.GetArchitecture();
239  // Only set the architecture if it is valid and if it isn't Haswell (x86_64h).
240  if (arch_spec.IsValid() &&
241      arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h)
242    command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());
243
244  command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name);
245
246  if (arch_spec.IsValid())
247    command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
248
249  FileSpec working_dir{launch_info.GetWorkingDirectory()};
250  if (working_dir)
251    command.Printf(" --working-dir '%s'", working_dir.GetCString());
252  else {
253    char cwd[PATH_MAX];
254    if (getcwd(cwd, PATH_MAX))
255      command.Printf(" --working-dir '%s'", cwd);
256  }
257
258  if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
259    command.PutCString(" --disable-aslr");
260
261  // We are launching on this host in a terminal. So compare the environment on
262  // the host to what is supplied in the launch_info. Any items that aren't in
263  // the host environment need to be sent to darwin-debug. If we send all
264  // environment entries, we might blow the max command line length, so we only
265  // send user modified entries.
266  Environment host_env = Host::GetEnvironment();
267
268  for (const auto &KV : launch_info.GetEnvironment()) {
269    auto host_entry = host_env.find(KV.first());
270    if (host_entry == host_env.end() || host_entry->second != KV.second)
271      command.Format(" --env='{0}'", Environment::compose(KV));
272  }
273
274  command.PutCString(" -- ");
275
276  const char **argv = launch_info.GetArguments().GetConstArgumentVector();
277  if (argv) {
278    for (size_t i = 0; argv[i] != NULL; ++i) {
279      if (i == 0)
280        command.Printf(" '%s'", exe_path);
281      else
282        command.Printf(" '%s'", argv[i]);
283    }
284  } else {
285    command.Printf(" '%s'", exe_path);
286  }
287  command.PutCString(" ; echo Process exited with status $?");
288  if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))
289    command.PutCString(" ; exit");
290
291  StreamString applescript_source;
292
293  applescript_source.Printf(applscript_in_new_tty,
294                            command.GetString().str().c_str());
295  NSAppleScript *applescript = [[NSAppleScript alloc]
296      initWithSource:[NSString stringWithCString:applescript_source.GetString()
297                                                     .str()
298                                                     .c_str()
299                                        encoding:NSUTF8StringEncoding]];
300
301  lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
302
303  Status lldb_error;
304  // Sleep and wait a bit for debugserver to start to listen...
305  ConnectionFileDescriptor file_conn;
306  char connect_url[128];
307  ::snprintf(connect_url, sizeof(connect_url), "unix-accept://%s",
308             unix_socket_name);
309
310  // Spawn a new thread to accept incoming connection on the connect_url
311  // so we can grab the pid from the inferior. We have to do this because we
312  // are sending an AppleScript that will launch a process in Terminal.app,
313  // in a shell and the shell will fork/exec a couple of times before we get
314  // to the process that we wanted to launch. So when our process actually
315  // gets launched, we will handshake with it and get the process ID for it.
316  llvm::Expected<HostThread> accept_thread = ThreadLauncher::LaunchThread(
317      unix_socket_name, AcceptPIDFromInferior, connect_url);
318
319  if (!accept_thread)
320    return Status(accept_thread.takeError());
321
322  [applescript executeAndReturnError:nil];
323
324  thread_result_t accept_thread_result = NULL;
325  lldb_error = accept_thread->Join(&accept_thread_result);
326  if (lldb_error.Success() && accept_thread_result) {
327    pid = (intptr_t)accept_thread_result;
328
329    // Wait for process to be stopped at the entry point by watching
330    // for the process status to be set to SSTOP which indicates it it
331    // SIGSTOP'ed at the entry point
332    WaitForProcessToSIGSTOP(pid, 5);
333  }
334
335  llvm::sys::fs::remove(unix_socket_name);
336  [applescript release];
337  if (pid != LLDB_INVALID_PROCESS_ID)
338    launch_info.SetProcessID(pid);
339  return error;
340}
341
342#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
343
344bool Host::OpenFileInExternalEditor(const FileSpec &file_spec,
345                                    uint32_t line_no) {
346#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
347  return false;
348#else
349  // We attach this to an 'odoc' event to specify a particular selection
350  typedef struct {
351    int16_t reserved0; // must be zero
352    int16_t fLineNumber;
353    int32_t fSelStart;
354    int32_t fSelEnd;
355    uint32_t reserved1; // must be zero
356    uint32_t reserved2; // must be zero
357  } BabelAESelInfo;
358
359  Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_HOST));
360  char file_path[PATH_MAX];
361  file_spec.GetPath(file_path, PATH_MAX);
362  CFCString file_cfstr(file_path, kCFStringEncodingUTF8);
363  CFCReleaser<CFURLRef> file_URL(::CFURLCreateWithFileSystemPath(
364      NULL, file_cfstr.get(), kCFURLPOSIXPathStyle, false));
365
366  LLDB_LOGF(log,
367            "Sending source file: \"%s\" and line: %d to external editor.\n",
368            file_path, line_no);
369
370  long error;
371  BabelAESelInfo file_and_line_info = {
372      0,                      // reserved0
373      (int16_t)(line_no - 1), // fLineNumber (zero based line number)
374      1,                      // fSelStart
375      1024,                   // fSelEnd
376      0,                      // reserved1
377      0                       // reserved2
378  };
379
380  AEKeyDesc file_and_line_desc;
381
382  error = ::AECreateDesc(typeUTF8Text, &file_and_line_info,
383                         sizeof(file_and_line_info),
384                         &(file_and_line_desc.descContent));
385
386  if (error != noErr) {
387    LLDB_LOGF(log, "Error creating AEDesc: %ld.\n", error);
388    return false;
389  }
390
391  file_and_line_desc.descKey = keyAEPosition;
392
393  static std::string g_app_name;
394  static FSRef g_app_fsref;
395
396  LSApplicationParameters app_params;
397  ::memset(&app_params, 0, sizeof(app_params));
398  app_params.flags =
399      kLSLaunchDefaults | kLSLaunchDontAddToRecents | kLSLaunchDontSwitch;
400
401  char *external_editor = ::getenv("LLDB_EXTERNAL_EDITOR");
402
403  if (external_editor) {
404    LLDB_LOGF(log, "Looking for external editor \"%s\".\n", external_editor);
405
406    if (g_app_name.empty() ||
407        strcmp(g_app_name.c_str(), external_editor) != 0) {
408      CFCString editor_name(external_editor, kCFStringEncodingUTF8);
409      error = ::LSFindApplicationForInfo(kLSUnknownCreator, NULL,
410                                         editor_name.get(), &g_app_fsref, NULL);
411
412      // If we found the app, then store away the name so we don't have to
413      // re-look it up.
414      if (error != noErr) {
415        LLDB_LOGF(log,
416                  "Could not find External Editor application, error: %ld.\n",
417                  error);
418        return false;
419      }
420    }
421    app_params.application = &g_app_fsref;
422  }
423
424  ProcessSerialNumber psn;
425  CFCReleaser<CFArrayRef> file_array(
426      CFArrayCreate(NULL, (const void **)file_URL.ptr_address(false), 1, NULL));
427  error = ::LSOpenURLsWithRole(file_array.get(), kLSRolesAll,
428                               &file_and_line_desc, &app_params, &psn, 1);
429
430  AEDisposeDesc(&(file_and_line_desc.descContent));
431
432  if (error != noErr) {
433    LLDB_LOGF(log, "LSOpenURLsWithRole failed, error: %ld.\n", error);
434
435    return false;
436  }
437
438  return true;
439#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
440}
441
442Environment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); }
443
444static bool GetMacOSXProcessCPUType(ProcessInstanceInfo &process_info) {
445  if (process_info.ProcessIDIsValid()) {
446    // Make a new mib to stay thread safe
447    int mib[CTL_MAXNAME] = {
448        0,
449    };
450    size_t mib_len = CTL_MAXNAME;
451    if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len))
452      return false;
453
454    mib[mib_len] = process_info.GetProcessID();
455    mib_len++;
456
457    cpu_type_t cpu, sub = 0;
458    size_t len = sizeof(cpu);
459    if (::sysctl(mib, mib_len, &cpu, &len, 0, 0) == 0) {
460      switch (cpu) {
461      case CPU_TYPE_I386:
462        sub = CPU_SUBTYPE_I386_ALL;
463        break;
464      case CPU_TYPE_X86_64:
465        sub = CPU_SUBTYPE_X86_64_ALL;
466        break;
467
468#if defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64_ALL)
469      case CPU_TYPE_ARM64:
470        sub = CPU_SUBTYPE_ARM64_ALL;
471        break;
472#endif
473
474#if defined(CPU_TYPE_ARM64_32) && defined(CPU_SUBTYPE_ARM64_32_ALL)
475      case CPU_TYPE_ARM64_32:
476        sub = CPU_SUBTYPE_ARM64_32_ALL;
477        break;
478#endif
479
480      case CPU_TYPE_ARM: {
481        // Note that we fetched the cpu type from the PROCESS but we can't get a
482        // cpusubtype of the
483        // process -- we can only get the host's cpu subtype.
484        uint32_t cpusubtype = 0;
485        len = sizeof(cpusubtype);
486        if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
487          sub = cpusubtype;
488
489        bool host_cpu_is_64bit;
490        uint32_t is64bit_capable;
491        size_t is64bit_capable_len = sizeof(is64bit_capable);
492        host_cpu_is_64bit =
493            sysctlbyname("hw.cpu64bit_capable", &is64bit_capable,
494                         &is64bit_capable_len, NULL, 0) == 0;
495
496        // if the host is an armv8 device, its cpusubtype will be in
497        // CPU_SUBTYPE_ARM64 numbering
498        // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value
499        // instead.
500
501        if (host_cpu_is_64bit) {
502          sub = CPU_SUBTYPE_ARM_V7;
503        }
504      } break;
505
506      default:
507        break;
508      }
509      process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, sub);
510      return true;
511    }
512  }
513  process_info.GetArchitecture().Clear();
514  return false;
515}
516
517static bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
518                                 ProcessInstanceInfo &process_info) {
519  if (process_info.ProcessIDIsValid()) {
520    int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2,
521                            (int)process_info.GetProcessID()};
522
523    size_t arg_data_size = 0;
524    if (::sysctl(proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) ||
525        arg_data_size == 0)
526      arg_data_size = 8192;
527
528    // Add a few bytes to the calculated length, I know we need to add at least
529    // one byte
530    // to this number otherwise we get junk back, so add 128 just in case...
531    DataBufferHeap arg_data(arg_data_size + 128, 0);
532    arg_data_size = arg_data.GetByteSize();
533    if (::sysctl(proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size, NULL,
534                 0) == 0) {
535      DataExtractor data(arg_data.GetBytes(), arg_data_size,
536                         endian::InlHostByteOrder(), sizeof(void *));
537      lldb::offset_t offset = 0;
538      uint32_t argc = data.GetU32(&offset);
539      llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
540      const llvm::Triple::ArchType triple_arch = triple.getArch();
541      const bool check_for_ios_simulator =
542          (triple_arch == llvm::Triple::x86 ||
543           triple_arch == llvm::Triple::x86_64);
544      const char *cstr = data.GetCStr(&offset);
545      if (cstr) {
546        process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);
547
548        if (match_info_ptr == NULL ||
549            NameMatches(
550                process_info.GetExecutableFile().GetFilename().GetCString(),
551                match_info_ptr->GetNameMatchType(),
552                match_info_ptr->GetProcessInfo().GetName())) {
553          // Skip NULLs
554          while (true) {
555            const uint8_t *p = data.PeekData(offset, 1);
556            if ((p == NULL) || (*p != '\0'))
557              break;
558            ++offset;
559          }
560          // Now extract all arguments
561          Args &proc_args = process_info.GetArguments();
562          for (int i = 0; i < static_cast<int>(argc); ++i) {
563            cstr = data.GetCStr(&offset);
564            if (cstr)
565              proc_args.AppendArgument(llvm::StringRef(cstr));
566          }
567
568          Environment &proc_env = process_info.GetEnvironment();
569          while ((cstr = data.GetCStr(&offset))) {
570            if (cstr[0] == '\0')
571              break;
572
573            if (check_for_ios_simulator) {
574              if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) ==
575                  0)
576                process_info.GetArchitecture().GetTriple().setOS(
577                    llvm::Triple::IOS);
578              else
579                process_info.GetArchitecture().GetTriple().setOS(
580                    llvm::Triple::MacOSX);
581            }
582
583            proc_env.insert(cstr);
584          }
585          return true;
586        }
587      }
588    }
589  }
590  return false;
591}
592
593static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) {
594  if (process_info.ProcessIDIsValid()) {
595    int mib[4];
596    mib[0] = CTL_KERN;
597    mib[1] = KERN_PROC;
598    mib[2] = KERN_PROC_PID;
599    mib[3] = process_info.GetProcessID();
600    struct kinfo_proc proc_kinfo;
601    size_t proc_kinfo_size = sizeof(struct kinfo_proc);
602
603    if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
604      if (proc_kinfo_size > 0) {
605        process_info.SetParentProcessID(proc_kinfo.kp_eproc.e_ppid);
606        process_info.SetUserID(proc_kinfo.kp_eproc.e_pcred.p_ruid);
607        process_info.SetGroupID(proc_kinfo.kp_eproc.e_pcred.p_rgid);
608        process_info.SetEffectiveUserID(proc_kinfo.kp_eproc.e_ucred.cr_uid);
609        if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
610          process_info.SetEffectiveGroupID(
611              proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
612        else
613          process_info.SetEffectiveGroupID(UINT32_MAX);
614        return true;
615      }
616    }
617  }
618  process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
619  process_info.SetUserID(UINT32_MAX);
620  process_info.SetGroupID(UINT32_MAX);
621  process_info.SetEffectiveUserID(UINT32_MAX);
622  process_info.SetEffectiveGroupID(UINT32_MAX);
623  return false;
624}
625
626uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
627                             ProcessInstanceInfoList &process_infos) {
628  std::vector<struct kinfo_proc> kinfos;
629
630  int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
631
632  size_t pid_data_size = 0;
633  if (::sysctl(mib, 3, nullptr, &pid_data_size, nullptr, 0) != 0)
634    return 0;
635
636  // Add a few extra in case a few more show up
637  const size_t estimated_pid_count =
638      (pid_data_size / sizeof(struct kinfo_proc)) + 10;
639
640  kinfos.resize(estimated_pid_count);
641  pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
642
643  if (::sysctl(mib, 3, &kinfos[0], &pid_data_size, nullptr, 0) != 0)
644    return 0;
645
646  const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
647
648  bool all_users = match_info.GetMatchAllUsers();
649  const lldb::pid_t our_pid = getpid();
650  const uid_t our_uid = getuid();
651  for (size_t i = 0; i < actual_pid_count; i++) {
652    const struct kinfo_proc &kinfo = kinfos[i];
653
654    bool kinfo_user_matches = false;
655    if (all_users)
656      kinfo_user_matches = true;
657    else
658      kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
659
660    // Special case, if lldb is being run as root we can attach to anything.
661    if (our_uid == 0)
662      kinfo_user_matches = true;
663
664    if (!kinfo_user_matches || // Make sure the user is acceptable
665        static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) ==
666            our_pid ||                   // Skip this process
667        kinfo.kp_proc.p_pid == 0 ||      // Skip kernel (kernel pid is zero)
668        kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains...
669        kinfo.kp_proc.p_flag & P_TRACED ||   // Being debugged?
670        kinfo.kp_proc.p_flag & P_WEXIT ||    // Working on exiting?
671        kinfo.kp_proc.p_flag & P_TRANSLATED) // Skip translated ppc (Rosetta)
672      continue;
673
674    ProcessInstanceInfo process_info;
675    process_info.SetProcessID(kinfo.kp_proc.p_pid);
676    process_info.SetParentProcessID(kinfo.kp_eproc.e_ppid);
677    process_info.SetUserID(kinfo.kp_eproc.e_pcred.p_ruid);
678    process_info.SetGroupID(kinfo.kp_eproc.e_pcred.p_rgid);
679    process_info.SetEffectiveUserID(kinfo.kp_eproc.e_ucred.cr_uid);
680    if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
681      process_info.SetEffectiveGroupID(kinfo.kp_eproc.e_ucred.cr_groups[0]);
682    else
683      process_info.SetEffectiveGroupID(UINT32_MAX);
684
685    // Make sure our info matches before we go fetch the name and cpu type
686    if (!match_info.UserIDsMatch(process_info) ||
687        !match_info.ProcessIDsMatch(process_info))
688      continue;
689
690    // Get CPU type first so we can know to look for iOS simulator is we have
691    // x86 or x86_64
692    if (GetMacOSXProcessCPUType(process_info)) {
693      if (GetMacOSXProcessArgs(&match_info, process_info)) {
694        if (match_info.Matches(process_info))
695          process_infos.Append(process_info);
696      }
697    }
698  }
699  return process_infos.GetSize();
700}
701
702bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
703  process_info.SetProcessID(pid);
704  bool success = false;
705
706  // Get CPU type first so we can know to look for iOS simulator is we have x86
707  // or x86_64
708  if (GetMacOSXProcessCPUType(process_info))
709    success = true;
710
711  if (GetMacOSXProcessArgs(NULL, process_info))
712    success = true;
713
714  if (GetMacOSXProcessUserAndGroup(process_info))
715    success = true;
716
717  if (success)
718    return true;
719
720  process_info.Clear();
721  return false;
722}
723
724#if !NO_XPC_SERVICES
725static void PackageXPCArguments(xpc_object_t message, const char *prefix,
726                                const Args &args) {
727  size_t count = args.GetArgumentCount();
728  char buf[50]; // long enough for 'argXXX'
729  memset(buf, 0, 50);
730  sprintf(buf, "%sCount", prefix);
731  xpc_dictionary_set_int64(message, buf, count);
732  for (size_t i = 0; i < count; i++) {
733    memset(buf, 0, 50);
734    sprintf(buf, "%s%zi", prefix, i);
735    xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
736  }
737}
738
739static void PackageXPCEnvironment(xpc_object_t message, llvm::StringRef prefix,
740                                  const Environment &env) {
741  xpc_dictionary_set_int64(message, (prefix + "Count").str().c_str(),
742                           env.size());
743  size_t i = 0;
744  for (const auto &KV : env) {
745    xpc_dictionary_set_string(message, (prefix + llvm::Twine(i)).str().c_str(),
746                              Environment::compose(KV).c_str());
747  }
748}
749
750/*
751 A valid authorizationRef means that
752    - there is the LaunchUsingXPCRightName rights in the /etc/authorization
753    - we have successfully copied the rights to be send over the XPC wire
754 Once obtained, it will be valid for as long as the process lives.
755 */
756static AuthorizationRef authorizationRef = NULL;
757static Status getXPCAuthorization(ProcessLaunchInfo &launch_info) {
758  Status error;
759  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
760                                                  LIBLLDB_LOG_PROCESS));
761
762  if ((launch_info.GetUserID() == 0) && !authorizationRef) {
763    OSStatus createStatus =
764        AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
765                            kAuthorizationFlagDefaults, &authorizationRef);
766    if (createStatus != errAuthorizationSuccess) {
767      error.SetError(1, eErrorTypeGeneric);
768      error.SetErrorString("Can't create authorizationRef.");
769      LLDB_LOG(log, "error: {0}", error);
770      return error;
771    }
772
773    OSStatus rightsStatus =
774        AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
775    if (rightsStatus != errAuthorizationSuccess) {
776      // No rights in the security database, Create it with the right prompt.
777      CFStringRef prompt =
778          CFSTR("Xcode is trying to take control of a root process.");
779      CFStringRef keys[] = {CFSTR("en")};
780      CFTypeRef values[] = {prompt};
781      CFDictionaryRef promptDict = CFDictionaryCreate(
782          kCFAllocatorDefault, (const void **)keys, (const void **)values, 1,
783          &kCFCopyStringDictionaryKeyCallBacks,
784          &kCFTypeDictionaryValueCallBacks);
785
786      CFStringRef keys1[] = {CFSTR("class"), CFSTR("group"), CFSTR("comment"),
787                             CFSTR("default-prompt"), CFSTR("shared")};
788      CFTypeRef values1[] = {CFSTR("user"), CFSTR("admin"),
789                             CFSTR(LaunchUsingXPCRightName), promptDict,
790                             kCFBooleanFalse};
791      CFDictionaryRef dict = CFDictionaryCreate(
792          kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5,
793          &kCFCopyStringDictionaryKeyCallBacks,
794          &kCFTypeDictionaryValueCallBacks);
795      rightsStatus = AuthorizationRightSet(
796          authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
797      CFRelease(promptDict);
798      CFRelease(dict);
799    }
800
801    OSStatus copyRightStatus = errAuthorizationDenied;
802    if (rightsStatus == errAuthorizationSuccess) {
803      AuthorizationItem item1 = {LaunchUsingXPCRightName, 0, NULL, 0};
804      AuthorizationItem items[] = {item1};
805      AuthorizationRights requestedRights = {1, items};
806      AuthorizationFlags authorizationFlags =
807          kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
808      copyRightStatus = AuthorizationCopyRights(
809          authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment,
810          authorizationFlags, NULL);
811    }
812
813    if (copyRightStatus != errAuthorizationSuccess) {
814      // Eventually when the commandline supports running as root and the user
815      // is not
816      // logged in in the current audit session, we will need the trick in gdb
817      // where
818      // we ask the user to type in the root passwd in the terminal.
819      error.SetError(2, eErrorTypeGeneric);
820      error.SetErrorStringWithFormat(
821          "Launching as root needs root authorization.");
822      LLDB_LOG(log, "error: {0}", error);
823
824      if (authorizationRef) {
825        AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
826        authorizationRef = NULL;
827      }
828    }
829  }
830
831  return error;
832}
833#endif
834
835static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {
836  short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
837
838  if (launch_info.GetFlags().Test(eLaunchFlagExec))
839    flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
840
841  if (launch_info.GetFlags().Test(eLaunchFlagDebug))
842    flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
843
844  if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
845    flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
846
847  if (launch_info.GetLaunchInSeparateProcessGroup())
848    flags |= POSIX_SPAWN_SETPGROUP;
849
850#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
851#if defined(__x86_64__) || defined(__i386__)
852  static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
853  if (g_use_close_on_exec_flag == eLazyBoolCalculate) {
854    g_use_close_on_exec_flag = eLazyBoolNo;
855
856    llvm::VersionTuple version = HostInfo::GetOSVersion();
857    if (version > llvm::VersionTuple(10, 7)) {
858      // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or
859      // earlier
860      g_use_close_on_exec_flag = eLazyBoolYes;
861    }
862  }
863#else
864  static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
865#endif // defined(__x86_64__) || defined(__i386__)
866  // Close all files exception those with file actions if this is supported.
867  if (g_use_close_on_exec_flag == eLazyBoolYes)
868    flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
869#endif // ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
870  return flags;
871}
872
873static Status LaunchProcessXPC(const char *exe_path,
874                               ProcessLaunchInfo &launch_info,
875                               lldb::pid_t &pid) {
876#if !NO_XPC_SERVICES
877  Status error = getXPCAuthorization(launch_info);
878  if (error.Fail())
879    return error;
880
881  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
882                                                  LIBLLDB_LOG_PROCESS));
883
884  uid_t requested_uid = launch_info.GetUserID();
885  const char *xpc_service = nil;
886  bool send_auth = false;
887  AuthorizationExternalForm extForm;
888  if (requested_uid == 0) {
889    if (AuthorizationMakeExternalForm(authorizationRef, &extForm) ==
890        errAuthorizationSuccess) {
891      send_auth = true;
892    } else {
893      error.SetError(3, eErrorTypeGeneric);
894      error.SetErrorStringWithFormat("Launching root via XPC needs to "
895                                     "externalize authorization reference.");
896      LLDB_LOG(log, "error: {0}", error);
897      return error;
898    }
899    xpc_service = LaunchUsingXPCRightName;
900  } else {
901    error.SetError(4, eErrorTypeGeneric);
902    error.SetErrorStringWithFormat(
903        "Launching via XPC is only currently available for root.");
904    LLDB_LOG(log, "error: {0}", error);
905    return error;
906  }
907
908  xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
909
910  xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
911    xpc_type_t type = xpc_get_type(event);
912
913    if (type == XPC_TYPE_ERROR) {
914      if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
915        // The service has either canceled itself, crashed, or been terminated.
916        // The XPC connection is still valid and sending a message to it will
917        // re-launch the service.
918        // If the service is state-full, this is the time to initialize the new
919        // service.
920        return;
921      } else if (event == XPC_ERROR_CONNECTION_INVALID) {
922        // The service is invalid. Either the service name supplied to
923        // xpc_connection_create() is incorrect
924        // or we (this process) have canceled the service; we can do any cleanup
925        // of application state at this point.
926        // printf("Service disconnected");
927        return;
928      } else {
929        // printf("Unexpected error from service: %s",
930        // xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
931      }
932
933    } else {
934      // printf("Received unexpected event in handler");
935    }
936  });
937
938  xpc_connection_set_finalizer_f(conn, xpc_finalizer_t(xpc_release));
939  xpc_connection_resume(conn);
940  xpc_object_t message = xpc_dictionary_create(nil, nil, 0);
941
942  if (send_auth) {
943    xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes,
944                            sizeof(AuthorizationExternalForm));
945  }
946
947  PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey,
948                      launch_info.GetArguments());
949  PackageXPCEnvironment(message, LauncherXPCServiceEnvPrefxKey,
950                        launch_info.GetEnvironment());
951
952  // Posix spawn stuff.
953  xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey,
954                           launch_info.GetArchitecture().GetMachOCPUType());
955  xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey,
956                           GetPosixspawnFlags(launch_info));
957  const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
958  if (file_action && !file_action->GetPath().empty()) {
959    xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey,
960                              file_action->GetPath().str().c_str());
961  }
962  file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
963  if (file_action && !file_action->GetPath().empty()) {
964    xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey,
965                              file_action->GetPath().str().c_str());
966  }
967  file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
968  if (file_action && !file_action->GetPath().empty()) {
969    xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey,
970                              file_action->GetPath().str().c_str());
971  }
972
973  xpc_object_t reply =
974      xpc_connection_send_message_with_reply_sync(conn, message);
975  xpc_type_t returnType = xpc_get_type(reply);
976  if (returnType == XPC_TYPE_DICTIONARY) {
977    pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
978    if (pid == 0) {
979      int errorType =
980          xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
981      int errorCode =
982          xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
983
984      error.SetError(errorCode, eErrorTypeGeneric);
985      error.SetErrorStringWithFormat(
986          "Problems with launching via XPC. Error type : %i, code : %i",
987          errorType, errorCode);
988      LLDB_LOG(log, "error: {0}", error);
989
990      if (authorizationRef) {
991        AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
992        authorizationRef = NULL;
993      }
994    }
995  } else if (returnType == XPC_TYPE_ERROR) {
996    error.SetError(5, eErrorTypeGeneric);
997    error.SetErrorStringWithFormat(
998        "Problems with launching via XPC. XPC error : %s",
999        xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
1000    LLDB_LOG(log, "error: {0}", error);
1001  }
1002
1003  return error;
1004#else
1005  Status error;
1006  return error;
1007#endif
1008}
1009
1010static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
1011                                    Log *log, Status &error) {
1012  if (info == NULL)
1013    return false;
1014
1015  posix_spawn_file_actions_t *file_actions =
1016      static_cast<posix_spawn_file_actions_t *>(_file_actions);
1017
1018  switch (info->GetAction()) {
1019  case FileAction::eFileActionNone:
1020    error.Clear();
1021    break;
1022
1023  case FileAction::eFileActionClose:
1024    if (info->GetFD() == -1)
1025      error.SetErrorString(
1026          "invalid fd for posix_spawn_file_actions_addclose(...)");
1027    else {
1028      error.SetError(
1029          ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),
1030          eErrorTypePOSIX);
1031      if (error.Fail())
1032        LLDB_LOG(log,
1033                 "error: {0}, posix_spawn_file_actions_addclose "
1034                 "(action={1}, fd={2})",
1035                 error, file_actions, info->GetFD());
1036    }
1037    break;
1038
1039  case FileAction::eFileActionDuplicate:
1040    if (info->GetFD() == -1)
1041      error.SetErrorString(
1042          "invalid fd for posix_spawn_file_actions_adddup2(...)");
1043    else if (info->GetActionArgument() == -1)
1044      error.SetErrorString(
1045          "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
1046    else {
1047      error.SetError(
1048          ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),
1049                                             info->GetActionArgument()),
1050          eErrorTypePOSIX);
1051      if (error.Fail())
1052        LLDB_LOG(log,
1053                 "error: {0}, posix_spawn_file_actions_adddup2 "
1054                 "(action={1}, fd={2}, dup_fd={3})",
1055                 error, file_actions, info->GetFD(), info->GetActionArgument());
1056    }
1057    break;
1058
1059  case FileAction::eFileActionOpen:
1060    if (info->GetFD() == -1)
1061      error.SetErrorString(
1062          "invalid fd in posix_spawn_file_actions_addopen(...)");
1063    else {
1064      int oflag = info->GetActionArgument();
1065
1066      mode_t mode = 0;
1067
1068      if (oflag & O_CREAT)
1069        mode = 0640;
1070
1071      error.SetError(::posix_spawn_file_actions_addopen(
1072                         file_actions, info->GetFD(),
1073                         info->GetPath().str().c_str(), oflag, mode),
1074                     eErrorTypePOSIX);
1075      if (error.Fail())
1076        LLDB_LOG(log,
1077                 "error: {0}, posix_spawn_file_actions_addopen (action={1}, "
1078                 "fd={2}, path='{3}', oflag={4}, mode={5})",
1079                 error, file_actions, info->GetFD(), info->GetPath(), oflag,
1080                 mode);
1081    }
1082    break;
1083  }
1084  return error.Success();
1085}
1086
1087static Status LaunchProcessPosixSpawn(const char *exe_path,
1088                                      const ProcessLaunchInfo &launch_info,
1089                                      lldb::pid_t &pid) {
1090  Status error;
1091  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
1092                                                  LIBLLDB_LOG_PROCESS));
1093
1094  posix_spawnattr_t attr;
1095  error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX);
1096
1097  if (error.Fail()) {
1098    LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error);
1099    return error;
1100  }
1101
1102  // Make sure we clean up the posix spawn attributes before exiting this scope.
1103  auto cleanup_attr =
1104      llvm::make_scope_exit([&]() { posix_spawnattr_destroy(&attr); });
1105
1106  sigset_t no_signals;
1107  sigset_t all_signals;
1108  sigemptyset(&no_signals);
1109  sigfillset(&all_signals);
1110  ::posix_spawnattr_setsigmask(&attr, &no_signals);
1111  ::posix_spawnattr_setsigdefault(&attr, &all_signals);
1112
1113  short flags = GetPosixspawnFlags(launch_info);
1114
1115  error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);
1116  if (error.Fail()) {
1117    LLDB_LOG(log,
1118             "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",
1119             error, flags);
1120    return error;
1121  }
1122
1123// posix_spawnattr_setbinpref_np appears to be an Apple extension per:
1124// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
1125#if !defined(__arm__)
1126
1127  // Don't set the binpref if a shell was provided.  After all, that's only
1128  // going to affect what version of the shell
1129  // is launched, not what fork of the binary is launched.  We insert "arch
1130  // --arch <ARCH> as part of the shell invocation
1131  // to do that job on OSX.
1132
1133  if (launch_info.GetShell() == FileSpec()) {
1134    // We don't need to do this for ARM, and we really shouldn't now that we
1135    // have multiple CPU subtypes and no posix_spawnattr call that allows us
1136    // to set which CPU subtype to launch...
1137    const ArchSpec &arch_spec = launch_info.GetArchitecture();
1138    cpu_type_t cpu = arch_spec.GetMachOCPUType();
1139    cpu_type_t sub = arch_spec.GetMachOCPUSubType();
1140    if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
1141        cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
1142        !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try
1143                                          // to set the CPU type or we will fail
1144    {
1145      size_t ocount = 0;
1146      error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount),
1147                     eErrorTypePOSIX);
1148      if (error.Fail())
1149        LLDB_LOG(log,
1150                 "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
1151                 "cpu_type = {1:x}, count => {2} )",
1152                 error, cpu, ocount);
1153
1154      if (error.Fail() || ocount != 1)
1155        return error;
1156    }
1157  }
1158#endif // !defined(__arm__)
1159
1160  const char *tmp_argv[2];
1161  char *const *argv = const_cast<char *const *>(
1162      launch_info.GetArguments().GetConstArgumentVector());
1163  Environment::Envp envp = launch_info.GetEnvironment().getEnvp();
1164  if (argv == NULL) {
1165    // posix_spawn gets very unhappy if it doesn't have at least the program
1166    // name in argv[0]. One of the side affects I have noticed is the
1167    // environment
1168    // variables don't make it into the child process if "argv == NULL"!!!
1169    tmp_argv[0] = exe_path;
1170    tmp_argv[1] = NULL;
1171    argv = const_cast<char *const *>(tmp_argv);
1172  }
1173
1174  FileSpec working_dir{launch_info.GetWorkingDirectory()};
1175  if (working_dir) {
1176    // Set the working directory on this thread only
1177    if (__pthread_chdir(working_dir.GetCString()) < 0) {
1178      if (errno == ENOENT) {
1179        error.SetErrorStringWithFormat("No such file or directory: %s",
1180                                       working_dir.GetCString());
1181      } else if (errno == ENOTDIR) {
1182        error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
1183                                       working_dir.GetCString());
1184      } else {
1185        error.SetErrorStringWithFormat("An unknown error occurred when "
1186                                       "changing directory for process "
1187                                       "execution.");
1188      }
1189      return error;
1190    }
1191  }
1192
1193  ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
1194  const size_t num_file_actions = launch_info.GetNumFileActions();
1195  if (num_file_actions > 0) {
1196    posix_spawn_file_actions_t file_actions;
1197    error.SetError(::posix_spawn_file_actions_init(&file_actions),
1198                   eErrorTypePOSIX);
1199    if (error.Fail()) {
1200      LLDB_LOG(log,
1201               "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",
1202               error);
1203      return error;
1204    }
1205
1206    // Make sure we clean up the posix file actions before exiting this scope.
1207    auto cleanup_fileact = llvm::make_scope_exit(
1208        [&]() { posix_spawn_file_actions_destroy(&file_actions); });
1209
1210    for (size_t i = 0; i < num_file_actions; ++i) {
1211      const FileAction *launch_file_action =
1212          launch_info.GetFileActionAtIndex(i);
1213      if (launch_file_action) {
1214        if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,
1215                                     error))
1216          return error;
1217      }
1218    }
1219
1220    error.SetError(
1221        ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
1222        eErrorTypePOSIX);
1223
1224    if (error.Fail()) {
1225      LLDB_LOG(log,
1226               "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
1227               "file_actions = {3}, "
1228               "attr = {4}, argv = {5}, envp = {6} )",
1229               error, result_pid, exe_path, &file_actions, &attr, argv,
1230               envp.get());
1231      if (log) {
1232        for (int ii = 0; argv[ii]; ++ii)
1233          LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
1234      }
1235    }
1236
1237  } else {
1238    error.SetError(
1239        ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
1240        eErrorTypePOSIX);
1241
1242    if (error.Fail()) {
1243      LLDB_LOG(log,
1244               "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
1245               "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
1246               error, result_pid, exe_path, &attr, argv, envp.get());
1247      if (log) {
1248        for (int ii = 0; argv[ii]; ++ii)
1249          LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
1250      }
1251    }
1252  }
1253  pid = result_pid;
1254
1255  if (working_dir) {
1256    // No more thread specific current working directory
1257    __pthread_fchdir(-1);
1258  }
1259
1260  return error;
1261}
1262
1263static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) {
1264  bool result = false;
1265
1266#if !NO_XPC_SERVICES
1267  bool launchingAsRoot = launch_info.GetUserID() == 0;
1268  bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
1269
1270  if (launchingAsRoot && !currentUserIsRoot) {
1271    // If current user is already root, we don't need XPC's help.
1272    result = true;
1273  }
1274#endif
1275
1276  return result;
1277}
1278
1279Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
1280  Status error;
1281
1282  FileSystem &fs = FileSystem::Instance();
1283  FileSpec exe_spec(launch_info.GetExecutableFile());
1284
1285  if (!fs.Exists(exe_spec))
1286    FileSystem::Instance().Resolve(exe_spec);
1287
1288  if (!fs.Exists(exe_spec))
1289    FileSystem::Instance().ResolveExecutableLocation(exe_spec);
1290
1291  if (!fs.Exists(exe_spec)) {
1292    error.SetErrorStringWithFormatv("executable doesn't exist: '{0}'",
1293                                    exe_spec);
1294    return error;
1295  }
1296
1297  if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) {
1298#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
1299    return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(),
1300                                              launch_info);
1301#else
1302    error.SetErrorString("launching a process in a new terminal is not "
1303                         "supported on iOS devices");
1304    return error;
1305#endif
1306  }
1307
1308  lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
1309
1310  // From now on we'll deal with the external (devirtualized) path.
1311  auto exe_path = fs.GetExternalPath(exe_spec);
1312  if (!exe_path)
1313    return Status(exe_path.getError());
1314
1315  if (ShouldLaunchUsingXPC(launch_info))
1316    error = LaunchProcessXPC(exe_path->c_str(), launch_info, pid);
1317  else
1318    error = LaunchProcessPosixSpawn(exe_path->c_str(), launch_info, pid);
1319
1320  if (pid != LLDB_INVALID_PROCESS_ID) {
1321    // If all went well, then set the process ID into the launch info
1322    launch_info.SetProcessID(pid);
1323
1324    // Make sure we reap any processes we spawn or we will have zombies.
1325    bool monitoring = launch_info.MonitorProcess();
1326    UNUSED_IF_ASSERT_DISABLED(monitoring);
1327    assert(monitoring);
1328  } else {
1329    // Invalid process ID, something didn't go well
1330    if (error.Success())
1331      error.SetErrorString("process launch failed for unknown reasons");
1332  }
1333  return error;
1334}
1335
1336Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
1337  Status error;
1338  if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {
1339    FileSpec expand_tool_spec = HostInfo::GetSupportExeDir();
1340    if (!expand_tool_spec) {
1341      error.SetErrorString(
1342          "could not get support executable directory for lldb-argdumper tool");
1343      return error;
1344    }
1345    expand_tool_spec.AppendPathComponent("lldb-argdumper");
1346    if (!FileSystem::Instance().Exists(expand_tool_spec)) {
1347      error.SetErrorStringWithFormat(
1348          "could not find the lldb-argdumper tool: %s",
1349          expand_tool_spec.GetPath().c_str());
1350      return error;
1351    }
1352
1353    StreamString expand_tool_spec_stream;
1354    expand_tool_spec_stream.Printf("\"%s\"",
1355                                   expand_tool_spec.GetPath().c_str());
1356
1357    Args expand_command(expand_tool_spec_stream.GetData());
1358    expand_command.AppendArguments(launch_info.GetArguments());
1359
1360    int status;
1361    std::string output;
1362    FileSpec cwd(launch_info.GetWorkingDirectory());
1363    if (!FileSystem::Instance().Exists(cwd)) {
1364      char *wd = getcwd(nullptr, 0);
1365      if (wd == nullptr) {
1366        error.SetErrorStringWithFormat(
1367            "cwd does not exist; cannot launch with shell argument expansion");
1368        return error;
1369      } else {
1370        FileSpec working_dir(wd);
1371        free(wd);
1372        launch_info.SetWorkingDirectory(working_dir);
1373      }
1374    }
1375    bool run_in_default_shell = true;
1376    bool hide_stderr = true;
1377    Status e = RunShellCommand(expand_command, cwd, &status, nullptr, &output,
1378                               std::chrono::seconds(10), run_in_default_shell,
1379                               hide_stderr);
1380
1381    if (e.Fail())
1382      return e;
1383
1384    if (status != 0) {
1385      error.SetErrorStringWithFormat("lldb-argdumper exited with error %d",
1386                                     status);
1387      return error;
1388    }
1389
1390    auto data_sp = StructuredData::ParseJSON(output);
1391    if (!data_sp) {
1392      error.SetErrorString("invalid JSON");
1393      return error;
1394    }
1395
1396    auto dict_sp = data_sp->GetAsDictionary();
1397    if (!data_sp) {
1398      error.SetErrorString("invalid JSON");
1399      return error;
1400    }
1401
1402    auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
1403    if (!args_sp) {
1404      error.SetErrorString("invalid JSON");
1405      return error;
1406    }
1407
1408    auto args_array_sp = args_sp->GetAsArray();
1409    if (!args_array_sp) {
1410      error.SetErrorString("invalid JSON");
1411      return error;
1412    }
1413
1414    launch_info.GetArguments().Clear();
1415
1416    for (size_t i = 0; i < args_array_sp->GetSize(); i++) {
1417      auto item_sp = args_array_sp->GetItemAtIndex(i);
1418      if (!item_sp)
1419        continue;
1420      auto str_sp = item_sp->GetAsString();
1421      if (!str_sp)
1422        continue;
1423
1424      launch_info.GetArguments().AppendArgument(str_sp->GetValue());
1425    }
1426  }
1427
1428  return error;
1429}
1430
1431llvm::Expected<HostThread> Host::StartMonitoringChildProcess(
1432    const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid,
1433    bool monitor_signals) {
1434  unsigned long mask = DISPATCH_PROC_EXIT;
1435  if (monitor_signals)
1436    mask |= DISPATCH_PROC_SIGNAL;
1437
1438  Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_HOST |
1439                                                  LIBLLDB_LOG_PROCESS));
1440
1441  dispatch_source_t source = ::dispatch_source_create(
1442      DISPATCH_SOURCE_TYPE_PROC, pid, mask,
1443      ::dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1444
1445  LLDB_LOGF(log,
1446            "Host::StartMonitoringChildProcess "
1447            "(callback, pid=%i, monitor_signals=%i) "
1448            "source = %p\n",
1449            static_cast<int>(pid), monitor_signals,
1450            static_cast<void *>(source));
1451
1452  if (source) {
1453    Host::MonitorChildProcessCallback callback_copy = callback;
1454    ::dispatch_source_set_cancel_handler(source, ^{
1455      dispatch_release(source);
1456    });
1457    ::dispatch_source_set_event_handler(source, ^{
1458
1459      int status = 0;
1460      int wait_pid = 0;
1461      bool cancel = false;
1462      bool exited = false;
1463      wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, 0);
1464      if (wait_pid >= 0) {
1465        int signal = 0;
1466        int exit_status = 0;
1467        const char *status_cstr = NULL;
1468        if (WIFSTOPPED(status)) {
1469          signal = WSTOPSIG(status);
1470          status_cstr = "STOPPED";
1471        } else if (WIFEXITED(status)) {
1472          exit_status = WEXITSTATUS(status);
1473          status_cstr = "EXITED";
1474          exited = true;
1475        } else if (WIFSIGNALED(status)) {
1476          signal = WTERMSIG(status);
1477          status_cstr = "SIGNALED";
1478          exited = true;
1479          exit_status = -1;
1480        } else {
1481          status_cstr = "???";
1482        }
1483
1484        LLDB_LOGF(log,
1485                  "::waitpid (pid = %llu, &status, 0) => pid = %i, status "
1486                  "= 0x%8.8x (%s), signal = %i, exit_status = %i",
1487                  pid, wait_pid, status, status_cstr, signal, exit_status);
1488
1489        if (callback_copy)
1490          cancel = callback_copy(pid, exited, signal, exit_status);
1491
1492        if (exited || cancel) {
1493          ::dispatch_source_cancel(source);
1494        }
1495      }
1496    });
1497
1498    ::dispatch_resume(source);
1499  }
1500  return HostThread();
1501}
1502
1503//----------------------------------------------------------------------
1504// Log to both stderr and to ASL Logging when running on MacOSX.
1505//----------------------------------------------------------------------
1506void Host::SystemLog(SystemLogType type, const char *format, va_list args) {
1507  if (format && format[0]) {
1508    static aslmsg g_aslmsg = NULL;
1509    if (g_aslmsg == NULL) {
1510      g_aslmsg = ::asl_new(ASL_TYPE_MSG);
1511      char asl_key_sender[PATH_MAX];
1512      snprintf(asl_key_sender, sizeof(asl_key_sender),
1513               "com.apple.LLDB.framework");
1514      ::asl_set(g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
1515    }
1516
1517    // Copy the va_list so we can log this message twice
1518    va_list copy_args;
1519    va_copy(copy_args, args);
1520    // Log to stderr
1521    ::vfprintf(stderr, format, copy_args);
1522    va_end(copy_args);
1523
1524    int asl_level;
1525    switch (type) {
1526    case eSystemLogError:
1527      asl_level = ASL_LEVEL_ERR;
1528      break;
1529
1530    case eSystemLogWarning:
1531      asl_level = ASL_LEVEL_WARNING;
1532      break;
1533    }
1534
1535    // Log to ASL
1536    ::asl_vlog(NULL, g_aslmsg, asl_level, format, args);
1537  }
1538}
1539