LLDB mainline
Host.mm
Go to the documentation of this file.
1//===-- Host.mm -------------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Host/Host.h"
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#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#define LauncherXPCServiceAuthKey "auth-key"
24#define LauncherXPCServiceArgPrefxKey "arg"
25#define LauncherXPCServiceEnvPrefxKey "env"
26#define LauncherXPCServiceCPUTypeKey "cpuType"
27#define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags"
28#define LauncherXPCServiceStdInPathKeyKey "stdInPath"
29#define LauncherXPCServiceStdOutPathKeyKey "stdOutPath"
30#define LauncherXPCServiceStdErrPathKeyKey "stdErrPath"
31#define LauncherXPCServiceChildPIDKey "childPID"
32#define LauncherXPCServiceErrorTypeKey "errorType"
33#define LauncherXPCServiceCodeTypeKey "errorCode"
34
35#include <bsm/audit.h>
36#include <bsm/audit_session.h>
37#endif
38
39#include "llvm/TargetParser/Host.h"
40
41#include <asl.h>
42#include <cassert>
43#include <cerrno>
44#include <crt_externs.h>
45#include <cstdio>
46#include <cstdlib>
47#include <dlfcn.h>
48#include <grp.h>
49#include <libproc.h>
50#include <pwd.h>
51#include <spawn.h>
52#include <sys/proc.h>
53#include <sys/stat.h>
54#include <sys/sysctl.h>
55#include <sys/types.h>
56#include <unistd.h>
57
60#include "lldb/Host/HostInfo.h"
67#include "lldb/Utility/Endian.h"
69#include "lldb/Utility/Log.h"
74#include "lldb/lldb-defines.h"
75
76#include "llvm/ADT/ScopeExit.h"
77#include "llvm/Support/Errno.h"
78#include "llvm/Support/Error.h"
79#include "llvm/Support/ErrorExtras.h"
80#include "llvm/Support/FileSystem.h"
81
82#include "../cfcpp/CFCBundle.h"
86#include "../cfcpp/CFCString.h"
87
88#include <objc/objc-auto.h>
89#include <os/log.h>
90
91#include <CoreFoundation/CoreFoundation.h>
92#include <Foundation/Foundation.h>
93
94#ifndef _POSIX_SPAWN_DISABLE_ASLR
95#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
96#endif
97
98extern "C" {
99int __pthread_chdir(const char *path);
100int __pthread_fchdir(int fildes);
101}
102
103using namespace lldb;
104using namespace lldb_private;
105
106static os_log_t g_os_log;
107static std::once_flag g_os_log_once;
108
109void Host::SystemLog(Severity severity, llvm::StringRef message) {
110 if (__builtin_available(macos 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
111 std::call_once(g_os_log_once, []() {
112 g_os_log = os_log_create("com.apple.dt.lldb", "lldb");
113 });
114 switch (severity) {
117 os_log(g_os_log, "%{public}s", message.str().c_str());
118 break;
120 os_log_error(g_os_log, "%{public}s", message.str().c_str());
121 break;
122 }
123 } else {
124 llvm::errs() << message;
125 }
126}
127
128bool Host::GetBundleDirectory(const FileSpec &file,
129 FileSpec &bundle_directory) {
130#if defined(__APPLE__)
131 if (FileSystem::Instance().IsDirectory(file)) {
132 char path[PATH_MAX];
133 if (file.GetPath(path, sizeof(path))) {
134 CFCBundle bundle(path);
135 if (bundle.GetPath(path, sizeof(path))) {
136 bundle_directory.SetFile(path, FileSpec::Style::native);
137 return true;
138 }
139 }
140 }
141#endif
142 bundle_directory.Clear();
143 return false;
144}
145
147#if defined(__APPLE__)
148 if (FileSystem::Instance().IsDirectory(file)) {
149 char path[PATH_MAX];
150 if (file.GetPath(path, sizeof(path))) {
151 CFCBundle bundle(path);
152 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL());
153 if (url.get()) {
154 if (::CFURLGetFileSystemRepresentation(url.get(), YES, (UInt8 *)path,
155 sizeof(path))) {
156 file.SetFile(path, FileSpec::Style::native);
157 return true;
158 }
159 }
160 }
161 }
162#endif
163 return false;
164}
165
166#if TARGET_OS_OSX
167
168static void *AcceptPIDFromInferior(const char *connect_url) {
169 ConnectionFileDescriptor file_conn;
171 if (file_conn.Connect(connect_url, &error) == eConnectionStatusSuccess) {
172 char pid_str[256];
173 ::memset(pid_str, 0, sizeof(pid_str));
174 ConnectionStatus status;
175 const size_t pid_str_len = file_conn.Read(
176 pid_str, sizeof(pid_str), std::chrono::seconds(0), status, NULL);
177 if (pid_str_len > 0) {
178 int pid = atoi(pid_str);
179 return (void *)(intptr_t)pid;
180 }
181 }
182 return NULL;
183}
184
185const char *applscript_in_new_tty = "tell application \"Terminal\"\n"
186 " activate\n"
187 " do script \"/bin/bash -c '%s';exit\"\n"
188 "end tell\n";
189
190const char *applscript_in_existing_tty = "\
191set the_shell_script to \"/bin/bash -c '%s';exit\"\n\
192tell application \"Terminal\"\n\
193 repeat with the_window in (get windows)\n\
194 repeat with the_tab in tabs of the_window\n\
195 set the_tty to tty in the_tab\n\
196 if the_tty contains \"%s\" then\n\
197 if the_tab is not busy then\n\
198 set selected of the_tab to true\n\
199 set frontmost of the_window to true\n\
200 do script the_shell_script in the_tab\n\
201 return\n\
202 end if\n\
203 end if\n\
204 end repeat\n\
205 end repeat\n\
206 do script the_shell_script\n\
207end tell\n";
208
209static Status
210LaunchInNewTerminalWithAppleScript(const char *exe_path,
211 ProcessLaunchInfo &launch_info) {
213 char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
214 if (::mktemp(unix_socket_name) == NULL) {
216 "failed to make temporary path for a unix socket");
217 return error;
218 }
219
220 StreamString command;
221 FileSpec darwin_debug_file_spec = HostInfo::GetSupportExeDir();
222 if (!darwin_debug_file_spec) {
223 error =
224 Status::FromErrorString("can't locate the 'darwin-debug' executable");
225 return error;
226 }
227
228 darwin_debug_file_spec.SetFilename("darwin-debug");
229
230 if (!FileSystem::Instance().Exists(darwin_debug_file_spec)) {
232 "the 'darwin-debug' executable doesn't exists at '%s'",
233 darwin_debug_file_spec.GetPath().c_str());
234 return error;
235 }
236
237 char launcher_path[PATH_MAX];
238 darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
239
240 const ArchSpec &arch_spec = launch_info.GetArchitecture();
241 // Only set the architecture if it is valid and if it isn't Haswell (x86_64h).
242 if (arch_spec.IsValid() &&
244 command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());
245
246 command.Printf(R"(\"%s\" --unix-socket=%s)", launcher_path, unix_socket_name);
247
248 if (arch_spec.IsValid())
249 command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
250
251 FileSpec working_dir{launch_info.GetWorkingDirectory()};
252 if (working_dir)
253 command.Printf(R"( --working-dir \"%s\")", working_dir.GetPath().c_str());
254 else {
255 char cwd[PATH_MAX];
256 if (getcwd(cwd, PATH_MAX))
257 command.Printf(R"( --working-dir \"%s\")", cwd);
258 }
259
260 if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
261 command.PutCString(" --disable-aslr");
262
263 // We are launching on this host in a terminal. So compare the environment on
264 // the host to what is supplied in the launch_info. Any items that aren't in
265 // the host environment need to be sent to darwin-debug. If we send all
266 // environment entries, we might blow the max command line length, so we only
267 // send user modified entries.
269
270 for (const auto &KV : launch_info.GetEnvironment()) {
271 auto host_entry = host_env.find(KV.first());
272 if (host_entry == host_env.end() || host_entry->second != KV.second)
273 command.Format(R"( --env=\"{0}\")", Environment::compose(KV));
274 }
275
276 command.PutCString(" -- ");
277
278 const char **argv = launch_info.GetArguments().GetConstArgumentVector();
279 if (argv) {
280 for (size_t i = 0; argv[i] != NULL; ++i) {
281 if (i == 0)
282 command.Printf(R"( \"%s\")", exe_path);
283 else
284 command.Printf(R"( \"%s\")", argv[i]);
285 }
286 } else {
287 command.Printf(R"( \"%s\")", exe_path);
288 }
289 command.PutCString(" ; echo Process exited with status $?");
290 if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))
291 command.PutCString(" ; exit");
292
293 StreamString applescript_source;
294
295 applescript_source.Printf(applscript_in_new_tty,
296 command.GetString().str().c_str());
297
298 NSAppleScript *applescript = [[NSAppleScript alloc]
299 initWithSource:[NSString stringWithCString:applescript_source.GetString()
300 .str()
301 .c_str()
302 encoding:NSUTF8StringEncoding]];
303
305
306 Status lldb_error;
307 // Sleep and wait a bit for debugserver to start to listen...
308 ConnectionFileDescriptor file_conn;
309 char connect_url[128];
310 ::snprintf(connect_url, sizeof(connect_url), "unix-accept://%s",
311 unix_socket_name);
312
313 // Spawn a new thread to accept incoming connection on the connect_url
314 // so we can grab the pid from the inferior. We have to do this because we
315 // are sending an AppleScript that will launch a process in Terminal.app,
316 // in a shell and the shell will fork/exec a couple of times before we get
317 // to the process that we wanted to launch. So when our process actually
318 // gets launched, we will handshake with it and get the process ID for it.
319 llvm::Expected<HostThread> accept_thread = ThreadLauncher::LaunchThread(
320 unix_socket_name, [&] { return AcceptPIDFromInferior(connect_url); });
321
322 if (!accept_thread)
323 return Status::FromError(accept_thread.takeError());
324
325 [applescript executeAndReturnError:nil];
326
327 thread_result_t accept_thread_result = NULL;
328 lldb_error = accept_thread->Join(&accept_thread_result);
329 if (lldb_error.Success() && accept_thread_result) {
330 pid = (intptr_t)accept_thread_result;
331 }
332
333 llvm::sys::fs::remove(unix_socket_name);
334 [applescript release];
335 if (pid != LLDB_INVALID_PROCESS_ID)
336 launch_info.SetProcessID(pid);
337 return error;
338}
339
340#endif // TARGET_OS_OSX
341
342llvm::Error Host::OpenFileInExternalEditor(llvm::StringRef editor,
343 const FileSpec &file_spec,
344 uint32_t line_no) {
345#if !TARGET_OS_OSX
346 return llvm::errorCodeToError(
347 std::error_code(ENOTSUP, std::system_category()));
348#else // !TARGET_OS_OSX
349 Log *log = GetLog(LLDBLog::Host);
350
351 const std::string file_path = file_spec.GetPath();
352
353 LLDB_LOG(log, "Sending {0}:{1} to external editor",
354 file_path.empty() ? "<invalid>" : file_path, line_no);
355
356 if (file_path.empty())
357 return llvm::createStringError(llvm::inconvertibleErrorCode(),
358 "no file specified");
359
360 CFCString file_cfstr(file_path.c_str(), kCFStringEncodingUTF8);
361 CFCReleaser<CFURLRef> file_URL = ::CFURLCreateWithFileSystemPath(
362 /*allocator=*/NULL,
363 /*filePath*/ file_cfstr.get(),
364 /*pathStyle=*/kCFURLPOSIXPathStyle,
365 /*isDirectory=*/false);
366
367 if (!file_URL.get())
368 return llvm::createStringError(
369 llvm::inconvertibleErrorCode(),
370 llvm::formatv("could not create CFURL from path \"{0}\"", file_path));
371
372 // Create a new Apple Event descriptor.
373 typedef struct {
374 int16_t reserved0; // must be zero
375 int16_t fLineNumber;
376 int32_t fSelStart;
377 int32_t fSelEnd;
378 uint32_t reserved1; // must be zero
379 uint32_t reserved2; // must be zero
380 } BabelAESelInfo;
381
382 // We attach this to an 'odoc' event to specify a particular selection.
383 BabelAESelInfo file_and_line_info = {
384 0, // reserved0
385 (int16_t)(line_no - 1), // fLineNumber (zero based line number)
386 1, // fSelStart
387 1024, // fSelEnd
388 0, // reserved1
389 0 // reserved2
390 };
391
392 AEKeyDesc file_and_line_desc;
393 file_and_line_desc.descKey = keyAEPosition;
394 long error = ::AECreateDesc(/*typeCode=*/typeUTF8Text,
395 /*dataPtr=*/&file_and_line_info,
396 /*dataSize=*/sizeof(file_and_line_info),
397 /*result=*/&(file_and_line_desc.descContent));
398
399 if (error != noErr)
400 return llvm::createStringError(
401 llvm::inconvertibleErrorCode(),
402 llvm::formatv("creating Apple Event descriptor failed: error {0}",
403 error));
404
405 // Deallocate the descriptor on exit.
406 llvm::scope_exit on_exit(
407 [&]() { AEDisposeDesc(&(file_and_line_desc.descContent)); });
408
409 if (editor.empty()) {
410 if (const char *lldb_external_editor = ::getenv("LLDB_EXTERNAL_EDITOR"))
411 editor = lldb_external_editor;
412 }
413
414 std::optional<FSRef> app_fsref;
415 if (!editor.empty()) {
416 LLDB_LOG(log, "Looking for external editor: {0}", editor);
417
418 app_fsref.emplace();
419 CFCString editor_name(editor.data(), kCFStringEncodingUTF8);
420 long app_error = ::LSFindApplicationForInfo(
421 /*inCreator=*/kLSUnknownCreator, /*inBundleID=*/NULL,
422 /*inName=*/editor_name.get(), /*outAppRef=*/&(*app_fsref),
423 /*outAppURL=*/NULL);
424 if (app_error != noErr)
425 return llvm::createStringError(
426 llvm::inconvertibleErrorCode(),
427 llvm::formatv("could not find external editor \"{0}\": "
428 "LSFindApplicationForInfo returned error {1}",
429 editor, app_error));
430 }
431
432 // Build app launch parameters.
433 LSApplicationParameters app_params;
434 ::memset(&app_params, 0, sizeof(app_params));
435 app_params.flags =
436 kLSLaunchDefaults | kLSLaunchDontAddToRecents | kLSLaunchDontSwitch;
437 if (app_fsref)
438 app_params.application = &(*app_fsref);
439
440 ProcessSerialNumber psn;
441 std::array<CFURLRef, 1> file_array = {file_URL.get()};
442 CFCReleaser<CFArrayRef> cf_array(
443 CFArrayCreate(/*allocator=*/NULL, /*values=*/(const void **)&file_array,
444 /*numValues*/ 1, /*callBacks=*/NULL));
445 error = ::LSOpenURLsWithRole(
446 /*inURLs=*/cf_array.get(), /*inRole=*/kLSRolesEditor,
447 /*inAEParam=*/&file_and_line_desc,
448 /*inAppParams=*/&app_params, /*outPSNs=*/&psn, /*inMaxPSNCount=*/1);
449
450 if (error != noErr)
451 return llvm::createStringError(
452 llvm::inconvertibleErrorCode(),
453 llvm::formatv("LSOpenURLsWithRole failed: error {0}", error));
454
455 return llvm::Error::success();
456#endif // TARGET_OS_OSX
457}
458
459llvm::Error Host::OpenURL(llvm::StringRef url) {
460#if !TARGET_OS_OSX
461 return llvm::errorCodeToError(
462 std::error_code(ENOTSUP, std::system_category()));
463#else // !TARGET_OS_OSX
464 if (url.empty())
465 return llvm::createStringError("cannot open empty URL");
466
467 LLDB_LOG(GetLog(LLDBLog::Host), "Opening URL: {0}", url);
468
469 CFCString url_cfstr(url.data(), kCFStringEncodingUTF8);
470 CFCReleaser<CFURLRef> cfurl = ::CFURLCreateWithString(
471 /*allocator=*/NULL,
472 /*URLString*/ url_cfstr.get(),
473 /*baseURL=*/NULL);
474
475 if (!cfurl.get())
476 return llvm::createStringError(
477 llvm::formatv("could not create CFURL from URL \"{0}\"", url));
478
479 OSStatus error = ::LSOpenCFURLRef(
480 /*inURL=*/cfurl.get(),
481 /*outLaunchedURL=*/NULL);
482
483 if (error != noErr)
484 return llvm::createStringError(
485 llvm::formatv("LSOpenCFURLRef failed: error {0:x}", error));
486
487 return llvm::Error::success();
488#endif // TARGET_OS_OSX
489}
490
492#if !TARGET_OS_OSX
493 return false;
494#else
495 auditinfo_addr_t info;
496 getaudit_addr(&info, sizeof(info));
497 return info.ai_flags & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS;
498#endif
499}
500
501Environment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); }
502
504 if (process_info.ProcessIDIsValid()) {
505 // Make a new mib to stay thread safe
506 int mib[CTL_MAXNAME] = {
507 0,
508 };
509 size_t mib_len = CTL_MAXNAME;
510 if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len))
511 return false;
512
513 mib[mib_len] = process_info.GetProcessID();
514 mib_len++;
515
516 cpu_type_t cpu, sub = 0;
517 size_t len = sizeof(cpu);
518 if (::sysctl(mib, mib_len, &cpu, &len, 0, 0) == 0) {
519 switch (cpu) {
520 case CPU_TYPE_I386:
521 sub = CPU_SUBTYPE_I386_ALL;
522 break;
523 case CPU_TYPE_X86_64:
524 sub = CPU_SUBTYPE_X86_64_ALL;
525 break;
526
527#if defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64_ALL)
528 case CPU_TYPE_ARM64:
529 sub = CPU_SUBTYPE_ARM64_ALL;
530 break;
531#endif
532
533#if defined(CPU_TYPE_ARM64_32) && defined(CPU_SUBTYPE_ARM64_32_ALL)
535 sub = CPU_SUBTYPE_ARM64_32_ALL;
536 break;
537#endif
538
539 case CPU_TYPE_ARM: {
540 // Note that we fetched the cpu type from the PROCESS but we can't get a
541 // cpusubtype of the
542 // process -- we can only get the host's cpu subtype.
543 uint32_t cpusubtype = 0;
544 len = sizeof(cpusubtype);
545 if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
546 sub = cpusubtype;
547
548 bool host_cpu_is_64bit;
549 uint32_t is64bit_capable;
550 size_t is64bit_capable_len = sizeof(is64bit_capable);
551 host_cpu_is_64bit =
552 sysctlbyname("hw.cpu64bit_capable", &is64bit_capable,
553 &is64bit_capable_len, NULL, 0) == 0;
554
555 // if the host is an armv8 device, its cpusubtype will be in
556 // CPU_SUBTYPE_ARM64 numbering
557 // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value
558 // instead.
559
560 if (host_cpu_is_64bit) {
561 sub = CPU_SUBTYPE_ARM_V7;
562 }
563 } break;
564
565 default:
566 break;
567 }
568 process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, sub);
569 return true;
570 }
571 }
572 process_info.GetArchitecture().Clear();
573 return false;
574}
575
576static bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
577 ProcessInstanceInfo &process_info) {
578 if (process_info.ProcessIDIsValid()) {
579 int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2,
580 (int)process_info.GetProcessID()};
581
582 size_t arg_data_size = 0;
583 if (::sysctl(proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) ||
584 arg_data_size == 0)
585 arg_data_size = 8192;
586
587 // Add a few bytes to the calculated length, I know we need to add at least
588 // one byte
589 // to this number otherwise we get junk back, so add 128 just in case...
590 DataBufferHeap arg_data(arg_data_size + 128, 0);
591 arg_data_size = arg_data.GetByteSize();
592 if (::sysctl(proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size, NULL,
593 0) == 0) {
594 DataExtractor data(arg_data.GetBytes(), arg_data_size,
595 endian::InlHostByteOrder(), sizeof(void *));
596 lldb::offset_t offset = 0;
597 uint32_t argc = data.GetU32(&offset);
598 llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
599 const llvm::Triple::ArchType triple_arch = triple.getArch();
600 const bool check_for_ios_simulator =
601 (triple_arch == llvm::Triple::x86 ||
602 triple_arch == llvm::Triple::x86_64 ||
603 triple_arch == llvm::Triple::aarch64);
604
605 const char *cstr = data.GetCStr(&offset);
606 if (cstr) {
607 process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);
608
609 if (match_info_ptr == NULL ||
611 process_info.GetExecutableFile().GetFilename().GetCString(),
612 match_info_ptr->GetNameMatchType(),
613 match_info_ptr->GetProcessInfo().GetName())) {
614 // Skip NULLs
615 while (true) {
616 const uint8_t *p = data.PeekData(offset, 1);
617 if ((p == NULL) || (*p != '\0'))
618 break;
619 ++offset;
620 }
621
622 // Skip argv[0] as we already have the file name from the executable path.
623 if (argc > 0)
624 process_info.SetArg0(data.GetCStr(&offset));
625
626 // Now extract the rest of the arguments.
627 Args &proc_args = process_info.GetArguments();
628 for (int i = 1; i < static_cast<int>(argc); ++i) {
629 cstr = data.GetCStr(&offset);
630 if (cstr)
631 proc_args.AppendArgument(llvm::StringRef(cstr));
632 }
633
634 Environment &proc_env = process_info.GetEnvironment();
635 bool is_simulator = false;
636 llvm::StringRef env_var;
637 while (!(env_var = data.GetCStr(&offset)).empty()) {
638 if (check_for_ios_simulator &&
639 env_var.starts_with("SIMULATOR_UDID="))
640 is_simulator = true;
641 proc_env.insert(env_var);
642 }
643 llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
644 if (is_simulator) {
645 triple.setOS(llvm::Triple::IOS);
646 triple.setEnvironment(llvm::Triple::Simulator);
647 } else {
648 triple.setOS(llvm::Triple::MacOSX);
649 }
650 return true;
651 }
652 }
653 }
654 }
655 return false;
656}
657
659 if (process_info.ProcessIDIsValid()) {
660 int mib[4];
661 mib[0] = CTL_KERN;
662 mib[1] = KERN_PROC;
663 mib[2] = KERN_PROC_PID;
664 mib[3] = process_info.GetProcessID();
665 struct kinfo_proc proc_kinfo;
666 size_t proc_kinfo_size = sizeof(struct kinfo_proc);
667
668 if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
669 if (proc_kinfo_size > 0) {
670 process_info.SetParentProcessID(proc_kinfo.kp_eproc.e_ppid);
671 process_info.SetUserID(proc_kinfo.kp_eproc.e_pcred.p_ruid);
672 process_info.SetGroupID(proc_kinfo.kp_eproc.e_pcred.p_rgid);
673 process_info.SetEffectiveUserID(proc_kinfo.kp_eproc.e_ucred.cr_uid);
674 if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
675 process_info.SetEffectiveGroupID(
676 proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
677 else
678 process_info.SetEffectiveGroupID(UINT32_MAX);
679 return true;
680 }
681 }
682 }
684 process_info.SetUserID(UINT32_MAX);
685 process_info.SetGroupID(UINT32_MAX);
686 process_info.SetEffectiveUserID(UINT32_MAX);
687 process_info.SetEffectiveGroupID(UINT32_MAX);
688 return false;
689}
690
691/// Fetches the list of all processes into \p kinfos.
692static llvm::Error GetProcessList(std::vector<struct kinfo_proc> &kinfos) {
693 int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
694
695 // How often we retry fetching the process list.
696 static constexpr unsigned g_retry_count = 200;
697 // The rate at which we increase the adjusted buffer size to
698 // account for newly created processes between two sysctl calls.
699 static constexpr unsigned g_expected_new_pids = 500;
700 // We keep increasing the expected growth rate between the two
701 // sysctl calls. Check that the last attempt does not create an
702 // unreasonbly large buffer. It is unlikely we run on a system where
703 // 100k processes are repeatedly created between each attempted sysctl
704 // pair.
705 static_assert(
706 g_retry_count * g_expected_new_pids <= 100'000,
707 "Final retry attempt assumes an unlikely amount of new processes.");
708
709 // This is an inherently racy API. We have to first query the size for our
710 // buffer and then pass it back to sysctl. If more processes spawn between the
711 // size query and the actual call to fetch, then sysctl returns ENOMEM.
712 // We keep retrying until we get a passing result.
713 for (unsigned attempt = 1; attempt < g_retry_count; ++attempt) {
714 // Fetch the buffer size sysctl would return.
715 size_t current_pid_size = 0;
716 if (::sysctl(mib, 3, nullptr, &current_pid_size, nullptr, 0) != 0)
717 return llvm::errorCodeToError(
718 std::error_code(errno, std::generic_category()));
719
720 // Convert the byte length result to number of elements.
721 const size_t current_num_processes =
722 current_pid_size / sizeof(struct kinfo_proc);
723
724 // Adjust the buffer for new processes that spawned between the
725 // previous and next sysctl call. We increase this growth each attempt
726 // to account for systems where a lot of new processes spawn between
727 // these two calls.
728 const size_t expected_growth = attempt * g_expected_new_pids;
729
730 // Allocate the buffer for the sysctl result.
731 kinfos.resize(current_num_processes + expected_growth);
732
733 // Fetch the actual process list and let sysctl adjust actual_pid_size.
734 size_t actual_pid_size = kinfos.size() * sizeof(struct kinfo_proc);
735 if (::sysctl(mib, 3, &kinfos[0], &actual_pid_size, nullptr, 0) == 0) {
736 // Shrink the buffer to the actual number of processes returned.
737 kinfos.resize(actual_pid_size / sizeof(struct kinfo_proc));
738 return llvm::Error::success();
739 }
740
741 // Errno is set to ENOMEM if our estimated_pid_size is too small, in which
742 // case we retry with a bigger buffer. Any other error is unexpected.
743 if (errno != ENOMEM)
744 return llvm::errorCodeToError(
745 std::error_code(errno, std::generic_category()));
746 }
747
748 // The only way to exit the loop above is by repeatedly hitting ENOMEM. The
749 // only way this can happen is if the process list somehow grew extremely
750 // large between the two sysctl calls.
751 assert(errno == ENOMEM &&
752 "loop should only be left via the ENOMEM retry path");
753 return llvm::createStringErrorV(
754 "Failed to read process list: sysctl kept returning ENOMEM after {0} "
755 "attempts",
756 g_retry_count);
757}
758
759uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
760 ProcessInstanceInfoList &process_infos) {
761 std::vector<struct kinfo_proc> kinfos;
762 if (llvm::Error error = GetProcessList(kinfos)) {
764 "failed to read process list: {0}");
765 return 0;
766 }
767
768 bool all_users = match_info.GetMatchAllUsers();
769 const lldb::pid_t our_pid = getpid();
770 const uid_t our_uid = getuid();
771 for (const struct kinfo_proc &kinfo : kinfos) {
772 bool kinfo_user_matches = false;
773 if (all_users)
774 kinfo_user_matches = true;
775 else
776 kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
777
778 // Special case, if lldb is being run as root we can attach to anything.
779 if (our_uid == 0)
780 kinfo_user_matches = true;
781
782 if (!kinfo_user_matches || // Make sure the user is acceptable
783 static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) ==
784 our_pid || // Skip this process
785 kinfo.kp_proc.p_pid == 0 || // Skip kernel (kernel pid is zero)
786 kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains...
787 kinfo.kp_proc.p_flag & P_TRACED || // Being debugged?
788 kinfo.kp_proc.p_flag & P_WEXIT)
789 continue;
790
791 ProcessInstanceInfo process_info;
792 process_info.SetProcessID(kinfo.kp_proc.p_pid);
793 process_info.SetParentProcessID(kinfo.kp_eproc.e_ppid);
794 process_info.SetUserID(kinfo.kp_eproc.e_pcred.p_ruid);
795 process_info.SetGroupID(kinfo.kp_eproc.e_pcred.p_rgid);
796 process_info.SetEffectiveUserID(kinfo.kp_eproc.e_ucred.cr_uid);
797 if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
798 process_info.SetEffectiveGroupID(kinfo.kp_eproc.e_ucred.cr_groups[0]);
799 else
800 process_info.SetEffectiveGroupID(UINT32_MAX);
801
802 // Make sure our info matches before we go fetch the name and cpu type
803 if (!match_info.UserIDsMatch(process_info) ||
804 !match_info.ProcessIDsMatch(process_info))
805 continue;
806
807 // Get CPU type first so we can know to look for iOS simulator if we have
808 // a compatible type.
809 if (GetMacOSXProcessCPUType(process_info)) {
810 if (GetMacOSXProcessArgs(&match_info, process_info)) {
811 if (match_info.Matches(process_info))
812 process_infos.push_back(process_info);
813 }
814 }
815 }
816 return process_infos.size();
817}
818
820 process_info.SetProcessID(pid);
821 bool success = false;
822
823 // Get CPU type first so we can know to look for iOS simulator is we have x86
824 // or x86_64
825 if (GetMacOSXProcessCPUType(process_info))
826 success = true;
827
828 if (GetMacOSXProcessArgs(NULL, process_info))
829 success = true;
830
831 if (GetMacOSXProcessUserAndGroup(process_info))
832 success = true;
833
834 if (success)
835 return true;
836
837 process_info.Clear();
838 return false;
839}
840
841#if TARGET_OS_OSX
842static void PackageXPCArguments(xpc_object_t message, const char *prefix,
843 const Args &args) {
844 size_t count = args.GetArgumentCount();
845 char buf[50]; // long enough for 'argXXX'
846 memset(buf, 0, sizeof(buf));
847 snprintf(buf, sizeof(buf), "%sCount", prefix);
848 xpc_dictionary_set_int64(message, buf, count);
849 for (size_t i = 0; i < count; i++) {
850 memset(buf, 0, sizeof(buf));
851 snprintf(buf, sizeof(buf), "%s%zi", prefix, i);
852 xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
853 }
854}
855
856static void PackageXPCEnvironment(xpc_object_t message, llvm::StringRef prefix,
857 const Environment &env) {
858 xpc_dictionary_set_int64(message, (prefix + "Count").str().c_str(),
859 env.size());
860 size_t i = 0;
861 for (const auto &KV : env) {
862 xpc_dictionary_set_string(message, (prefix + llvm::Twine(i)).str().c_str(),
863 Environment::compose(KV).c_str());
864 }
865}
866
867/*
868 A valid authorizationRef means that
869 - there is the LaunchUsingXPCRightName rights in the /etc/authorization
870 - we have successfully copied the rights to be send over the XPC wire
871 Once obtained, it will be valid for as long as the process lives.
872 */
873static AuthorizationRef authorizationRef = NULL;
874static Status getXPCAuthorization(ProcessLaunchInfo &launch_info) {
877
878 if ((launch_info.GetUserID() == 0) && !authorizationRef) {
879 OSStatus createStatus =
880 AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
881 kAuthorizationFlagDefaults, &authorizationRef);
882 if (createStatus != errAuthorizationSuccess) {
884 error = Status::FromErrorString("Can't create authorizationRef.");
885 LLDB_LOG(log, "error: {0}", error);
886 return error;
887 }
888
889 OSStatus rightsStatus =
890 AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
891 if (rightsStatus != errAuthorizationSuccess) {
892 // No rights in the security database, Create it with the right prompt.
893 CFStringRef prompt =
894 CFSTR("Xcode is trying to take control of a root process.");
895 CFStringRef keys[] = {CFSTR("en")};
896 CFTypeRef values[] = {prompt};
897 CFDictionaryRef promptDict = CFDictionaryCreate(
898 kCFAllocatorDefault, (const void **)keys, (const void **)values, 1,
899 &kCFCopyStringDictionaryKeyCallBacks,
900 &kCFTypeDictionaryValueCallBacks);
901
902 CFStringRef keys1[] = {CFSTR("class"), CFSTR("group"), CFSTR("comment"),
903 CFSTR("default-prompt"), CFSTR("shared")};
904 CFTypeRef values1[] = {CFSTR("user"), CFSTR("admin"),
905 CFSTR(LaunchUsingXPCRightName), promptDict,
906 kCFBooleanFalse};
907 CFDictionaryRef dict = CFDictionaryCreate(
908 kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5,
909 &kCFCopyStringDictionaryKeyCallBacks,
910 &kCFTypeDictionaryValueCallBacks);
911 rightsStatus = AuthorizationRightSet(
912 authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
913 CFRelease(promptDict);
914 CFRelease(dict);
915 }
916
917 OSStatus copyRightStatus = errAuthorizationDenied;
918 if (rightsStatus == errAuthorizationSuccess) {
919 AuthorizationItem item1 = {LaunchUsingXPCRightName, 0, NULL, 0};
920 AuthorizationItem items[] = {item1};
921 AuthorizationRights requestedRights = {1, items};
922 AuthorizationFlags authorizationFlags =
923 kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
924 copyRightStatus = AuthorizationCopyRights(
925 authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment,
926 authorizationFlags, NULL);
927 }
928
929 if (copyRightStatus != errAuthorizationSuccess) {
930 // Eventually when the commandline supports running as root and the user
931 // is not
932 // logged in to the current audit session, we will need the trick in gdb
933 // where
934 // we ask the user to type in the root passwd in the terminal.
937 "Launching as root needs root authorization.");
938 LLDB_LOG(log, "error: {0}", error);
939
940 if (authorizationRef) {
941 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
942 authorizationRef = NULL;
943 }
944 }
945 }
946
947 return error;
948}
949#endif
950
951static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {
952 short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
953
954 if (launch_info.GetFlags().Test(eLaunchFlagExec))
955 flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
956
957 if (launch_info.GetFlags().Test(eLaunchFlagDebug))
958 flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
959
960 if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
961 flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
962
963 if (launch_info.GetLaunchInSeparateProcessGroup())
964 flags |= POSIX_SPAWN_SETPGROUP;
965
966#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
967#if defined(__x86_64__) || defined(__i386__)
968 static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
969 if (g_use_close_on_exec_flag == eLazyBoolCalculate) {
970 g_use_close_on_exec_flag = eLazyBoolNo;
971
972 llvm::VersionTuple version = HostInfo::GetOSVersion();
973 if (version > llvm::VersionTuple(10, 7)) {
974 // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or
975 // earlier
976 g_use_close_on_exec_flag = eLazyBoolYes;
977 }
978 }
979#else
980 static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
981#endif // defined(__x86_64__) || defined(__i386__)
982 // Close all files exception those with file actions if this is supported.
983 if (g_use_close_on_exec_flag == eLazyBoolYes)
984 flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
985#endif // ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
986 return flags;
987}
988
989static void finalize_xpc(void *xpc_object) {
990 xpc_release((xpc_object_t)xpc_object);
991}
992
993static Status LaunchProcessXPC(const char *exe_path,
994 ProcessLaunchInfo &launch_info,
995 lldb::pid_t &pid) {
996#if TARGET_OS_OSX
997 Status error = getXPCAuthorization(launch_info);
998 if (error.Fail())
999 return error;
1000
1002
1003 uid_t requested_uid = launch_info.GetUserID();
1004 const char *xpc_service = nil;
1005 bool send_auth = false;
1006 AuthorizationExternalForm extForm;
1007 if (requested_uid == 0) {
1008 if (AuthorizationMakeExternalForm(authorizationRef, &extForm) ==
1009 errAuthorizationSuccess) {
1010 send_auth = true;
1011 } else {
1014 "Launching root via XPC needs to "
1015 "externalize authorization reference.");
1016 LLDB_LOG(log, "error: {0}", error);
1017 return error;
1018 }
1019 xpc_service = LaunchUsingXPCRightName;
1020 } else {
1023 "Launching via XPC is only currently available for root.");
1024 LLDB_LOG(log, "error: {0}", error);
1025 return error;
1026 }
1027
1028 xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
1029
1030 xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
1031 xpc_type_t type = xpc_get_type(event);
1032
1033 if (type == XPC_TYPE_ERROR) {
1034 if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
1035 // The service has either canceled itself, crashed, or been terminated.
1036 // The XPC connection is still valid and sending a message to it will
1037 // re-launch the service.
1038 // If the service is state-full, this is the time to initialize the new
1039 // service.
1040 return;
1041 } else if (event == XPC_ERROR_CONNECTION_INVALID) {
1042 // The service is invalid. Either the service name supplied to
1043 // xpc_connection_create() is incorrect
1044 // or we (this process) have canceled the service; we can do any cleanup
1045 // of application state at this point.
1046 // printf("Service disconnected");
1047 return;
1048 } else {
1049 // printf("Unexpected error from service: %s",
1050 // xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
1051 }
1052
1053 } else {
1054 // printf("Received unexpected event in handler");
1055 }
1056 });
1057
1058 xpc_connection_set_finalizer_f(conn, finalize_xpc);
1059 xpc_connection_resume(conn);
1060 xpc_object_t message = xpc_dictionary_create(nil, nil, 0);
1061
1062 if (send_auth) {
1063 xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes,
1064 sizeof(AuthorizationExternalForm));
1065 }
1066
1067 PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey,
1068 launch_info.GetArguments());
1069 PackageXPCEnvironment(message, LauncherXPCServiceEnvPrefxKey,
1070 launch_info.GetEnvironment());
1071
1072 // Posix spawn stuff.
1073 xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey,
1074 launch_info.GetArchitecture().GetMachOCPUType());
1075 xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey,
1076 GetPosixspawnFlags(launch_info));
1077 const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
1078 std::string file_action_path;
1079 if (file_action)
1080 file_action_path = file_action->GetFileSpec().GetPath();
1081
1082 if (!file_action_path.empty())
1083 xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey,
1084 file_action_path.c_str());
1085
1086 file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
1087 if (file_action)
1088 file_action_path = file_action->GetFileSpec().GetPath();
1089
1090 if (!file_action_path.empty())
1091 xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey,
1092 file_action_path.c_str());
1093
1094 file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
1095 if (file_action)
1096 file_action_path = file_action->GetFileSpec().GetPath();
1097
1098 if (!file_action_path.empty())
1099 xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey,
1100 file_action_path.c_str());
1101
1102 xpc_object_t reply =
1103 xpc_connection_send_message_with_reply_sync(conn, message);
1104 xpc_type_t returnType = xpc_get_type(reply);
1105 if (returnType == XPC_TYPE_DICTIONARY) {
1106 pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
1107 if (pid == 0) {
1108 int errorType =
1109 xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
1110 int errorCode =
1111 xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
1112
1113 error = Status(errorCode, eErrorTypeGeneric);
1115 "Problems with launching via XPC. Error type : %i, code : %i",
1116 errorType, errorCode);
1117 LLDB_LOG(log, "error: {0}", error);
1118
1119 if (authorizationRef) {
1120 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1121 authorizationRef = NULL;
1122 }
1123 }
1124 } else if (returnType == XPC_TYPE_ERROR) {
1127 "Problems with launching via XPC. XPC error : %s",
1128 xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
1129 LLDB_LOG(log, "error: {0}", error);
1130 }
1131
1132 return error;
1133#else
1134 Status error;
1135 return error;
1136#endif
1137}
1138
1139static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
1140 Log *log, Status &error) {
1141 if (info == NULL)
1142 return false;
1143
1144 posix_spawn_file_actions_t *file_actions =
1145 static_cast<posix_spawn_file_actions_t *>(_file_actions);
1146
1147 switch (info->GetAction()) {
1149 error.Clear();
1150 break;
1151
1153 if (info->GetFD() == -1)
1155 "invalid fd for posix_spawn_file_actions_addclose(...)");
1156 else {
1157 error = Status(
1158 ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),
1160 if (error.Fail())
1161 LLDB_LOG(log,
1162 "error: {0}, posix_spawn_file_actions_addclose "
1163 "(action={1}, fd={2})",
1164 error, file_actions, info->GetFD());
1165 }
1166 break;
1167
1169 if (info->GetFD() == -1)
1171 "invalid fd for posix_spawn_file_actions_adddup2(...)");
1172 else if (info->GetActionArgument() == -1)
1174 "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
1175 else if (info->GetFD() != info->GetActionArgument()) {
1176 error =
1177 Status(::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),
1178 info->GetActionArgument()),
1180 if (error.Fail())
1181 LLDB_LOG(log,
1182 "error: {0}, posix_spawn_file_actions_adddup2 "
1183 "(action={1}, fd={2}, dup_fd={3})",
1184 error, file_actions, info->GetFD(), info->GetActionArgument());
1185 } else {
1186 error =
1187 Status(::posix_spawn_file_actions_addinherit_np(file_actions, info->GetFD()),
1189 if (error.Fail())
1190 LLDB_LOG(log,
1191 "error: {0}, posix_spawn_file_actions_addinherit_np "
1192 "(action={1}, fd={2})",
1193 error, file_actions, info->GetFD());
1194 }
1195 break;
1196
1198 if (info->GetFD() == -1)
1200 "invalid fd in posix_spawn_file_actions_addopen(...)");
1201 else {
1202 int oflag = info->GetActionArgument();
1203
1204 mode_t mode = 0;
1205
1206 if (oflag & O_CREAT)
1207 mode = 0640;
1208
1209 const std::string file_path(info->GetFileSpec().GetPath());
1210 error = Status(
1211 ::posix_spawn_file_actions_addopen(file_actions, info->GetFD(),
1212 file_path.c_str(), oflag, mode),
1214 if (error.Fail())
1215 LLDB_LOG(log,
1216 "error: {0}, posix_spawn_file_actions_addopen (action={1}, "
1217 "fd={2}, path='{3}', oflag={4}, mode={5})",
1218 error, file_actions, info->GetFD(), file_path, oflag, mode);
1219 }
1220 break;
1221 }
1222 return error.Success();
1223}
1224
1225static Status LaunchProcessPosixSpawn(const char *exe_path,
1226 const ProcessLaunchInfo &launch_info,
1227 lldb::pid_t &pid) {
1228 Status error;
1230
1231 posix_spawnattr_t attr;
1232 error = Status(::posix_spawnattr_init(&attr), eErrorTypePOSIX);
1233
1234 if (error.Fail()) {
1235 LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error);
1236 return error;
1237 }
1238
1239 // Make sure we clean up the posix spawn attributes before exiting this scope.
1240 llvm::scope_exit cleanup_attr([&]() { posix_spawnattr_destroy(&attr); });
1241
1242 sigset_t no_signals;
1243 sigset_t all_signals;
1244 sigemptyset(&no_signals);
1245 sigfillset(&all_signals);
1246 ::posix_spawnattr_setsigmask(&attr, &no_signals);
1247 ::posix_spawnattr_setsigdefault(&attr, &all_signals);
1248
1249 short flags = GetPosixspawnFlags(launch_info);
1250
1251 error = Status(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);
1252 if (error.Fail()) {
1253 LLDB_LOG(log,
1254 "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",
1255 error, flags);
1256 return error;
1257 }
1258
1259 bool is_graphical = true;
1260
1261#if TARGET_OS_OSX
1262 SecuritySessionId session_id;
1263 SessionAttributeBits session_attributes;
1264 OSStatus status =
1265 SessionGetInfo(callerSecuritySession, &session_id, &session_attributes);
1266 if (status == errSessionSuccess)
1267 is_graphical = session_attributes & sessionHasGraphicAccess;
1268#endif
1269
1270 // When lldb is ran through a graphical session, make the debuggee process
1271 // responsible for its own TCC permissions instead of inheriting them from
1272 // its parent.
1273 if (is_graphical && launch_info.GetFlags().Test(eLaunchFlagDebug) &&
1274 !launch_info.GetFlags().Test(eLaunchFlagInheritTCCFromParent)) {
1276 if (error.Fail()) {
1277 LLDB_LOG(log, "error: {0}, setup_posix_spawn_responsible_flag(&attr)",
1278 error);
1279 return error;
1280 }
1281 }
1282
1283 if (launch_info.GetFlags().Test(eLaunchFlagMemoryTagging)) {
1284 // The following function configures the spawn attributes to launch the
1285 // process with memory tagging explicitly enabled. We look it up
1286 // dynamically since it is only available on newer OS. Does nothing on
1287 // hardware which does not support MTE.
1288 //
1289 // int posix_spawnattr_set_use_sec_transition_shims_np(
1290 // posix_spawnattr_t *attr, uint32_t flags);
1291 //
1292 using posix_spawnattr_set_use_sec_transition_shims_np_t =
1293 int (*)(posix_spawnattr_t *attr, uint32_t flags);
1294 auto posix_spawnattr_enable_memory_tagging_fn =
1295 (posix_spawnattr_set_use_sec_transition_shims_np_t)dlsym(
1296 RTLD_DEFAULT, "posix_spawnattr_set_use_sec_transition_shims_np");
1297 if (posix_spawnattr_enable_memory_tagging_fn) {
1298 error = Status(posix_spawnattr_enable_memory_tagging_fn(&attr, 0),
1300 if (error.Fail()) {
1301 LLDB_LOG(log,
1302 "error: {}, "
1303 "posix_spawnattr_set_use_sec_transition_shims_np(&attr, 0)",
1304 error);
1305 return error;
1306 }
1307 } else {
1308 LLDB_LOG(log,
1309 "error: {}, posix_spawnattr_set_use_sec_transition_shims_np "
1310 "not available",
1311 error);
1312 }
1313 }
1314
1315 // Don't set the binpref if a shell was provided. After all, that's only
1316 // going to affect what version of the shell is launched, not what fork of
1317 // the binary is launched. We insert "arch --arch <ARCH> as part of the
1318 // shell invocation to do that job on OSX.
1319 if (launch_info.GetShell() == FileSpec()) {
1320 const ArchSpec &arch_spec = launch_info.GetArchitecture();
1321 cpu_type_t cpu_type = arch_spec.GetMachOCPUType();
1322 cpu_type_t cpu_subtype = arch_spec.GetMachOCPUSubType();
1323 const bool set_cpu_type =
1324 cpu_type != 0 && cpu_type != static_cast<cpu_type_t>(UINT32_MAX) &&
1325 cpu_type != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE);
1326 const bool set_cpu_subtype =
1327 cpu_subtype != 0 &&
1328 cpu_subtype != static_cast<cpu_subtype_t>(UINT32_MAX) &&
1329 cpu_subtype != CPU_SUBTYPE_X86_64_H;
1330 if (set_cpu_type) {
1331 size_t ocount = 0;
1332 typedef int (*posix_spawnattr_setarchpref_np_t)(
1333 posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *);
1334 posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn =
1335 (posix_spawnattr_setarchpref_np_t)dlsym(
1336 RTLD_DEFAULT, "posix_spawnattr_setarchpref_np");
1337 if (set_cpu_subtype && posix_spawnattr_setarchpref_np_fn) {
1338 error = Status((*posix_spawnattr_setarchpref_np_fn)(
1339 &attr, 1, &cpu_type, &cpu_subtype, &ocount),
1341 if (error.Fail())
1342 LLDB_LOG(log,
1343 "error: {}, ::posix_spawnattr_setarchpref_np ( &attr, 1, "
1344 "cpu_type = {:x}, cpu_subtype = {:x}, count => {} )",
1345 error, cpu_type, cpu_subtype, ocount);
1346
1347 if (error.Fail() || ocount != 1)
1348 return error;
1349 } else {
1350 error = Status(
1351 ::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount),
1353 if (error.Fail())
1354 LLDB_LOG(log,
1355 "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
1356 "cpu_type = {1:x}, count => {2} )",
1357 error, cpu_type, ocount);
1358 if (error.Fail() || ocount != 1)
1359 return error;
1360 }
1361 }
1362 }
1363
1364 const char *tmp_argv[2];
1365 char *const *argv = const_cast<char *const *>(
1366 launch_info.GetArguments().GetConstArgumentVector());
1367 Environment::Envp envp = launch_info.GetEnvironment().getEnvp();
1368 if (argv == NULL) {
1369 // posix_spawn gets very unhappy if it doesn't have at least the program
1370 // name in argv[0]. One of the side affects I have noticed is the
1371 // environment
1372 // variables don't make it into the child process if "argv == NULL"!!!
1373 tmp_argv[0] = exe_path;
1374 tmp_argv[1] = NULL;
1375 argv = const_cast<char *const *>(tmp_argv);
1376 }
1377
1378 FileSpec working_dir{launch_info.GetWorkingDirectory()};
1379 if (working_dir) {
1380 // Set the working directory on this thread only
1381 std::string working_dir_path = working_dir.GetPath();
1382 if (__pthread_chdir(working_dir_path.c_str()) < 0) {
1383 if (errno == ENOENT) {
1385 "No such file or directory: %s", working_dir_path.c_str());
1386 } else if (errno == ENOTDIR) {
1388 "Path doesn't name a directory: %s", working_dir_path.c_str());
1389 } else {
1390 error =
1391 Status::FromErrorStringWithFormat("An unknown error occurred when "
1392 "changing directory for process "
1393 "execution.");
1394 }
1395 return error;
1396 }
1397 }
1398
1399 ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
1400 const size_t num_file_actions = launch_info.GetNumFileActions();
1401 if (num_file_actions > 0) {
1402 posix_spawn_file_actions_t file_actions;
1403 error =
1404 Status(::posix_spawn_file_actions_init(&file_actions), eErrorTypePOSIX);
1405 if (error.Fail()) {
1406 LLDB_LOG(log,
1407 "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",
1408 error);
1409 return error;
1410 }
1411
1412 // Make sure we clean up the posix file actions before exiting this scope.
1413 llvm::scope_exit cleanup_fileact(
1414 [&]() { posix_spawn_file_actions_destroy(&file_actions); });
1415
1416 for (size_t i = 0; i < num_file_actions; ++i) {
1417 const FileAction *launch_file_action =
1418 launch_info.GetFileActionAtIndex(i);
1419 if (launch_file_action) {
1420 if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,
1421 error))
1422 return error;
1423 }
1424 }
1425
1426 error = Status(
1427 ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
1429
1430 if (error.Fail()) {
1431 LLDB_LOG(log,
1432 "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
1433 "file_actions = {3}, "
1434 "attr = {4}, argv = {5}, envp = {6} )",
1435 error, result_pid, exe_path, &file_actions, &attr, argv,
1436 envp.get());
1437 if (log) {
1438 for (int ii = 0; argv[ii]; ++ii)
1439 LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
1440 }
1441 }
1442
1443 } else {
1444 error =
1445 Status(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
1447
1448 if (error.Fail()) {
1449 LLDB_LOG(log,
1450 "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
1451 "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
1452 error, result_pid, exe_path, &attr, argv, envp.get());
1453 if (log) {
1454 for (int ii = 0; argv[ii]; ++ii)
1455 LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
1456 }
1457 }
1458 }
1459 pid = result_pid;
1460
1461 if (working_dir) {
1462 // No more thread specific current working directory
1463 __pthread_fchdir(-1);
1464 }
1465
1466 return error;
1467}
1468
1469static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) {
1470 bool result = false;
1471
1472#if TARGET_OS_OSX
1473 bool launchingAsRoot = launch_info.GetUserID() == 0;
1474 bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
1475
1476 if (launchingAsRoot && !currentUserIsRoot) {
1477 // If current user is already root, we don't need XPC's help.
1478 result = true;
1479 }
1480#endif
1481
1482 return result;
1483}
1484
1486 Status error;
1487
1488 FileSystem &fs = FileSystem::Instance();
1489 FileSpec exe_spec(launch_info.GetExecutableFile());
1490
1491 if (!fs.Exists(exe_spec))
1492 FileSystem::Instance().Resolve(exe_spec);
1493
1494 if (!fs.Exists(exe_spec))
1496
1497 if (!fs.Exists(exe_spec)) {
1499 "executable doesn't exist: '{0}'", exe_spec);
1500 return error;
1501 }
1502
1503 if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) {
1504#if TARGET_OS_OSX
1505 return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(),
1506 launch_info);
1507#else
1508 error =
1509 Status::FromErrorString("launching a process in a new terminal is not "
1510 "supported on iOS devices");
1511 return error;
1512#endif
1513 }
1514
1516
1517 auto exe_path = exe_spec.GetPath();
1518
1519 if (ShouldLaunchUsingXPC(launch_info))
1520 error = LaunchProcessXPC(exe_path.c_str(), launch_info, pid);
1521 else
1522 error = LaunchProcessPosixSpawn(exe_path.c_str(), launch_info, pid);
1523
1524 if (pid != LLDB_INVALID_PROCESS_ID) {
1525 // If all went well, then set the process ID into the launch info
1526 launch_info.SetProcessID(pid);
1527
1528 // Make sure we reap any processes we spawn or we will have zombies.
1529 bool monitoring = launch_info.MonitorProcess();
1530 UNUSED_IF_ASSERT_DISABLED(monitoring);
1531 assert(monitoring);
1532 } else {
1533 // Invalid process ID, something didn't go well
1534 if (error.Success())
1535 error =
1536 Status::FromErrorString("process launch failed for unknown reasons");
1537 }
1538 return error;
1539}
1540
1542 Status error;
1543 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {
1544 FileSpec expand_tool_spec;
1545 Environment host_env = Host::GetEnvironment();
1546 std::string env_argdumper_path = host_env.lookup("LLDB_ARGDUMPER_PATH");
1547 if (!env_argdumper_path.empty()) {
1548 expand_tool_spec.SetFile(env_argdumper_path, FileSpec::Style::native);
1550 LLDB_LOGF(log,
1551 "lldb-argdumper exe path set from environment variable: %s",
1552 env_argdumper_path.c_str());
1553 }
1554 bool argdumper_exists = FileSystem::Instance().Exists(env_argdumper_path);
1555 if (!argdumper_exists) {
1556 expand_tool_spec = HostInfo::GetSupportExeDir();
1557 if (!expand_tool_spec) {
1559 "could not get support executable directory for "
1560 "lldb-argdumper tool");
1561 return error;
1562 }
1563 expand_tool_spec.AppendPathComponent("lldb-argdumper");
1564 if (!FileSystem::Instance().Exists(expand_tool_spec)) {
1566 "could not find the lldb-argdumper tool: %s",
1567 expand_tool_spec.GetPath().c_str());
1568 return error;
1569 }
1570 }
1571
1572 StreamString expand_tool_spec_stream;
1573 expand_tool_spec_stream.Printf("\"%s\"",
1574 expand_tool_spec.GetPath().c_str());
1575
1576 Args expand_command(expand_tool_spec_stream.GetData());
1577 expand_command.AppendArguments(launch_info.GetArguments());
1578
1579 int status;
1580 std::string output;
1581 FileSpec cwd(launch_info.GetWorkingDirectory());
1582 if (!FileSystem::Instance().Exists(cwd)) {
1583 char *wd = getcwd(nullptr, 0);
1584 if (wd == nullptr) {
1586 "cwd does not exist: Cannot launch with shell argument expansion");
1587 return error;
1588 } else {
1589 FileSpec working_dir(wd);
1590 free(wd);
1591 launch_info.SetWorkingDirectory(working_dir);
1592 }
1593 }
1594 bool run_in_shell = true;
1595 std::string error_output; // Pass stderr string arg so it is not mixed with
1596 // stdout.
1597 Status e =
1598 RunShellCommand(expand_command, cwd, &status, nullptr, &output,
1599 &error_output, std::chrono::seconds(10), run_in_shell);
1600
1601 if (e.Fail())
1602 return e;
1603
1604 if (status != 0) {
1606 "lldb-argdumper exited with error %d", status);
1607 return error;
1608 }
1609
1610 auto data_sp = StructuredData::ParseJSON(output);
1611 if (!data_sp) {
1612 error = Status::FromErrorString("invalid JSON");
1613 return error;
1614 }
1615
1616 auto dict_sp = data_sp->GetAsDictionary();
1617 if (!data_sp) {
1618 error = Status::FromErrorString("invalid JSON");
1619 return error;
1620 }
1621
1622 auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
1623 if (!args_sp) {
1624 error = Status::FromErrorString("invalid JSON");
1625 return error;
1626 }
1627
1628 auto args_array_sp = args_sp->GetAsArray();
1629 if (!args_array_sp) {
1630 error = Status::FromErrorString("invalid JSON");
1631 return error;
1632 }
1633
1634 launch_info.GetArguments().Clear();
1635
1636 for (size_t i = 0; i < args_array_sp->GetSize(); i++) {
1637 auto item_sp = args_array_sp->GetItemAtIndex(i);
1638 if (!item_sp)
1639 continue;
1640 auto str_sp = item_sp->GetAsString();
1641 if (!str_sp)
1642 continue;
1643
1644 launch_info.GetArguments().AppendArgument(str_sp->GetValue());
1645 }
1646 }
1647
1648 return error;
1649}
1650
1651llvm::Expected<HostThread> Host::StartMonitoringChildProcess(
1652 const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) {
1653 unsigned long mask = DISPATCH_PROC_EXIT;
1654
1656
1657 dispatch_source_t source = ::dispatch_source_create(
1658 DISPATCH_SOURCE_TYPE_PROC, pid, mask,
1659 ::dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1660
1661 LLDB_LOGF(log,
1662 "Host::StartMonitoringChildProcess(callback, pid=%i) source = %p\n",
1663 static_cast<int>(pid), static_cast<void *>(source));
1664
1665 if (source) {
1666 Host::MonitorChildProcessCallback callback_copy = callback;
1667 ::dispatch_source_set_cancel_handler(source, ^{
1668 dispatch_release(source);
1669 });
1670 ::dispatch_source_set_event_handler(source, ^{
1671
1672 int status = 0;
1673 int wait_pid = 0;
1674 wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, 0);
1675 if (wait_pid >= 0) {
1676 int signal = 0;
1677 int exit_status = 0;
1678 const char *status_cstr = NULL;
1679 if (WIFEXITED(status)) {
1680 exit_status = WEXITSTATUS(status);
1681 status_cstr = "EXITED";
1682 } else if (WIFSIGNALED(status)) {
1683 signal = WTERMSIG(status);
1684 status_cstr = "SIGNALED";
1685 exit_status = -1;
1686 } else {
1687 llvm_unreachable("Unknown status");
1688 }
1689
1690 LLDB_LOGF(log,
1691 "::waitpid (pid = %llu, &status, 0) => pid = %i, status "
1692 "= 0x%8.8x (%s), signal = %i, exit_status = %i",
1693 pid, wait_pid, status, status_cstr, signal, exit_status);
1694
1695 if (callback_copy)
1696 callback_copy(pid, signal, exit_status);
1697
1698 ::dispatch_source_cancel(source);
1699 }
1700 });
1701
1702 ::dispatch_resume(source);
1703 }
1704 return HostThread();
1705}
static llvm::raw_ostream & error(Stream &strm)
#define CPU_SUBTYPE_X86_64_H
#define CPU_TYPE_ARM64
#define CPU_TYPE_ARM64_32
static llvm::Error GetProcessList(std::vector< struct kinfo_proc > &kinfos)
Fetches the list of all processes into kinfos.
Definition Host.mm:692
static Status LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
Definition Host.mm:1225
static os_log_t g_os_log
Definition Host.mm:106
static Status LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
Definition Host.mm:993
static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info)
Definition Host.mm:951
#define _POSIX_SPAWN_DISABLE_ASLR
Definition Host.mm:95
int __pthread_chdir(const char *path)
static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info)
Definition Host.mm:658
static std::once_flag g_os_log_once
Definition Host.mm:107
static bool GetMacOSXProcessCPUType(ProcessInstanceInfo &process_info)
Definition Host.mm:503
static void finalize_xpc(void *xpc_object)
Definition Host.mm:989
int __pthread_fchdir(int fildes)
static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info)
Definition Host.mm:1469
static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Status &error)
Definition Host.mm:1139
static bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr, ProcessInstanceInfo &process_info)
Definition Host.mm:576
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:364
#define LLDB_LOGF(log,...)
Definition Log.h:378
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:394
static int setup_posix_spawn_responsible_flag(posix_spawnattr_t *attr)
int cpu_subtype_t
int cpu_type_t
An architecture specification class.
Definition ArchSpec.h:32
bool IsValid() const
Tests if this ArchSpec is valid.
Definition ArchSpec.h:370
void Clear()
Clears the object state.
Definition ArchSpec.cpp:547
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:460
bool SetArchitecture(ArchitectureType arch_type, uint32_t cpu, uint32_t sub, uint32_t os=0)
Change the architecture object type, CPU type and OS type.
Definition ArchSpec.cpp:852
uint32_t GetMachOCPUSubType() const
Definition ArchSpec.cpp:670
uint32_t GetMachOCPUType() const
Definition ArchSpec.cpp:658
Core GetCore() const
Definition ArchSpec.h:451
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition ArchSpec.cpp:557
A command line argument class.
Definition Args.h:33
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition Args.h:120
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
Definition Args.cpp:332
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
Definition Args.cpp:273
const char ** GetConstArgumentVector() const
Gets the argument vector.
Definition Args.cpp:289
void Clear()
Clear the arguments.
Definition Args.cpp:388
lldb::ConnectionStatus Connect(llvm::StringRef url, Status *error_ptr) override
Connect using the connect string url.
size_t Read(void *dst, size_t dst_len, const Timeout< std::micro > &timeout, lldb::ConnectionStatus &status, Status *error_ptr) override
The read function that attempts to read from the connection.
const char * GetCString() const
Get the string value as a C string.
A subclass of DataBuffer that stores a data buffer on the heap.
lldb::offset_t GetByteSize() const override
Get the number of bytes in the data buffer.
An data extractor class.
const char * GetCStr(lldb::offset_t *offset_ptr) const
Extract a C string from *offset_ptr.
virtual const uint8_t * PeekData(lldb::offset_t offset, lldb::offset_t length) const
Peek at a bytes at offset.
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
char *const * get() const
Definition Environment.h:27
static std::string compose(const value_type &KeyValue)
Definition Environment.h:80
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
Definition Environment.h:71
Represents a file descriptor action to be performed during process launch.
Definition FileAction.h:21
Action GetAction() const
Get the type of action.
Definition FileAction.h:59
int GetActionArgument() const
Get the action-specific argument.
Definition FileAction.h:65
const FileSpec & GetFileSpec() const
Get the file specification for open actions.
int GetFD() const
Get the file descriptor this action applies to.
Definition FileAction.h:56
A file utility class.
Definition FileSpec.h:57
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition FileSpec.cpp:174
void AppendPathComponent(llvm::StringRef component)
Definition FileSpec.cpp:450
const ConstString & GetFilename() const
Filename string const get accessor.
Definition FileSpec.h:250
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:374
void Clear()
Clears the object state.
Definition FileSpec.cpp:259
void SetFilename(ConstString filename)
Filename string set accessor.
Definition FileSpec.cpp:352
bool ResolveExecutableLocation(FileSpec &file_spec)
Call into the Host to see if it can help find the file.
bool Exists(const FileSpec &file_spec) const
Returns whether the given file exists.
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
bool Test(ValueType bit) const
Test a single flag bit.
Definition Flags.h:96
static Status LaunchProcess(ProcessLaunchInfo &launch_info)
Launch the process specified in launch_info.
static bool ResolveExecutableInBundle(FileSpec &file)
When executable files may live within a directory, where the directory represents an executable bundl...
static void SystemLog(lldb::Severity severity, llvm::StringRef message)
Emit the given message to the operating system log.
static llvm::Error OpenURL(llvm::StringRef url)
Definition Host.mm:459
static Status ShellExpandArguments(ProcessLaunchInfo &launch_info)
Perform expansion of the command-line for this launch info This can potentially involve wildcard expa...
Definition aix/Host.cpp:216
static Environment GetEnvironment()
static Status RunShellCommand(llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output, std::string *error_output, const Timeout< std::micro > &timeout, bool run_in_shell=true)
Run a shell command.
static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &proc_infos)
Definition aix/Host.cpp:169
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
Definition aix/Host.cpp:211
std::function< void(lldb::pid_t pid, int signal, int status)> MonitorChildProcessCallback
Definition Host.h:88
static llvm::Expected< HostThread > StartMonitoringChildProcess(const MonitorChildProcessCallback &callback, lldb::pid_t pid)
Start monitoring a child process.
static bool IsInteractiveGraphicSession()
Check if we're running in an interactive graphical session.
static bool GetBundleDirectory(const FileSpec &file, FileSpec &bundle_directory)
If you have an executable that is in a bundle and want to get back to the bundle directory from the p...
static llvm::Error OpenFileInExternalEditor(llvm::StringRef editor, const FileSpec &file_spec, uint32_t line_no)
void SetGroupID(uint32_t gid)
Definition ProcessInfo.h:58
bool ProcessIDIsValid() const
Definition ProcessInfo.h:70
void SetArg0(llvm::StringRef arg)
lldb::pid_t GetProcessID() const
Definition ProcessInfo.h:66
void SetProcessID(lldb::pid_t pid)
Definition ProcessInfo.h:68
FileSpec & GetExecutableFile()
Definition ProcessInfo.h:41
llvm::StringRef GetName() const
uint32_t GetUserID() const
Definition ProcessInfo.h:48
Environment & GetEnvironment()
Definition ProcessInfo.h:86
void SetUserID(uint32_t uid)
Definition ProcessInfo.h:56
ArchSpec & GetArchitecture()
Definition ProcessInfo.h:60
bool Matches(const ProcessInstanceInfo &proc_info) const
ProcessInstanceInfo & GetProcessInfo()
bool ProcessIDsMatch(const ProcessInstanceInfo &proc_info) const
Return true iff the process ID and parent process IDs in this object match the ones in proc_info.
bool UserIDsMatch(const ProcessInstanceInfo &proc_info) const
Return true iff the (both effective and real) user and group IDs in this object match the ones in pro...
void SetEffectiveGroupID(uint32_t gid)
void SetParentProcessID(lldb::pid_t pid)
void SetEffectiveUserID(uint32_t uid)
const FileSpec & GetShell() const
const FileAction * GetFileActionAtIndex(size_t idx) const
const FileAction * GetFileActionForFD(int fd) const
void SetWorkingDirectory(const FileSpec &working_dir)
const FileSpec & GetWorkingDirectory() const
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static Status FromErrorString(const char *str)
Definition Status.h:141
bool Fail() const
Test for error condition.
Definition Status.cpp:293
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
bool Success() const
Test for success condition.
Definition Status.cpp:303
const char * GetData() const
llvm::StringRef GetString() const
void Format(const char *format, Args &&... args)
Forwards the arguments to llvm::formatv and writes to the stream.
Definition Stream.h:370
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
static ObjectSP ParseJSON(llvm::StringRef json_text)
static llvm::Expected< HostThread > LaunchThread(llvm::StringRef name, std::function< lldb::thread_result_t()> thread_function, size_t min_stack_byte_size=0)
uint8_t * GetBytes()
Get a pointer to the data.
Definition DataBuffer.h:108
#define LLDB_INVALID_CPUTYPE
#define UNUSED_IF_ASSERT_DISABLED(x)
#define UINT32_MAX
#define LLDB_INVALID_PROCESS_ID
lldb::ByteOrder InlHostByteOrder()
Definition Endian.h:25
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:327
bool NameMatches(llvm::StringRef name, NameMatch match_type, llvm::StringRef match)
std::vector< ProcessInstanceInfo > ProcessInstanceInfoList
Definition Host.h:32
Severity
Used for expressing severity in logs and diagnostics.
void * thread_result_t
Definition lldb-types.h:62
ConnectionStatus
Connection Status Types.
@ eConnectionStatusSuccess
Success.
uint64_t offset_t
Definition lldb-types.h:85
@ eErrorTypeGeneric
Generic errors that can be any value.
@ eErrorTypePOSIX
POSIX error codes.
uint64_t pid_t
Definition lldb-types.h:83
#define PATH_MAX