Coverage Report

Created: 2022-01-18 06:27

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