Coverage Report

Created: 2023-09-30 09:22

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