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