brintos

brintos / llvm-project-archived public Read only

0
0
Text · 56.1 KiB · 96a282c Raw
1635 lines · plain
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/Host.h"10#include "PosixSpawnResponsible.h"11 12#include <AvailabilityMacros.h>13#include <TargetConditionals.h>14 15#if TARGET_OS_OSX16#define __XPC_PRIVATE_H__17#include <xpc/xpc.h>18 19#define LaunchUsingXPCRightName "com.apple.lldb.RootDebuggingXPCService"20 21// These XPC messaging keys are used for communication between Host.mm and the22// XPC service.23#define LauncherXPCServiceAuthKey "auth-key"24#define LauncherXPCServiceArgPrefxKey "arg"25#define LauncherXPCServiceEnvPrefxKey "env"26#define LauncherXPCServiceCPUTypeKey "cpuType"27#define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags"28#define LauncherXPCServiceStdInPathKeyKey "stdInPath"29#define LauncherXPCServiceStdOutPathKeyKey "stdOutPath"30#define LauncherXPCServiceStdErrPathKeyKey "stdErrPath"31#define LauncherXPCServiceChildPIDKey "childPID"32#define LauncherXPCServiceErrorTypeKey "errorType"33#define LauncherXPCServiceCodeTypeKey "errorCode"34 35#include <bsm/audit.h>36#include <bsm/audit_session.h>37#endif38 39#include "llvm/TargetParser/Host.h"40 41#include <asl.h>42#include <crt_externs.h>43#include <cstdio>44#include <cstdlib>45#include <dlfcn.h>46#include <grp.h>47#include <libproc.h>48#include <pwd.h>49#include <spawn.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/LLDBLog.h"63#include "lldb/Utility/DataBufferHeap.h"64#include "lldb/Utility/DataExtractor.h"65#include "lldb/Utility/Endian.h"66#include "lldb/Utility/FileSpec.h"67#include "lldb/Utility/Log.h"68#include "lldb/Utility/NameMatches.h"69#include "lldb/Utility/ProcessInfo.h"70#include "lldb/Utility/StreamString.h"71#include "lldb/Utility/StructuredData.h"72#include "lldb/lldb-defines.h"73 74#include "llvm/ADT/ScopeExit.h"75#include "llvm/Support/Errno.h"76#include "llvm/Support/FileSystem.h"77 78#include "../cfcpp/CFCBundle.h"79#include "../cfcpp/CFCMutableArray.h"80#include "../cfcpp/CFCMutableDictionary.h"81#include "../cfcpp/CFCReleaser.h"82#include "../cfcpp/CFCString.h"83 84#include <objc/objc-auto.h>85#include <os/log.h>86 87#include <CoreFoundation/CoreFoundation.h>88#include <Foundation/Foundation.h>89 90#ifndef _POSIX_SPAWN_DISABLE_ASLR91#define _POSIX_SPAWN_DISABLE_ASLR 0x010092#endif93 94extern "C" {95int __pthread_chdir(const char *path);96int __pthread_fchdir(int fildes);97}98 99using namespace lldb;100using namespace lldb_private;101 102static os_log_t g_os_log;103static std::once_flag g_os_log_once;104 105void Host::SystemLog(Severity severity, llvm::StringRef message) {106  if (__builtin_available(macos 10.12, iOS 10, tvOS 10, watchOS 3, *)) {107    std::call_once(g_os_log_once, []() {108      g_os_log = os_log_create("com.apple.dt.lldb", "lldb");109    });110    switch (severity) {111    case lldb::eSeverityInfo:112    case lldb::eSeverityWarning:113      os_log(g_os_log, "%{public}s", message.str().c_str());114      break;115    case lldb::eSeverityError:116      os_log_error(g_os_log, "%{public}s", message.str().c_str());117      break;118    }119  } else {120    llvm::errs() << message;121  }122}123 124bool Host::GetBundleDirectory(const FileSpec &file,125                              FileSpec &bundle_directory) {126#if defined(__APPLE__)127  if (FileSystem::Instance().IsDirectory(file)) {128    char path[PATH_MAX];129    if (file.GetPath(path, sizeof(path))) {130      CFCBundle bundle(path);131      if (bundle.GetPath(path, sizeof(path))) {132        bundle_directory.SetFile(path, FileSpec::Style::native);133        return true;134      }135    }136  }137#endif138  bundle_directory.Clear();139  return false;140}141 142bool Host::ResolveExecutableInBundle(FileSpec &file) {143#if defined(__APPLE__)144  if (FileSystem::Instance().IsDirectory(file)) {145    char path[PATH_MAX];146    if (file.GetPath(path, sizeof(path))) {147      CFCBundle bundle(path);148      CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL());149      if (url.get()) {150        if (::CFURLGetFileSystemRepresentation(url.get(), YES, (UInt8 *)path,151                                               sizeof(path))) {152          file.SetFile(path, FileSpec::Style::native);153          return true;154        }155      }156    }157  }158#endif159  return false;160}161 162#if TARGET_OS_OSX163 164static void *AcceptPIDFromInferior(const char *connect_url) {165  ConnectionFileDescriptor file_conn;166  Status error;167  if (file_conn.Connect(connect_url, &error) == eConnectionStatusSuccess) {168    char pid_str[256];169    ::memset(pid_str, 0, sizeof(pid_str));170    ConnectionStatus status;171    const size_t pid_str_len = file_conn.Read(172        pid_str, sizeof(pid_str), std::chrono::seconds(0), status, NULL);173    if (pid_str_len > 0) {174      int pid = atoi(pid_str);175      return (void *)(intptr_t)pid;176    }177  }178  return NULL;179}180 181const char *applscript_in_new_tty = "tell application \"Terminal\"\n"182                                    "   activate\n"183                                    "	do script \"/bin/bash -c '%s';exit\"\n"184                                    "end tell\n";185 186const char *applscript_in_existing_tty = "\187set the_shell_script to \"/bin/bash -c '%s';exit\"\n\188tell application \"Terminal\"\n\189	repeat with the_window in (get windows)\n\190		repeat with the_tab in tabs of the_window\n\191			set the_tty to tty in the_tab\n\192			if the_tty contains \"%s\" then\n\193				if the_tab is not busy then\n\194					set selected of the_tab to true\n\195					set frontmost of the_window to true\n\196					do script the_shell_script in the_tab\n\197					return\n\198				end if\n\199			end if\n\200		end repeat\n\201	end repeat\n\202	do script the_shell_script\n\203end tell\n";204 205static Status206LaunchInNewTerminalWithAppleScript(const char *exe_path,207                                   ProcessLaunchInfo &launch_info) {208  Status error;209  char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";210  if (::mktemp(unix_socket_name) == NULL) {211    error = Status::FromErrorString(212        "failed to make temporary path for a unix socket");213    return error;214  }215 216  StreamString command;217  FileSpec darwin_debug_file_spec = HostInfo::GetSupportExeDir();218  if (!darwin_debug_file_spec) {219    error =220        Status::FromErrorString("can't locate the 'darwin-debug' executable");221    return error;222  }223 224  darwin_debug_file_spec.SetFilename("darwin-debug");225 226  if (!FileSystem::Instance().Exists(darwin_debug_file_spec)) {227    error = Status::FromErrorStringWithFormat(228        "the 'darwin-debug' executable doesn't exists at '%s'",229        darwin_debug_file_spec.GetPath().c_str());230    return error;231  }232 233  char launcher_path[PATH_MAX];234  darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));235 236  const ArchSpec &arch_spec = launch_info.GetArchitecture();237  // Only set the architecture if it is valid and if it isn't Haswell (x86_64h).238  if (arch_spec.IsValid() &&239      arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h)240    command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());241 242  command.Printf(R"(\"%s\" --unix-socket=%s)", launcher_path, unix_socket_name);243 244  if (arch_spec.IsValid())245    command.Printf(" --arch=%s", arch_spec.GetArchitectureName());246 247  FileSpec working_dir{launch_info.GetWorkingDirectory()};248  if (working_dir)249    command.Printf(R"( --working-dir \"%s\")", working_dir.GetPath().c_str());250  else {251    char cwd[PATH_MAX];252    if (getcwd(cwd, PATH_MAX))253      command.Printf(R"( --working-dir \"%s\")", cwd);254  }255 256  if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))257    command.PutCString(" --disable-aslr");258 259  // We are launching on this host in a terminal. So compare the environment on260  // the host to what is supplied in the launch_info. Any items that aren't in261  // the host environment need to be sent to darwin-debug. If we send all262  // environment entries, we might blow the max command line length, so we only263  // send user modified entries.264  Environment host_env = Host::GetEnvironment();265 266  for (const auto &KV : launch_info.GetEnvironment()) {267    auto host_entry = host_env.find(KV.first());268    if (host_entry == host_env.end() || host_entry->second != KV.second)269      command.Format(R"( --env=\"{0}\")", Environment::compose(KV));270  }271 272  command.PutCString(" -- ");273 274  const char **argv = launch_info.GetArguments().GetConstArgumentVector();275  if (argv) {276    for (size_t i = 0; argv[i] != NULL; ++i) {277      if (i == 0)278        command.Printf(R"( \"%s\")", exe_path);279      else280        command.Printf(R"( \"%s\")", argv[i]);281    }282  } else {283    command.Printf(R"( \"%s\")", exe_path);284  }285  command.PutCString(" ; echo Process exited with status $?");286  if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))287    command.PutCString(" ; exit");288 289  StreamString applescript_source;290 291  applescript_source.Printf(applscript_in_new_tty,292                            command.GetString().str().c_str());293 294  NSAppleScript *applescript = [[NSAppleScript alloc]295      initWithSource:[NSString stringWithCString:applescript_source.GetString()296                                                     .str()297                                                     .c_str()298                                        encoding:NSUTF8StringEncoding]];299 300  lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;301 302  Status lldb_error;303  // Sleep and wait a bit for debugserver to start to listen...304  ConnectionFileDescriptor file_conn;305  char connect_url[128];306  ::snprintf(connect_url, sizeof(connect_url), "unix-accept://%s",307             unix_socket_name);308 309  // Spawn a new thread to accept incoming connection on the connect_url310  // so we can grab the pid from the inferior. We have to do this because we311  // are sending an AppleScript that will launch a process in Terminal.app,312  // in a shell and the shell will fork/exec a couple of times before we get313  // to the process that we wanted to launch. So when our process actually314  // gets launched, we will handshake with it and get the process ID for it.315  llvm::Expected<HostThread> accept_thread = ThreadLauncher::LaunchThread(316      unix_socket_name, [&] { return AcceptPIDFromInferior(connect_url); });317 318  if (!accept_thread)319    return Status::FromError(accept_thread.takeError());320 321  [applescript executeAndReturnError:nil];322 323  thread_result_t accept_thread_result = NULL;324  lldb_error = accept_thread->Join(&accept_thread_result);325  if (lldb_error.Success() && accept_thread_result) {326    pid = (intptr_t)accept_thread_result;327  }328 329  llvm::sys::fs::remove(unix_socket_name);330  [applescript release];331  if (pid != LLDB_INVALID_PROCESS_ID)332    launch_info.SetProcessID(pid);333  return error;334}335 336#endif // TARGET_OS_OSX337 338llvm::Error Host::OpenFileInExternalEditor(llvm::StringRef editor,339                                           const FileSpec &file_spec,340                                           uint32_t line_no) {341#if !TARGET_OS_OSX342  return llvm::errorCodeToError(343      std::error_code(ENOTSUP, std::system_category()));344#else // !TARGET_OS_OSX345  Log *log = GetLog(LLDBLog::Host);346 347  const std::string file_path = file_spec.GetPath();348 349  LLDB_LOG(log, "Sending {0}:{1} to external editor",350           file_path.empty() ? "<invalid>" : file_path, line_no);351 352  if (file_path.empty())353    return llvm::createStringError(llvm::inconvertibleErrorCode(),354                                   "no file specified");355 356  CFCString file_cfstr(file_path.c_str(), kCFStringEncodingUTF8);357  CFCReleaser<CFURLRef> file_URL = ::CFURLCreateWithFileSystemPath(358      /*allocator=*/NULL,359      /*filePath*/ file_cfstr.get(),360      /*pathStyle=*/kCFURLPOSIXPathStyle,361      /*isDirectory=*/false);362 363  if (!file_URL.get())364    return llvm::createStringError(365        llvm::inconvertibleErrorCode(),366        llvm::formatv("could not create CFURL from path \"{0}\"", file_path));367 368  // Create a new Apple Event descriptor.369  typedef struct {370    int16_t reserved0; // must be zero371    int16_t fLineNumber;372    int32_t fSelStart;373    int32_t fSelEnd;374    uint32_t reserved1; // must be zero375    uint32_t reserved2; // must be zero376  } BabelAESelInfo;377 378  // We attach this to an 'odoc' event to specify a particular selection.379  BabelAESelInfo file_and_line_info = {380      0,                      // reserved0381      (int16_t)(line_no - 1), // fLineNumber (zero based line number)382      1,                      // fSelStart383      1024,                   // fSelEnd384      0,                      // reserved1385      0                       // reserved2386  };387 388  AEKeyDesc file_and_line_desc;389  file_and_line_desc.descKey = keyAEPosition;390  long error = ::AECreateDesc(/*typeCode=*/typeUTF8Text,391                              /*dataPtr=*/&file_and_line_info,392                              /*dataSize=*/sizeof(file_and_line_info),393                              /*result=*/&(file_and_line_desc.descContent));394 395  if (error != noErr)396    return llvm::createStringError(397        llvm::inconvertibleErrorCode(),398        llvm::formatv("creating Apple Event descriptor failed: error {0}",399                      error));400 401  // Deallocate the descriptor on exit.402  auto on_exit = llvm::make_scope_exit(403      [&]() { AEDisposeDesc(&(file_and_line_desc.descContent)); });404 405  if (editor.empty()) {406    if (const char *lldb_external_editor = ::getenv("LLDB_EXTERNAL_EDITOR"))407      editor = lldb_external_editor;408  }409 410  std::optional<FSRef> app_fsref;411  if (!editor.empty()) {412    LLDB_LOG(log, "Looking for external editor: {0}", editor);413 414    app_fsref.emplace();415    CFCString editor_name(editor.data(), kCFStringEncodingUTF8);416    long app_error = ::LSFindApplicationForInfo(417        /*inCreator=*/kLSUnknownCreator, /*inBundleID=*/NULL,418        /*inName=*/editor_name.get(), /*outAppRef=*/&(*app_fsref),419        /*outAppURL=*/NULL);420    if (app_error != noErr)421      return llvm::createStringError(422          llvm::inconvertibleErrorCode(),423          llvm::formatv("could not find external editor \"{0}\": "424                        "LSFindApplicationForInfo returned error {1}",425                        editor, app_error));426  }427 428  // Build app launch parameters.429  LSApplicationParameters app_params;430  ::memset(&app_params, 0, sizeof(app_params));431  app_params.flags =432      kLSLaunchDefaults | kLSLaunchDontAddToRecents | kLSLaunchDontSwitch;433  if (app_fsref)434    app_params.application = &(*app_fsref);435 436  ProcessSerialNumber psn;437  std::array<CFURLRef, 1> file_array = {file_URL.get()};438  CFCReleaser<CFArrayRef> cf_array(439      CFArrayCreate(/*allocator=*/NULL, /*values=*/(const void **)&file_array,440                    /*numValues*/ 1, /*callBacks=*/NULL));441  error = ::LSOpenURLsWithRole(442      /*inURLs=*/cf_array.get(), /*inRole=*/kLSRolesEditor,443      /*inAEParam=*/&file_and_line_desc,444      /*inAppParams=*/&app_params, /*outPSNs=*/&psn, /*inMaxPSNCount=*/1);445 446  if (error != noErr)447    return llvm::createStringError(448        llvm::inconvertibleErrorCode(),449        llvm::formatv("LSOpenURLsWithRole failed: error {0}", error));450 451  return llvm::Error::success();452#endif // TARGET_OS_OSX453}454 455llvm::Error Host::OpenURL(llvm::StringRef url) {456#if !TARGET_OS_OSX457  return llvm::errorCodeToError(458      std::error_code(ENOTSUP, std::system_category()));459#else  // !TARGET_OS_OSX460  if (url.empty())461    return llvm::createStringError("Cannot open empty URL.");462 463  LLDB_LOG(GetLog(LLDBLog::Host), "Opening URL: {0}", url);464 465  CFCString url_cfstr(url.data(), kCFStringEncodingUTF8);466  CFCReleaser<CFURLRef> cfurl = ::CFURLCreateWithString(467      /*allocator=*/NULL,468      /*URLString*/ url_cfstr.get(),469      /*baseURL=*/NULL);470 471  if (!cfurl.get())472    return llvm::createStringError(473        llvm::formatv("could not create CFURL from URL \"{0}\"", url));474 475  OSStatus error = ::LSOpenCFURLRef(476      /*inURL=*/cfurl.get(),477      /*outLaunchedURL=*/NULL);478 479  if (error != noErr)480    return llvm::createStringError(481        llvm::formatv("LSOpenCFURLRef failed: error {0:x}", error));482 483  return llvm::Error::success();484#endif // TARGET_OS_OSX485}486 487bool Host::IsInteractiveGraphicSession() {488#if !TARGET_OS_OSX489  return false;490#else491  auditinfo_addr_t info;492  getaudit_addr(&info, sizeof(info));493  return info.ai_flags & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS;494#endif495}496 497Environment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); }498 499static bool GetMacOSXProcessCPUType(ProcessInstanceInfo &process_info) {500  if (process_info.ProcessIDIsValid()) {501    // Make a new mib to stay thread safe502    int mib[CTL_MAXNAME] = {503        0,504    };505    size_t mib_len = CTL_MAXNAME;506    if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len))507      return false;508 509    mib[mib_len] = process_info.GetProcessID();510    mib_len++;511 512    cpu_type_t cpu, sub = 0;513    size_t len = sizeof(cpu);514    if (::sysctl(mib, mib_len, &cpu, &len, 0, 0) == 0) {515      switch (cpu) {516      case CPU_TYPE_I386:517        sub = CPU_SUBTYPE_I386_ALL;518        break;519      case CPU_TYPE_X86_64:520        sub = CPU_SUBTYPE_X86_64_ALL;521        break;522 523#if defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64_ALL)524      case CPU_TYPE_ARM64:525        sub = CPU_SUBTYPE_ARM64_ALL;526        break;527#endif528 529#if defined(CPU_TYPE_ARM64_32) && defined(CPU_SUBTYPE_ARM64_32_ALL)530      case CPU_TYPE_ARM64_32:531        sub = CPU_SUBTYPE_ARM64_32_ALL;532        break;533#endif534 535      case CPU_TYPE_ARM: {536        // Note that we fetched the cpu type from the PROCESS but we can't get a537        // cpusubtype of the538        // process -- we can only get the host's cpu subtype.539        uint32_t cpusubtype = 0;540        len = sizeof(cpusubtype);541        if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)542          sub = cpusubtype;543 544        bool host_cpu_is_64bit;545        uint32_t is64bit_capable;546        size_t is64bit_capable_len = sizeof(is64bit_capable);547        host_cpu_is_64bit =548            sysctlbyname("hw.cpu64bit_capable", &is64bit_capable,549                         &is64bit_capable_len, NULL, 0) == 0;550 551        // if the host is an armv8 device, its cpusubtype will be in552        // CPU_SUBTYPE_ARM64 numbering553        // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value554        // instead.555 556        if (host_cpu_is_64bit) {557          sub = CPU_SUBTYPE_ARM_V7;558        }559      } break;560 561      default:562        break;563      }564      process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, sub);565      return true;566    }567  }568  process_info.GetArchitecture().Clear();569  return false;570}571 572static bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,573                                 ProcessInstanceInfo &process_info) {574  if (process_info.ProcessIDIsValid()) {575    int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2,576                            (int)process_info.GetProcessID()};577 578    size_t arg_data_size = 0;579    if (::sysctl(proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) ||580        arg_data_size == 0)581      arg_data_size = 8192;582 583    // Add a few bytes to the calculated length, I know we need to add at least584    // one byte585    // to this number otherwise we get junk back, so add 128 just in case...586    DataBufferHeap arg_data(arg_data_size + 128, 0);587    arg_data_size = arg_data.GetByteSize();588    if (::sysctl(proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size, NULL,589                 0) == 0) {590      DataExtractor data(arg_data.GetBytes(), arg_data_size,591                         endian::InlHostByteOrder(), sizeof(void *));592      lldb::offset_t offset = 0;593      uint32_t argc = data.GetU32(&offset);594      llvm::Triple &triple = process_info.GetArchitecture().GetTriple();595      const llvm::Triple::ArchType triple_arch = triple.getArch();596      const bool check_for_ios_simulator =597          (triple_arch == llvm::Triple::x86 ||598           triple_arch == llvm::Triple::x86_64 ||599           triple_arch == llvm::Triple::aarch64);600 601      const char *cstr = data.GetCStr(&offset);602      if (cstr) {603        process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);604 605        if (match_info_ptr == NULL ||606            NameMatches(607                process_info.GetExecutableFile().GetFilename().GetCString(),608                match_info_ptr->GetNameMatchType(),609                match_info_ptr->GetProcessInfo().GetName())) {610          // Skip NULLs611          while (true) {612            const uint8_t *p = data.PeekData(offset, 1);613            if ((p == NULL) || (*p != '\0'))614              break;615            ++offset;616          }617          // Now extract all arguments618          Args &proc_args = process_info.GetArguments();619          for (int i = 0; i < static_cast<int>(argc); ++i) {620            cstr = data.GetCStr(&offset);621            if (cstr)622              proc_args.AppendArgument(llvm::StringRef(cstr));623          }624 625          Environment &proc_env = process_info.GetEnvironment();626          bool is_simulator = false;627          llvm::StringRef env_var;628          while (!(env_var = data.GetCStr(&offset)).empty()) {629            if (check_for_ios_simulator &&630                env_var.starts_with("SIMULATOR_UDID="))631              is_simulator = true;632            proc_env.insert(env_var);633          }634          llvm::Triple &triple = process_info.GetArchitecture().GetTriple();635          if (is_simulator) {636            triple.setOS(llvm::Triple::IOS);637            triple.setEnvironment(llvm::Triple::Simulator);638          } else {639            triple.setOS(llvm::Triple::MacOSX);640          }641          return true;642        }643      }644    }645  }646  return false;647}648 649static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) {650  if (process_info.ProcessIDIsValid()) {651    int mib[4];652    mib[0] = CTL_KERN;653    mib[1] = KERN_PROC;654    mib[2] = KERN_PROC_PID;655    mib[3] = process_info.GetProcessID();656    struct kinfo_proc proc_kinfo;657    size_t proc_kinfo_size = sizeof(struct kinfo_proc);658 659    if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {660      if (proc_kinfo_size > 0) {661        process_info.SetParentProcessID(proc_kinfo.kp_eproc.e_ppid);662        process_info.SetUserID(proc_kinfo.kp_eproc.e_pcred.p_ruid);663        process_info.SetGroupID(proc_kinfo.kp_eproc.e_pcred.p_rgid);664        process_info.SetEffectiveUserID(proc_kinfo.kp_eproc.e_ucred.cr_uid);665        if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)666          process_info.SetEffectiveGroupID(667              proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);668        else669          process_info.SetEffectiveGroupID(UINT32_MAX);670        return true;671      }672    }673  }674  process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);675  process_info.SetUserID(UINT32_MAX);676  process_info.SetGroupID(UINT32_MAX);677  process_info.SetEffectiveUserID(UINT32_MAX);678  process_info.SetEffectiveGroupID(UINT32_MAX);679  return false;680}681 682uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,683                                 ProcessInstanceInfoList &process_infos) {684  std::vector<struct kinfo_proc> kinfos;685 686  int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};687 688  size_t pid_data_size = 0;689  if (::sysctl(mib, 3, nullptr, &pid_data_size, nullptr, 0) != 0)690    return 0;691 692  // Add a few extra in case a few more show up693  const size_t estimated_pid_count =694      (pid_data_size / sizeof(struct kinfo_proc)) + 10;695 696  kinfos.resize(estimated_pid_count);697  pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);698 699  if (::sysctl(mib, 3, &kinfos[0], &pid_data_size, nullptr, 0) != 0)700    return 0;701 702  const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));703 704  bool all_users = match_info.GetMatchAllUsers();705  const lldb::pid_t our_pid = getpid();706  const uid_t our_uid = getuid();707  for (size_t i = 0; i < actual_pid_count; i++) {708    const struct kinfo_proc &kinfo = kinfos[i];709 710    bool kinfo_user_matches = false;711    if (all_users)712      kinfo_user_matches = true;713    else714      kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;715 716    // Special case, if lldb is being run as root we can attach to anything.717    if (our_uid == 0)718      kinfo_user_matches = true;719 720    if (!kinfo_user_matches || // Make sure the user is acceptable721        static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) ==722            our_pid ||                   // Skip this process723        kinfo.kp_proc.p_pid == 0 ||      // Skip kernel (kernel pid is zero)724        kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains...725        kinfo.kp_proc.p_flag & P_TRACED ||   // Being debugged?726        kinfo.kp_proc.p_flag & P_WEXIT)727      continue;728 729    ProcessInstanceInfo process_info;730    process_info.SetProcessID(kinfo.kp_proc.p_pid);731    process_info.SetParentProcessID(kinfo.kp_eproc.e_ppid);732    process_info.SetUserID(kinfo.kp_eproc.e_pcred.p_ruid);733    process_info.SetGroupID(kinfo.kp_eproc.e_pcred.p_rgid);734    process_info.SetEffectiveUserID(kinfo.kp_eproc.e_ucred.cr_uid);735    if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)736      process_info.SetEffectiveGroupID(kinfo.kp_eproc.e_ucred.cr_groups[0]);737    else738      process_info.SetEffectiveGroupID(UINT32_MAX);739 740    // Make sure our info matches before we go fetch the name and cpu type741    if (!match_info.UserIDsMatch(process_info) ||742        !match_info.ProcessIDsMatch(process_info))743      continue;744 745    // Get CPU type first so we can know to look for iOS simulator if we have746    // a compatible type.747    if (GetMacOSXProcessCPUType(process_info)) {748      if (GetMacOSXProcessArgs(&match_info, process_info)) {749        if (match_info.Matches(process_info))750          process_infos.push_back(process_info);751      }752    }753  }754  return process_infos.size();755}756 757bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {758  process_info.SetProcessID(pid);759  bool success = false;760 761  // Get CPU type first so we can know to look for iOS simulator is we have x86762  // or x86_64763  if (GetMacOSXProcessCPUType(process_info))764    success = true;765 766  if (GetMacOSXProcessArgs(NULL, process_info))767    success = true;768 769  if (GetMacOSXProcessUserAndGroup(process_info))770    success = true;771 772  if (success)773    return true;774 775  process_info.Clear();776  return false;777}778 779#if TARGET_OS_OSX780static void PackageXPCArguments(xpc_object_t message, const char *prefix,781                                const Args &args) {782  size_t count = args.GetArgumentCount();783  char buf[50]; // long enough for 'argXXX'784  memset(buf, 0, sizeof(buf));785  snprintf(buf, sizeof(buf), "%sCount", prefix);786  xpc_dictionary_set_int64(message, buf, count);787  for (size_t i = 0; i < count; i++) {788    memset(buf, 0, sizeof(buf));789    snprintf(buf, sizeof(buf), "%s%zi", prefix, i);790    xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));791  }792}793 794static void PackageXPCEnvironment(xpc_object_t message, llvm::StringRef prefix,795                                  const Environment &env) {796  xpc_dictionary_set_int64(message, (prefix + "Count").str().c_str(),797                           env.size());798  size_t i = 0;799  for (const auto &KV : env) {800    xpc_dictionary_set_string(message, (prefix + llvm::Twine(i)).str().c_str(),801                              Environment::compose(KV).c_str());802  }803}804 805/*806 A valid authorizationRef means that807    - there is the LaunchUsingXPCRightName rights in the /etc/authorization808    - we have successfully copied the rights to be send over the XPC wire809 Once obtained, it will be valid for as long as the process lives.810 */811static AuthorizationRef authorizationRef = NULL;812static Status getXPCAuthorization(ProcessLaunchInfo &launch_info) {813  Status error;814  Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));815 816  if ((launch_info.GetUserID() == 0) && !authorizationRef) {817    OSStatus createStatus =818        AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,819                            kAuthorizationFlagDefaults, &authorizationRef);820    if (createStatus != errAuthorizationSuccess) {821      error = Status(1, eErrorTypeGeneric);822      error = Status::FromErrorString("Can't create authorizationRef.");823      LLDB_LOG(log, "error: {0}", error);824      return error;825    }826 827    OSStatus rightsStatus =828        AuthorizationRightGet(LaunchUsingXPCRightName, NULL);829    if (rightsStatus != errAuthorizationSuccess) {830      // No rights in the security database, Create it with the right prompt.831      CFStringRef prompt =832          CFSTR("Xcode is trying to take control of a root process.");833      CFStringRef keys[] = {CFSTR("en")};834      CFTypeRef values[] = {prompt};835      CFDictionaryRef promptDict = CFDictionaryCreate(836          kCFAllocatorDefault, (const void **)keys, (const void **)values, 1,837          &kCFCopyStringDictionaryKeyCallBacks,838          &kCFTypeDictionaryValueCallBacks);839 840      CFStringRef keys1[] = {CFSTR("class"), CFSTR("group"), CFSTR("comment"),841                             CFSTR("default-prompt"), CFSTR("shared")};842      CFTypeRef values1[] = {CFSTR("user"), CFSTR("admin"),843                             CFSTR(LaunchUsingXPCRightName), promptDict,844                             kCFBooleanFalse};845      CFDictionaryRef dict = CFDictionaryCreate(846          kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5,847          &kCFCopyStringDictionaryKeyCallBacks,848          &kCFTypeDictionaryValueCallBacks);849      rightsStatus = AuthorizationRightSet(850          authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);851      CFRelease(promptDict);852      CFRelease(dict);853    }854 855    OSStatus copyRightStatus = errAuthorizationDenied;856    if (rightsStatus == errAuthorizationSuccess) {857      AuthorizationItem item1 = {LaunchUsingXPCRightName, 0, NULL, 0};858      AuthorizationItem items[] = {item1};859      AuthorizationRights requestedRights = {1, items};860      AuthorizationFlags authorizationFlags =861          kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;862      copyRightStatus = AuthorizationCopyRights(863          authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment,864          authorizationFlags, NULL);865    }866 867    if (copyRightStatus != errAuthorizationSuccess) {868      // Eventually when the commandline supports running as root and the user869      // is not870      // logged in to the current audit session, we will need the trick in gdb871      // where872      // we ask the user to type in the root passwd in the terminal.873      error = Status(2, eErrorTypeGeneric);874      error = Status::FromErrorStringWithFormat(875          "Launching as root needs root authorization.");876      LLDB_LOG(log, "error: {0}", error);877 878      if (authorizationRef) {879        AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);880        authorizationRef = NULL;881      }882    }883  }884 885  return error;886}887#endif888 889static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {890  short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;891 892  if (launch_info.GetFlags().Test(eLaunchFlagExec))893    flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag894 895  if (launch_info.GetFlags().Test(eLaunchFlagDebug))896    flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag897 898  if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))899    flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag900 901  if (launch_info.GetLaunchInSeparateProcessGroup())902    flags |= POSIX_SPAWN_SETPGROUP;903 904#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT905#if defined(__x86_64__) || defined(__i386__)906  static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;907  if (g_use_close_on_exec_flag == eLazyBoolCalculate) {908    g_use_close_on_exec_flag = eLazyBoolNo;909 910    llvm::VersionTuple version = HostInfo::GetOSVersion();911    if (version > llvm::VersionTuple(10, 7)) {912      // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or913      // earlier914      g_use_close_on_exec_flag = eLazyBoolYes;915    }916  }917#else918  static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;919#endif // defined(__x86_64__) || defined(__i386__)920  // Close all files exception those with file actions if this is supported.921  if (g_use_close_on_exec_flag == eLazyBoolYes)922    flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;923#endif // ifdef POSIX_SPAWN_CLOEXEC_DEFAULT924  return flags;925}926 927static void finalize_xpc(void *xpc_object) {928  xpc_release((xpc_object_t)xpc_object);929}930 931static Status LaunchProcessXPC(const char *exe_path,932                               ProcessLaunchInfo &launch_info,933                               lldb::pid_t &pid) {934#if TARGET_OS_OSX935  Status error = getXPCAuthorization(launch_info);936  if (error.Fail())937    return error;938 939  Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));940 941  uid_t requested_uid = launch_info.GetUserID();942  const char *xpc_service = nil;943  bool send_auth = false;944  AuthorizationExternalForm extForm;945  if (requested_uid == 0) {946    if (AuthorizationMakeExternalForm(authorizationRef, &extForm) ==947        errAuthorizationSuccess) {948      send_auth = true;949    } else {950      error = Status(3, eErrorTypeGeneric);951      error = Status::FromErrorStringWithFormat(952          "Launching root via XPC needs to "953          "externalize authorization reference.");954      LLDB_LOG(log, "error: {0}", error);955      return error;956    }957    xpc_service = LaunchUsingXPCRightName;958  } else {959    error = Status(4, eErrorTypeGeneric);960    error = Status::FromErrorStringWithFormat(961        "Launching via XPC is only currently available for root.");962    LLDB_LOG(log, "error: {0}", error);963    return error;964  }965 966  xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);967 968  xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {969    xpc_type_t type = xpc_get_type(event);970 971    if (type == XPC_TYPE_ERROR) {972      if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {973        // The service has either canceled itself, crashed, or been terminated.974        // The XPC connection is still valid and sending a message to it will975        // re-launch the service.976        // If the service is state-full, this is the time to initialize the new977        // service.978        return;979      } else if (event == XPC_ERROR_CONNECTION_INVALID) {980        // The service is invalid. Either the service name supplied to981        // xpc_connection_create() is incorrect982        // or we (this process) have canceled the service; we can do any cleanup983        // of application state at this point.984        // printf("Service disconnected");985        return;986      } else {987        // printf("Unexpected error from service: %s",988        // xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));989      }990 991    } else {992      // printf("Received unexpected event in handler");993    }994  });995 996  xpc_connection_set_finalizer_f(conn, finalize_xpc);997  xpc_connection_resume(conn);998  xpc_object_t message = xpc_dictionary_create(nil, nil, 0);999 1000  if (send_auth) {1001    xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes,1002                            sizeof(AuthorizationExternalForm));1003  }1004 1005  PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey,1006                      launch_info.GetArguments());1007  PackageXPCEnvironment(message, LauncherXPCServiceEnvPrefxKey,1008                        launch_info.GetEnvironment());1009 1010  // Posix spawn stuff.1011  xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey,1012                           launch_info.GetArchitecture().GetMachOCPUType());1013  xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey,1014                           GetPosixspawnFlags(launch_info));1015  const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);1016  if (file_action && !file_action->GetPath().empty()) {1017    xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey,1018                              file_action->GetPath().str().c_str());1019  }1020  file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);1021  if (file_action && !file_action->GetPath().empty()) {1022    xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey,1023                              file_action->GetPath().str().c_str());1024  }1025  file_action = launch_info.GetFileActionForFD(STDERR_FILENO);1026  if (file_action && !file_action->GetPath().empty()) {1027    xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey,1028                              file_action->GetPath().str().c_str());1029  }1030 1031  xpc_object_t reply =1032      xpc_connection_send_message_with_reply_sync(conn, message);1033  xpc_type_t returnType = xpc_get_type(reply);1034  if (returnType == XPC_TYPE_DICTIONARY) {1035    pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);1036    if (pid == 0) {1037      int errorType =1038          xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);1039      int errorCode =1040          xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);1041 1042      error = Status(errorCode, eErrorTypeGeneric);1043      error = Status::FromErrorStringWithFormat(1044          "Problems with launching via XPC. Error type : %i, code : %i",1045          errorType, errorCode);1046      LLDB_LOG(log, "error: {0}", error);1047 1048      if (authorizationRef) {1049        AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);1050        authorizationRef = NULL;1051      }1052    }1053  } else if (returnType == XPC_TYPE_ERROR) {1054    error = Status(5, eErrorTypeGeneric);1055    error = Status::FromErrorStringWithFormat(1056        "Problems with launching via XPC. XPC error : %s",1057        xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));1058    LLDB_LOG(log, "error: {0}", error);1059  }1060 1061  return error;1062#else1063  Status error;1064  return error;1065#endif1066}1067 1068static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,1069                                    Log *log, Status &error) {1070  if (info == NULL)1071    return false;1072 1073  posix_spawn_file_actions_t *file_actions =1074      static_cast<posix_spawn_file_actions_t *>(_file_actions);1075 1076  switch (info->GetAction()) {1077  case FileAction::eFileActionNone:1078    error.Clear();1079    break;1080 1081  case FileAction::eFileActionClose:1082    if (info->GetFD() == -1)1083      error = Status::FromErrorString(1084          "invalid fd for posix_spawn_file_actions_addclose(...)");1085    else {1086      error = Status(1087          ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),1088          eErrorTypePOSIX);1089      if (error.Fail())1090        LLDB_LOG(log,1091                 "error: {0}, posix_spawn_file_actions_addclose "1092                 "(action={1}, fd={2})",1093                 error, file_actions, info->GetFD());1094    }1095    break;1096 1097  case FileAction::eFileActionDuplicate:1098    if (info->GetFD() == -1)1099      error = Status::FromErrorString(1100          "invalid fd for posix_spawn_file_actions_adddup2(...)");1101    else if (info->GetActionArgument() == -1)1102      error = Status::FromErrorString(1103          "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");1104    else if (info->GetFD() != info->GetActionArgument()) {1105      error =1106          Status(::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),1107                                                    info->GetActionArgument()),1108                 eErrorTypePOSIX);1109      if (error.Fail())1110        LLDB_LOG(log,1111                 "error: {0}, posix_spawn_file_actions_adddup2 "1112                 "(action={1}, fd={2}, dup_fd={3})",1113                 error, file_actions, info->GetFD(), info->GetActionArgument());1114    } else {1115      error =1116          Status(::posix_spawn_file_actions_addinherit_np(file_actions, info->GetFD()),1117                 eErrorTypePOSIX);1118      if (error.Fail())1119        LLDB_LOG(log,1120                 "error: {0}, posix_spawn_file_actions_addinherit_np "1121                 "(action={1}, fd={2})",1122                 error, file_actions, info->GetFD());1123    }1124    break;1125 1126  case FileAction::eFileActionOpen:1127    if (info->GetFD() == -1)1128      error = Status::FromErrorString(1129          "invalid fd in posix_spawn_file_actions_addopen(...)");1130    else {1131      int oflag = info->GetActionArgument();1132 1133      mode_t mode = 0;1134 1135      if (oflag & O_CREAT)1136        mode = 0640;1137 1138      error = Status(::posix_spawn_file_actions_addopen(1139                         file_actions, info->GetFD(),1140                         info->GetPath().str().c_str(), oflag, mode),1141                     eErrorTypePOSIX);1142      if (error.Fail())1143        LLDB_LOG(log,1144                 "error: {0}, posix_spawn_file_actions_addopen (action={1}, "1145                 "fd={2}, path='{3}', oflag={4}, mode={5})",1146                 error, file_actions, info->GetFD(), info->GetPath(), oflag,1147                 mode);1148    }1149    break;1150  }1151  return error.Success();1152}1153 1154static Status LaunchProcessPosixSpawn(const char *exe_path,1155                                      const ProcessLaunchInfo &launch_info,1156                                      lldb::pid_t &pid) {1157  Status error;1158  Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));1159 1160  posix_spawnattr_t attr;1161  error = Status(::posix_spawnattr_init(&attr), eErrorTypePOSIX);1162 1163  if (error.Fail()) {1164    LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error);1165    return error;1166  }1167 1168  // Make sure we clean up the posix spawn attributes before exiting this scope.1169  auto cleanup_attr =1170      llvm::make_scope_exit([&]() { posix_spawnattr_destroy(&attr); });1171 1172  sigset_t no_signals;1173  sigset_t all_signals;1174  sigemptyset(&no_signals);1175  sigfillset(&all_signals);1176  ::posix_spawnattr_setsigmask(&attr, &no_signals);1177  ::posix_spawnattr_setsigdefault(&attr, &all_signals);1178 1179  short flags = GetPosixspawnFlags(launch_info);1180 1181  error = Status(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);1182  if (error.Fail()) {1183    LLDB_LOG(log,1184             "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",1185             error, flags);1186    return error;1187  }1188 1189  bool is_graphical = true;1190 1191#if TARGET_OS_OSX1192  SecuritySessionId session_id;1193  SessionAttributeBits session_attributes;1194  OSStatus status =1195      SessionGetInfo(callerSecuritySession, &session_id, &session_attributes);1196  if (status == errSessionSuccess)1197    is_graphical = session_attributes & sessionHasGraphicAccess;1198#endif1199 1200  //  When lldb is ran through a graphical session, make the debuggee process1201  //  responsible for its own TCC permissions instead of inheriting them from1202  //  its parent.1203  if (is_graphical && launch_info.GetFlags().Test(eLaunchFlagDebug) &&1204      !launch_info.GetFlags().Test(eLaunchFlagInheritTCCFromParent)) {1205    error = Status(setup_posix_spawn_responsible_flag(&attr), eErrorTypePOSIX);1206    if (error.Fail()) {1207      LLDB_LOG(log, "error: {0}, setup_posix_spawn_responsible_flag(&attr)",1208               error);1209      return error;1210    }1211  }1212 1213  if (launch_info.GetFlags().Test(eLaunchFlagMemoryTagging)) {1214    // The following function configures the spawn attributes to launch the1215    // process with memory tagging explicitly enabled.  We look it up1216    // dynamically since it is only available on newer OS.  Does nothing on1217    // hardware which does not support MTE.1218    //1219    //   int posix_spawnattr_set_use_sec_transition_shims_np(1220    //       posix_spawnattr_t *attr, uint32_t flags);1221    //1222    using posix_spawnattr_set_use_sec_transition_shims_np_t =1223        int (*)(posix_spawnattr_t *attr, uint32_t flags);1224    auto posix_spawnattr_enable_memory_tagging_fn =1225        (posix_spawnattr_set_use_sec_transition_shims_np_t)dlsym(1226            RTLD_DEFAULT, "posix_spawnattr_set_use_sec_transition_shims_np");1227    if (posix_spawnattr_enable_memory_tagging_fn) {1228      error = Status(posix_spawnattr_enable_memory_tagging_fn(&attr, 0),1229                     eErrorTypePOSIX);1230      if (error.Fail()) {1231        LLDB_LOG(log,1232                 "error: {0}, "1233                 "posix_spawnattr_set_use_sec_transition_shims_np(&attr, 0)",1234                 error);1235        return error;1236      }1237    } else {1238      LLDB_LOG(log,1239               "error: posix_spawnattr_set_use_sec_transition_shims_np not "1240               "available",1241               error);1242    }1243  }1244 1245  // Don't set the binpref if a shell was provided. After all, that's only1246  // going to affect what version of the shell is launched, not what fork of1247  // the binary is launched.  We insert "arch --arch <ARCH> as part of the1248  // shell invocation to do that job on OSX.1249  if (launch_info.GetShell() == FileSpec()) {1250    const ArchSpec &arch_spec = launch_info.GetArchitecture();1251    cpu_type_t cpu_type = arch_spec.GetMachOCPUType();1252    cpu_type_t cpu_subtype = arch_spec.GetMachOCPUSubType();1253    const bool set_cpu_type =1254        cpu_type != 0 && cpu_type != static_cast<cpu_type_t>(UINT32_MAX) &&1255        cpu_type != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE);1256    const bool set_cpu_subtype =1257        cpu_subtype != 0 &&1258        cpu_subtype != static_cast<cpu_subtype_t>(UINT32_MAX) &&1259        cpu_subtype != CPU_SUBTYPE_X86_64_H;1260    if (set_cpu_type) {1261      size_t ocount = 0;1262      typedef int (*posix_spawnattr_setarchpref_np_t)(1263          posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *);1264      posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn =1265          (posix_spawnattr_setarchpref_np_t)dlsym(1266              RTLD_DEFAULT, "posix_spawnattr_setarchpref_np");1267      if (set_cpu_subtype && posix_spawnattr_setarchpref_np_fn) {1268        error = Status((*posix_spawnattr_setarchpref_np_fn)(1269                           &attr, 1, &cpu_type, &cpu_subtype, &ocount),1270                       eErrorTypePOSIX);1271        if (error.Fail())1272          LLDB_LOG(log,1273                   "error: {0}, ::posix_spawnattr_setarchpref_np ( &attr, 1, "1274                   "cpu_type = {1:x}, cpu_subtype = {1:x}, count => {2} )",1275                   error, cpu_type, cpu_subtype, ocount);1276 1277        if (error.Fail() || ocount != 1)1278          return error;1279      } else {1280        error = Status(1281            ::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount),1282            eErrorTypePOSIX);1283        if (error.Fail())1284          LLDB_LOG(log,1285                   "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "1286                   "cpu_type = {1:x}, count => {2} )",1287                   error, cpu_type, ocount);1288        if (error.Fail() || ocount != 1)1289          return error;1290      }1291    }1292  }1293 1294  const char *tmp_argv[2];1295  char *const *argv = const_cast<char *const *>(1296      launch_info.GetArguments().GetConstArgumentVector());1297  Environment::Envp envp = launch_info.GetEnvironment().getEnvp();1298  if (argv == NULL) {1299    // posix_spawn gets very unhappy if it doesn't have at least the program1300    // name in argv[0]. One of the side affects I have noticed is the1301    // environment1302    // variables don't make it into the child process if "argv == NULL"!!!1303    tmp_argv[0] = exe_path;1304    tmp_argv[1] = NULL;1305    argv = const_cast<char *const *>(tmp_argv);1306  }1307 1308  FileSpec working_dir{launch_info.GetWorkingDirectory()};1309  if (working_dir) {1310    // Set the working directory on this thread only1311    std::string working_dir_path = working_dir.GetPath();1312    if (__pthread_chdir(working_dir_path.c_str()) < 0) {1313      if (errno == ENOENT) {1314        error = Status::FromErrorStringWithFormat(1315            "No such file or directory: %s", working_dir_path.c_str());1316      } else if (errno == ENOTDIR) {1317        error = Status::FromErrorStringWithFormat(1318            "Path doesn't name a directory: %s", working_dir_path.c_str());1319      } else {1320        error =1321            Status::FromErrorStringWithFormat("An unknown error occurred when "1322                                              "changing directory for process "1323                                              "execution.");1324      }1325      return error;1326    }1327  }1328 1329  ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;1330  const size_t num_file_actions = launch_info.GetNumFileActions();1331  if (num_file_actions > 0) {1332    posix_spawn_file_actions_t file_actions;1333    error =1334        Status(::posix_spawn_file_actions_init(&file_actions), eErrorTypePOSIX);1335    if (error.Fail()) {1336      LLDB_LOG(log,1337               "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",1338               error);1339      return error;1340    }1341 1342    // Make sure we clean up the posix file actions before exiting this scope.1343    auto cleanup_fileact = llvm::make_scope_exit(1344        [&]() { posix_spawn_file_actions_destroy(&file_actions); });1345 1346    for (size_t i = 0; i < num_file_actions; ++i) {1347      const FileAction *launch_file_action =1348          launch_info.GetFileActionAtIndex(i);1349      if (launch_file_action) {1350        if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,1351                                     error))1352          return error;1353      }1354    }1355 1356    error = Status(1357        ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),1358        eErrorTypePOSIX);1359 1360    if (error.Fail()) {1361      LLDB_LOG(log,1362               "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "1363               "file_actions = {3}, "1364               "attr = {4}, argv = {5}, envp = {6} )",1365               error, result_pid, exe_path, &file_actions, &attr, argv,1366               envp.get());1367      if (log) {1368        for (int ii = 0; argv[ii]; ++ii)1369          LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);1370      }1371    }1372 1373  } else {1374    error =1375        Status(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),1376               eErrorTypePOSIX);1377 1378    if (error.Fail()) {1379      LLDB_LOG(log,1380               "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "1381               "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",1382               error, result_pid, exe_path, &attr, argv, envp.get());1383      if (log) {1384        for (int ii = 0; argv[ii]; ++ii)1385          LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);1386      }1387    }1388  }1389  pid = result_pid;1390 1391  if (working_dir) {1392    // No more thread specific current working directory1393    __pthread_fchdir(-1);1394  }1395 1396  return error;1397}1398 1399static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) {1400  bool result = false;1401 1402#if TARGET_OS_OSX1403  bool launchingAsRoot = launch_info.GetUserID() == 0;1404  bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;1405 1406  if (launchingAsRoot && !currentUserIsRoot) {1407    // If current user is already root, we don't need XPC's help.1408    result = true;1409  }1410#endif1411 1412  return result;1413}1414 1415Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {1416  Status error;1417 1418  FileSystem &fs = FileSystem::Instance();1419  FileSpec exe_spec(launch_info.GetExecutableFile());1420 1421  if (!fs.Exists(exe_spec))1422    FileSystem::Instance().Resolve(exe_spec);1423 1424  if (!fs.Exists(exe_spec))1425    FileSystem::Instance().ResolveExecutableLocation(exe_spec);1426 1427  if (!fs.Exists(exe_spec)) {1428    error = Status::FromErrorStringWithFormatv(1429        "executable doesn't exist: '{0}'", exe_spec);1430    return error;1431  }1432 1433  if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) {1434#if TARGET_OS_OSX1435    return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(),1436                                              launch_info);1437#else1438    error =1439        Status::FromErrorString("launching a process in a new terminal is not "1440                                "supported on iOS devices");1441    return error;1442#endif1443  }1444 1445  lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;1446 1447  auto exe_path = exe_spec.GetPath();1448 1449  if (ShouldLaunchUsingXPC(launch_info))1450    error = LaunchProcessXPC(exe_path.c_str(), launch_info, pid);1451  else1452    error = LaunchProcessPosixSpawn(exe_path.c_str(), launch_info, pid);1453 1454  if (pid != LLDB_INVALID_PROCESS_ID) {1455    // If all went well, then set the process ID into the launch info1456    launch_info.SetProcessID(pid);1457 1458    // Make sure we reap any processes we spawn or we will have zombies.1459    bool monitoring = launch_info.MonitorProcess();1460    UNUSED_IF_ASSERT_DISABLED(monitoring);1461    assert(monitoring);1462  } else {1463    // Invalid process ID, something didn't go well1464    if (error.Success())1465      error =1466          Status::FromErrorString("process launch failed for unknown reasons");1467  }1468  return error;1469}1470 1471Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {1472  Status error;1473  if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {1474    FileSpec expand_tool_spec;1475    Environment host_env = Host::GetEnvironment();1476    std::string env_argdumper_path = host_env.lookup("LLDB_ARGDUMPER_PATH");1477    if (!env_argdumper_path.empty()) {1478      expand_tool_spec.SetFile(env_argdumper_path, FileSpec::Style::native);1479      Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));1480      LLDB_LOGF(log,1481                "lldb-argdumper exe path set from environment variable: %s",1482                env_argdumper_path.c_str());1483    }1484    bool argdumper_exists = FileSystem::Instance().Exists(env_argdumper_path);1485    if (!argdumper_exists) {1486      expand_tool_spec = HostInfo::GetSupportExeDir();1487      if (!expand_tool_spec) {1488        error = Status::FromErrorString(1489            "could not get support executable directory for "1490            "lldb-argdumper tool");1491        return error;1492      }1493      expand_tool_spec.AppendPathComponent("lldb-argdumper");1494      if (!FileSystem::Instance().Exists(expand_tool_spec)) {1495        error = Status::FromErrorStringWithFormat(1496            "could not find the lldb-argdumper tool: %s",1497            expand_tool_spec.GetPath().c_str());1498        return error;1499      }1500    }1501 1502    StreamString expand_tool_spec_stream;1503    expand_tool_spec_stream.Printf("\"%s\"",1504                                   expand_tool_spec.GetPath().c_str());1505 1506    Args expand_command(expand_tool_spec_stream.GetData());1507    expand_command.AppendArguments(launch_info.GetArguments());1508 1509    int status;1510    std::string output;1511    FileSpec cwd(launch_info.GetWorkingDirectory());1512    if (!FileSystem::Instance().Exists(cwd)) {1513      char *wd = getcwd(nullptr, 0);1514      if (wd == nullptr) {1515        error = Status::FromErrorStringWithFormat(1516            "cwd does not exist: Cannot launch with shell argument expansion");1517        return error;1518      } else {1519        FileSpec working_dir(wd);1520        free(wd);1521        launch_info.SetWorkingDirectory(working_dir);1522      }1523    }1524    bool run_in_shell = true;1525    bool hide_stderr = true;1526    Status e =1527        RunShellCommand(expand_command, cwd, &status, nullptr, &output,1528                        std::chrono::seconds(10), run_in_shell, hide_stderr);1529 1530    if (e.Fail())1531      return e;1532 1533    if (status != 0) {1534      error = Status::FromErrorStringWithFormat(1535          "lldb-argdumper exited with error %d", status);1536      return error;1537    }1538 1539    auto data_sp = StructuredData::ParseJSON(output);1540    if (!data_sp) {1541      error = Status::FromErrorString("invalid JSON");1542      return error;1543    }1544 1545    auto dict_sp = data_sp->GetAsDictionary();1546    if (!data_sp) {1547      error = Status::FromErrorString("invalid JSON");1548      return error;1549    }1550 1551    auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");1552    if (!args_sp) {1553      error = Status::FromErrorString("invalid JSON");1554      return error;1555    }1556 1557    auto args_array_sp = args_sp->GetAsArray();1558    if (!args_array_sp) {1559      error = Status::FromErrorString("invalid JSON");1560      return error;1561    }1562 1563    launch_info.GetArguments().Clear();1564 1565    for (size_t i = 0; i < args_array_sp->GetSize(); i++) {1566      auto item_sp = args_array_sp->GetItemAtIndex(i);1567      if (!item_sp)1568        continue;1569      auto str_sp = item_sp->GetAsString();1570      if (!str_sp)1571        continue;1572 1573      launch_info.GetArguments().AppendArgument(str_sp->GetValue());1574    }1575  }1576 1577  return error;1578}1579 1580llvm::Expected<HostThread> Host::StartMonitoringChildProcess(1581    const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) {1582  unsigned long mask = DISPATCH_PROC_EXIT;1583 1584  Log *log(GetLog(LLDBLog::Host | LLDBLog::Process));1585 1586  dispatch_source_t source = ::dispatch_source_create(1587      DISPATCH_SOURCE_TYPE_PROC, pid, mask,1588      ::dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));1589 1590  LLDB_LOGF(log,1591            "Host::StartMonitoringChildProcess(callback, pid=%i) source = %p\n",1592            static_cast<int>(pid), static_cast<void *>(source));1593 1594  if (source) {1595    Host::MonitorChildProcessCallback callback_copy = callback;1596    ::dispatch_source_set_cancel_handler(source, ^{1597      dispatch_release(source);1598    });1599    ::dispatch_source_set_event_handler(source, ^{1600 1601      int status = 0;1602      int wait_pid = 0;1603      wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, 0);1604      if (wait_pid >= 0) {1605        int signal = 0;1606        int exit_status = 0;1607        const char *status_cstr = NULL;1608        if (WIFEXITED(status)) {1609          exit_status = WEXITSTATUS(status);1610          status_cstr = "EXITED";1611        } else if (WIFSIGNALED(status)) {1612          signal = WTERMSIG(status);1613          status_cstr = "SIGNALED";1614          exit_status = -1;1615        } else {1616          llvm_unreachable("Unknown status");1617        }1618 1619        LLDB_LOGF(log,1620                  "::waitpid (pid = %llu, &status, 0) => pid = %i, status "1621                  "= 0x%8.8x (%s), signal = %i, exit_status = %i",1622                  pid, wait_pid, status, status_cstr, signal, exit_status);1623 1624        if (callback_copy)1625          callback_copy(pid, signal, exit_status);1626 1627        ::dispatch_source_cancel(source);1628      }1629    });1630 1631    ::dispatch_resume(source);1632  }1633  return HostThread();1634}1635