12#include <AvailabilityMacros.h>
13#include <TargetConditionals.h>
16#define __XPC_PRIVATE_H__
19#define LaunchUsingXPCRightName "com.apple.lldb.RootDebuggingXPCService"
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"
36#include <bsm/audit_session.h>
39#include "llvm/TargetParser/Host.h"
44#include <crt_externs.h>
54#include <sys/sysctl.h>
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"
88#include <objc/objc-auto.h>
91#include <CoreFoundation/CoreFoundation.h>
92#include <Foundation/Foundation.h>
94#ifndef _POSIX_SPAWN_DISABLE_ASLR
95#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
110 if (__builtin_available(macos 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
112 g_os_log = os_log_create(
"com.apple.dt.lldb",
"lldb");
117 os_log(
g_os_log,
"%{public}s", message.str().c_str());
120 os_log_error(
g_os_log,
"%{public}s", message.str().c_str());
124 llvm::errs() << message;
130#if defined(__APPLE__)
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);
142 bundle_directory.
Clear();
147#if defined(__APPLE__)
150 if (file.
GetPath(path,
sizeof(path))) {
151 CFCBundle bundle(path);
152 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL());
154 if (::CFURLGetFileSystemRepresentation(url.get(), YES, (UInt8 *)path,
156 file.
SetFile(path, FileSpec::Style::native);
168static void *AcceptPIDFromInferior(
const char *connect_url) {
173 ::memset(pid_str, 0,
sizeof(pid_str));
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;
185const char *applscript_in_new_tty =
"tell application \"Terminal\"\n"
187 " do script \"/bin/bash -c '%s';exit\"\n"
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\
206 do script the_shell_script\n\
210LaunchInNewTerminalWithAppleScript(
const char *exe_path,
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");
221 FileSpec darwin_debug_file_spec = HostInfo::GetSupportExeDir();
222 if (!darwin_debug_file_spec) {
228 darwin_debug_file_spec.
SetFilename(
"darwin-debug");
232 "the 'darwin-debug' executable doesn't exists at '%s'",
233 darwin_debug_file_spec.
GetPath().c_str());
238 darwin_debug_file_spec.
GetPath(launcher_path,
sizeof(launcher_path));
246 command.
Printf(R
"(\"%s\" --unix-socket=%s)", launcher_path, unix_socket_name);
253 command.
Printf(R
"( --working-dir \"%s\")", working_dir.GetPath().c_str());
257 command.
Printf(R
"( --working-dir \"%s\")", cwd);
260 if (launch_info.
GetFlags().
Test(eLaunchFlagDisableASLR))
271 auto host_entry = host_env.find(KV.first());
272 if (host_entry == host_env.end() || host_entry->second != KV.second)
280 for (
size_t i = 0; argv[i] != NULL; ++i) {
282 command.
Printf(R
"( \"%s\")", exe_path);
284 command.
Printf(R
"( \"%s\")", argv[i]);
287 command.
Printf(R
"( \"%s\")", exe_path);
289 command.PutCString(" ; echo Process exited with status $?");
290 if (launch_info.
GetFlags().
Test(lldb::eLaunchFlagCloseTTYOnExit))
295 applescript_source.
Printf(applscript_in_new_tty,
298 NSAppleScript *applescript = [[NSAppleScript alloc]
299 initWithSource:[NSString stringWithCString:applescript_source.
GetString()
302 encoding:NSUTF8StringEncoding]];
309 char connect_url[128];
310 ::snprintf(connect_url,
sizeof(connect_url),
"unix-accept://%s",
320 unix_socket_name, [&] {
return AcceptPIDFromInferior(connect_url); });
325 [applescript executeAndReturnError:nil];
328 lldb_error = accept_thread->Join(&accept_thread_result);
329 if (lldb_error.
Success() && accept_thread_result) {
330 pid = (intptr_t)accept_thread_result;
333 llvm::sys::fs::remove(unix_socket_name);
334 [applescript release];
346 return llvm::errorCodeToError(
347 std::error_code(ENOTSUP, std::system_category()));
351 const std::string file_path = file_spec.
GetPath();
353 LLDB_LOG(log,
"Sending {0}:{1} to external editor",
354 file_path.empty() ?
"<invalid>" : file_path, line_no);
356 if (file_path.empty())
357 return llvm::createStringError(llvm::inconvertibleErrorCode(),
358 "no file specified");
360 CFCString file_cfstr(file_path.c_str(), kCFStringEncodingUTF8);
361 CFCReleaser<CFURLRef> file_URL = ::CFURLCreateWithFileSystemPath(
364 kCFURLPOSIXPathStyle,
368 return llvm::createStringError(
369 llvm::inconvertibleErrorCode(),
370 llvm::formatv(
"could not create CFURL from path \"{0}\"", file_path));
383 BabelAESelInfo file_and_line_info = {
385 (int16_t)(line_no - 1),
392 AEKeyDesc file_and_line_desc;
393 file_and_line_desc.descKey = keyAEPosition;
394 long error = ::AECreateDesc(typeUTF8Text,
396 sizeof(file_and_line_info),
397 &(file_and_line_desc.descContent));
400 return llvm::createStringError(
401 llvm::inconvertibleErrorCode(),
402 llvm::formatv(
"creating Apple Event descriptor failed: error {0}",
406 llvm::scope_exit on_exit(
407 [&]() { AEDisposeDesc(&(file_and_line_desc.descContent)); });
409 if (editor.empty()) {
410 if (
const char *lldb_external_editor = ::getenv(
"LLDB_EXTERNAL_EDITOR"))
411 editor = lldb_external_editor;
414 std::optional<FSRef> app_fsref;
415 if (!editor.empty()) {
416 LLDB_LOG(log,
"Looking for external editor: {0}", editor);
419 CFCString editor_name(editor.data(), kCFStringEncodingUTF8);
420 long app_error = ::LSFindApplicationForInfo(
421 kLSUnknownCreator, NULL,
422 editor_name.get(), &(*app_fsref),
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}",
433 LSApplicationParameters app_params;
434 ::memset(&app_params, 0,
sizeof(app_params));
436 kLSLaunchDefaults | kLSLaunchDontAddToRecents | kLSLaunchDontSwitch;
438 app_params.application = &(*app_fsref);
440 ProcessSerialNumber psn;
441 std::array<CFURLRef, 1> file_array = {file_URL.
get()};
442 CFCReleaser<CFArrayRef> cf_array(
443 CFArrayCreate(NULL, (
const void **)&file_array,
445 error = ::LSOpenURLsWithRole(
446 cf_array.get(), kLSRolesEditor,
448 &app_params, &psn, 1);
451 return llvm::createStringError(
452 llvm::inconvertibleErrorCode(),
453 llvm::formatv(
"LSOpenURLsWithRole failed: error {0}",
error));
455 return llvm::Error::success();
461 return llvm::errorCodeToError(
462 std::error_code(ENOTSUP, std::system_category()));
465 return llvm::createStringError(
"cannot open empty URL");
469 CFCString url_cfstr(url.data(), kCFStringEncodingUTF8);
470 CFCReleaser<CFURLRef> cfurl = ::CFURLCreateWithString(
476 return llvm::createStringError(
477 llvm::formatv(
"could not create CFURL from URL \"{0}\"", url));
479 OSStatus
error = ::LSOpenCFURLRef(
484 return llvm::createStringError(
485 llvm::formatv(
"LSOpenCFURLRef failed: error {0:x}",
error));
487 return llvm::Error::success();
495 auditinfo_addr_t info;
496 getaudit_addr(&info,
sizeof(info));
497 return info.ai_flags & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS;
506 int mib[CTL_MAXNAME] = {
509 size_t mib_len = CTL_MAXNAME;
510 if (::sysctlnametomib(
"sysctl.proc_cputype", mib, &mib_len))
517 size_t len =
sizeof(cpu);
518 if (::sysctl(mib, mib_len, &cpu, &len, 0, 0) == 0) {
521 sub = CPU_SUBTYPE_I386_ALL;
523 case CPU_TYPE_X86_64:
524 sub = CPU_SUBTYPE_X86_64_ALL;
527#if defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64_ALL)
529 sub = CPU_SUBTYPE_ARM64_ALL;
533#if defined(CPU_TYPE_ARM64_32) && defined(CPU_SUBTYPE_ARM64_32_ALL)
535 sub = CPU_SUBTYPE_ARM64_32_ALL;
543 uint32_t cpusubtype = 0;
544 len =
sizeof(cpusubtype);
545 if (::sysctlbyname(
"hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
548 bool host_cpu_is_64bit;
549 uint32_t is64bit_capable;
550 size_t is64bit_capable_len =
sizeof(is64bit_capable);
552 sysctlbyname(
"hw.cpu64bit_capable", &is64bit_capable,
553 &is64bit_capable_len, NULL, 0) == 0;
560 if (host_cpu_is_64bit) {
561 sub = CPU_SUBTYPE_ARM_V7;
579 int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2,
582 size_t arg_data_size = 0;
583 if (::sysctl(proc_args_mib, 3,
nullptr, &arg_data_size, NULL, 0) ||
585 arg_data_size = 8192;
592 if (::sysctl(proc_args_mib, 3, arg_data.
GetBytes(), &arg_data_size, NULL,
597 uint32_t argc = data.
GetU32(&offset);
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);
605 const char *cstr = data.
GetCStr(&offset);
609 if (match_info_ptr == NULL ||
615 const uint8_t *p = data.
PeekData(offset, 1);
616 if ((p == NULL) || (*p !=
'\0'))
627 for (
int i = 1; i < static_cast<int>(argc); ++i) {
634 bool is_simulator =
false;
635 llvm::StringRef env_var;
636 while (!(env_var = data.
GetCStr(&offset)).empty()) {
637 if (check_for_ios_simulator &&
638 env_var.starts_with(
"SIMULATOR_UDID="))
644 triple.setOS(llvm::Triple::IOS);
645 triple.setEnvironment(llvm::Triple::Simulator);
647 triple.setOS(llvm::Triple::MacOSX);
662 mib[2] = KERN_PROC_PID;
664 struct kinfo_proc proc_kinfo;
665 size_t proc_kinfo_size =
sizeof(
struct kinfo_proc);
667 if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
668 if (proc_kinfo_size > 0) {
670 process_info.
SetUserID(proc_kinfo.kp_eproc.e_pcred.p_ruid);
671 process_info.
SetGroupID(proc_kinfo.kp_eproc.e_pcred.p_rgid);
673 if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
675 proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
692 int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
695 static constexpr unsigned g_retry_count = 200;
698 static constexpr unsigned g_expected_new_pids = 500;
705 g_retry_count * g_expected_new_pids <= 100'000,
706 "Final retry attempt assumes an unlikely amount of new processes.");
712 for (
unsigned attempt = 1; attempt < g_retry_count; ++attempt) {
714 size_t current_pid_size = 0;
715 if (::sysctl(mib, 3,
nullptr, ¤t_pid_size,
nullptr, 0) != 0)
716 return llvm::errorCodeToError(
717 std::error_code(errno, std::generic_category()));
720 const size_t current_num_processes =
721 current_pid_size /
sizeof(
struct kinfo_proc);
727 const size_t expected_growth = attempt * g_expected_new_pids;
730 kinfos.resize(current_num_processes + expected_growth);
733 size_t actual_pid_size = kinfos.size() *
sizeof(
struct kinfo_proc);
734 if (::sysctl(mib, 3, &kinfos[0], &actual_pid_size,
nullptr, 0) == 0) {
736 kinfos.resize(actual_pid_size /
sizeof(
struct kinfo_proc));
737 return llvm::Error::success();
743 return llvm::errorCodeToError(
744 std::error_code(errno, std::generic_category()));
750 assert(errno == ENOMEM &&
751 "loop should only be left via the ENOMEM retry path");
752 return llvm::createStringErrorV(
753 "Failed to read process list: sysctl kept returning ENOMEM after {0} "
760 std::vector<struct kinfo_proc> kinfos;
763 "failed to read process list: {0}");
769 const uid_t our_uid = getuid();
770 for (
const struct kinfo_proc &kinfo : kinfos) {
771 bool kinfo_user_matches =
false;
773 kinfo_user_matches =
true;
775 kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
779 kinfo_user_matches =
true;
781 if (!kinfo_user_matches ||
784 kinfo.kp_proc.p_pid == 0 ||
785 kinfo.kp_proc.p_stat == SZOMB ||
786 kinfo.kp_proc.p_flag & P_TRACED ||
787 kinfo.kp_proc.p_flag & P_WEXIT)
790 ProcessInstanceInfo process_info;
793 process_info.
SetUserID(kinfo.kp_eproc.e_pcred.p_ruid);
794 process_info.
SetGroupID(kinfo.kp_eproc.e_pcred.p_rgid);
796 if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
810 if (match_info.
Matches(process_info))
811 process_infos.push_back(process_info);
815 return process_infos.size();
820 bool success =
false;
836 process_info.
Clear();
841static void PackageXPCArguments(xpc_object_t message,
const char *prefix,
845 memset(buf, 0,
sizeof(buf));
846 snprintf(buf,
sizeof(buf),
"%sCount", prefix);
847 xpc_dictionary_set_int64(message, buf, count);
848 for (
size_t i = 0; i < count; i++) {
849 memset(buf, 0,
sizeof(buf));
850 snprintf(buf,
sizeof(buf),
"%s%zi", prefix, i);
855static void PackageXPCEnvironment(xpc_object_t message, llvm::StringRef prefix,
857 xpc_dictionary_set_int64(message, (prefix +
"Count").str().c_str(),
860 for (
const auto &KV : env) {
861 xpc_dictionary_set_string(message, (prefix + llvm::Twine(i)).str().c_str(),
872static AuthorizationRef authorizationRef = NULL;
877 if ((launch_info.
GetUserID() == 0) && !authorizationRef) {
878 OSStatus createStatus =
879 AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
880 kAuthorizationFlagDefaults, &authorizationRef);
881 if (createStatus != errAuthorizationSuccess) {
888 OSStatus rightsStatus =
889 AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
890 if (rightsStatus != errAuthorizationSuccess) {
893 CFSTR(
"Xcode is trying to take control of a root process.");
894 CFStringRef keys[] = {CFSTR(
"en")};
895 CFTypeRef values[] = {prompt};
896 CFDictionaryRef promptDict = CFDictionaryCreate(
897 kCFAllocatorDefault, (
const void **)keys, (
const void **)values, 1,
898 &kCFCopyStringDictionaryKeyCallBacks,
899 &kCFTypeDictionaryValueCallBacks);
901 CFStringRef keys1[] = {CFSTR(
"class"), CFSTR(
"group"), CFSTR(
"comment"),
902 CFSTR(
"default-prompt"), CFSTR(
"shared")};
903 CFTypeRef values1[] = {CFSTR(
"user"), CFSTR(
"admin"),
904 CFSTR(LaunchUsingXPCRightName), promptDict,
906 CFDictionaryRef dict = CFDictionaryCreate(
907 kCFAllocatorDefault, (
const void **)keys1, (
const void **)values1, 5,
908 &kCFCopyStringDictionaryKeyCallBacks,
909 &kCFTypeDictionaryValueCallBacks);
910 rightsStatus = AuthorizationRightSet(
911 authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
912 CFRelease(promptDict);
916 OSStatus copyRightStatus = errAuthorizationDenied;
917 if (rightsStatus == errAuthorizationSuccess) {
918 AuthorizationItem item1 = {LaunchUsingXPCRightName, 0, NULL, 0};
919 AuthorizationItem items[] = {item1};
920 AuthorizationRights requestedRights = {1, items};
921 AuthorizationFlags authorizationFlags =
922 kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
923 copyRightStatus = AuthorizationCopyRights(
924 authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment,
925 authorizationFlags, NULL);
928 if (copyRightStatus != errAuthorizationSuccess) {
936 "Launching as root needs root authorization.");
939 if (authorizationRef) {
940 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
941 authorizationRef = NULL;
951 short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
954 flags |= POSIX_SPAWN_SETEXEC;
957 flags |= POSIX_SPAWN_START_SUSPENDED;
959 if (launch_info.
GetFlags().
Test(eLaunchFlagDisableASLR))
963 flags |= POSIX_SPAWN_SETPGROUP;
965#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
966#if defined(__x86_64__) || defined(__i386__)
971 llvm::VersionTuple version = HostInfo::GetOSVersion();
972 if (version > llvm::VersionTuple(10, 7)) {
983 flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
989 xpc_release((xpc_object_t)xpc_object);
1002 uid_t requested_uid = launch_info.
GetUserID();
1003 const char *xpc_service = nil;
1004 bool send_auth =
false;
1005 AuthorizationExternalForm extForm;
1006 if (requested_uid == 0) {
1007 if (AuthorizationMakeExternalForm(authorizationRef, &extForm) ==
1008 errAuthorizationSuccess) {
1013 "Launching root via XPC needs to "
1014 "externalize authorization reference.");
1018 xpc_service = LaunchUsingXPCRightName;
1022 "Launching via XPC is only currently available for root.");
1027 xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
1029 xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
1030 xpc_type_t type = xpc_get_type(event);
1032 if (type == XPC_TYPE_ERROR) {
1033 if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
1040 }
else if (event == XPC_ERROR_CONNECTION_INVALID) {
1058 xpc_connection_resume(conn);
1059 xpc_object_t message = xpc_dictionary_create(nil, nil, 0);
1062 xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes,
1063 sizeof(AuthorizationExternalForm));
1066 PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey,
1068 PackageXPCEnvironment(message, LauncherXPCServiceEnvPrefxKey,
1072 xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey,
1074 xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey,
1077 std::string file_action_path;
1081 if (!file_action_path.empty())
1082 xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey,
1083 file_action_path.c_str());
1089 if (!file_action_path.empty())
1090 xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey,
1091 file_action_path.c_str());
1097 if (!file_action_path.empty())
1098 xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey,
1099 file_action_path.c_str());
1101 xpc_object_t reply =
1102 xpc_connection_send_message_with_reply_sync(conn, message);
1103 xpc_type_t returnType = xpc_get_type(reply);
1104 if (returnType == XPC_TYPE_DICTIONARY) {
1105 pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
1108 xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
1110 xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
1114 "Problems with launching via XPC. Error type : %i, code : %i",
1115 errorType, errorCode);
1118 if (authorizationRef) {
1119 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1120 authorizationRef = NULL;
1123 }
else if (returnType == XPC_TYPE_ERROR) {
1126 "Problems with launching via XPC. XPC error : %s",
1127 xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
1143 posix_spawn_file_actions_t *file_actions =
1144 static_cast<posix_spawn_file_actions_t *
>(_file_actions);
1152 if (info->
GetFD() == -1)
1154 "invalid fd for posix_spawn_file_actions_addclose(...)");
1157 ::posix_spawn_file_actions_addclose(file_actions, info->
GetFD()),
1161 "error: {0}, posix_spawn_file_actions_addclose "
1162 "(action={1}, fd={2})",
1168 if (info->
GetFD() == -1)
1170 "invalid fd for posix_spawn_file_actions_adddup2(...)");
1173 "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
1176 Status(::posix_spawn_file_actions_adddup2(file_actions, info->
GetFD(),
1181 "error: {0}, posix_spawn_file_actions_adddup2 "
1182 "(action={1}, fd={2}, dup_fd={3})",
1186 Status(::posix_spawn_file_actions_addinherit_np(file_actions, info->
GetFD()),
1190 "error: {0}, posix_spawn_file_actions_addinherit_np "
1191 "(action={1}, fd={2})",
1197 if (info->
GetFD() == -1)
1199 "invalid fd in posix_spawn_file_actions_addopen(...)");
1205 if (oflag & O_CREAT)
1210 ::posix_spawn_file_actions_addopen(file_actions, info->
GetFD(),
1211 file_path.c_str(), oflag, mode),
1215 "error: {0}, posix_spawn_file_actions_addopen (action={1}, "
1216 "fd={2}, path='{3}', oflag={4}, mode={5})",
1217 error, file_actions, info->
GetFD(), file_path, oflag, mode);
1221 return error.Success();
1230 posix_spawnattr_t attr;
1234 LLDB_LOG(log,
"error: {0}, ::posix_spawnattr_init ( &attr )",
error);
1239 llvm::scope_exit cleanup_attr([&]() { posix_spawnattr_destroy(&attr); });
1241 sigset_t no_signals;
1242 sigset_t all_signals;
1243 sigemptyset(&no_signals);
1244 sigfillset(&all_signals);
1245 ::posix_spawnattr_setsigmask(&attr, &no_signals);
1246 ::posix_spawnattr_setsigdefault(&attr, &all_signals);
1253 "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",
1258 bool is_graphical =
true;
1261 SecuritySessionId session_id;
1262 SessionAttributeBits session_attributes;
1264 SessionGetInfo(callerSecuritySession, &session_id, &session_attributes);
1265 if (status == errSessionSuccess)
1266 is_graphical = session_attributes & sessionHasGraphicAccess;
1272 if (is_graphical && launch_info.
GetFlags().
Test(eLaunchFlagDebug) &&
1273 !launch_info.
GetFlags().
Test(eLaunchFlagInheritTCCFromParent)) {
1276 LLDB_LOG(log,
"error: {0}, setup_posix_spawn_responsible_flag(&attr)",
1282 if (launch_info.
GetFlags().
Test(eLaunchFlagMemoryTagging)) {
1291 using posix_spawnattr_set_use_sec_transition_shims_np_t =
1292 int (*)(posix_spawnattr_t *attr, uint32_t flags);
1293 auto posix_spawnattr_enable_memory_tagging_fn =
1294 (posix_spawnattr_set_use_sec_transition_shims_np_t)dlsym(
1295 RTLD_DEFAULT,
"posix_spawnattr_set_use_sec_transition_shims_np");
1296 if (posix_spawnattr_enable_memory_tagging_fn) {
1297 error =
Status(posix_spawnattr_enable_memory_tagging_fn(&attr, 0),
1302 "posix_spawnattr_set_use_sec_transition_shims_np(&attr, 0)",
1308 "error: {}, posix_spawnattr_set_use_sec_transition_shims_np "
1322 const bool set_cpu_type =
1325 const bool set_cpu_subtype =
1331 typedef int (*posix_spawnattr_setarchpref_np_t)(
1333 posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn =
1334 (posix_spawnattr_setarchpref_np_t)dlsym(
1335 RTLD_DEFAULT,
"posix_spawnattr_setarchpref_np");
1336 if (set_cpu_subtype && posix_spawnattr_setarchpref_np_fn) {
1337 error =
Status((*posix_spawnattr_setarchpref_np_fn)(
1338 &attr, 1, &cpu_type, &cpu_subtype, &ocount),
1342 "error: {}, ::posix_spawnattr_setarchpref_np ( &attr, 1, "
1343 "cpu_type = {:x}, cpu_subtype = {:x}, count => {} )",
1344 error, cpu_type, cpu_subtype, ocount);
1346 if (
error.Fail() || ocount != 1)
1350 ::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount),
1354 "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
1355 "cpu_type = {1:x}, count => {2} )",
1356 error, cpu_type, ocount);
1357 if (
error.Fail() || ocount != 1)
1363 const char *tmp_argv[2];
1364 char *
const *argv =
const_cast<char *
const *
>(
1372 tmp_argv[0] = exe_path;
1374 argv =
const_cast<char *
const *
>(tmp_argv);
1380 std::string working_dir_path = working_dir.
GetPath();
1382 if (errno == ENOENT) {
1384 "No such file or directory: %s", working_dir_path.c_str());
1385 }
else if (errno == ENOTDIR) {
1387 "Path doesn't name a directory: %s", working_dir_path.c_str());
1391 "changing directory for process "
1400 if (num_file_actions > 0) {
1401 posix_spawn_file_actions_t file_actions;
1406 "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",
1412 llvm::scope_exit cleanup_fileact(
1413 [&]() { posix_spawn_file_actions_destroy(&file_actions); });
1415 for (
size_t i = 0; i < num_file_actions; ++i) {
1418 if (launch_file_action) {
1426 ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
1431 "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
1432 "file_actions = {3}, "
1433 "attr = {4}, argv = {5}, envp = {6} )",
1434 error, result_pid, exe_path, &file_actions, &attr, argv,
1437 for (
int ii = 0; argv[ii]; ++ii)
1438 LLDB_LOG(log,
"argv[{0}] = '{1}'", ii, argv[ii]);
1444 Status(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
1449 "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
1450 "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
1451 error, result_pid, exe_path, &attr, argv, envp.
get());
1453 for (
int ii = 0; argv[ii]; ++ii)
1454 LLDB_LOG(log,
"argv[{0}] = '{1}'", ii, argv[ii]);
1469 bool result =
false;
1472 bool launchingAsRoot = launch_info.
GetUserID() == 0;
1473 bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
1475 if (launchingAsRoot && !currentUserIsRoot) {
1490 if (!fs.
Exists(exe_spec))
1493 if (!fs.
Exists(exe_spec))
1496 if (!fs.
Exists(exe_spec)) {
1498 "executable doesn't exist: '{0}'", exe_spec);
1502 if (launch_info.
GetFlags().
Test(eLaunchFlagLaunchInTTY)) {
1504 return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(),
1509 "supported on iOS devices");
1516 auto exe_path = exe_spec.GetPath();
1533 if (
error.Success())
1542 if (launch_info.
GetFlags().
Test(eLaunchFlagShellExpandArguments)) {
1543 FileSpec expand_tool_spec;
1545 std::string env_argdumper_path = host_env.lookup(
"LLDB_ARGDUMPER_PATH");
1546 if (!env_argdumper_path.empty()) {
1547 expand_tool_spec.
SetFile(env_argdumper_path, FileSpec::Style::native);
1550 "lldb-argdumper exe path set from environment variable: %s",
1551 env_argdumper_path.c_str());
1554 if (!argdumper_exists) {
1555 expand_tool_spec = HostInfo::GetSupportExeDir();
1556 if (!expand_tool_spec) {
1558 "could not get support executable directory for "
1559 "lldb-argdumper tool");
1565 "could not find the lldb-argdumper tool: %s",
1566 expand_tool_spec.
GetPath().c_str());
1571 StreamString expand_tool_spec_stream;
1572 expand_tool_spec_stream.
Printf(
"\"%s\"",
1573 expand_tool_spec.
GetPath().c_str());
1575 Args expand_command(expand_tool_spec_stream.
GetData());
1576 expand_command.AppendArguments(launch_info.
GetArguments());
1582 char *wd = getcwd(
nullptr, 0);
1583 if (wd ==
nullptr) {
1585 "cwd does not exist: Cannot launch with shell argument expansion");
1588 FileSpec working_dir(wd);
1593 bool run_in_shell =
true;
1594 std::string error_output;
1598 &error_output, std::chrono::seconds(10), run_in_shell);
1605 "lldb-argdumper exited with error %d", status);
1615 auto dict_sp = data_sp->GetAsDictionary();
1621 auto args_sp = dict_sp->GetObjectForDotSeparatedPath(
"arguments");
1627 auto args_array_sp = args_sp->GetAsArray();
1628 if (!args_array_sp) {
1635 for (
size_t i = 0; i < args_array_sp->GetSize(); i++) {
1636 auto item_sp = args_array_sp->GetItemAtIndex(i);
1639 auto str_sp = item_sp->GetAsString();
1652 unsigned long mask = DISPATCH_PROC_EXIT;
1656 dispatch_source_t source = ::dispatch_source_create(
1657 DISPATCH_SOURCE_TYPE_PROC, pid, mask,
1658 ::dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1661 "Host::StartMonitoringChildProcess(callback, pid=%i) source = %p\n",
1662 static_cast<int>(pid),
static_cast<void *
>(source));
1666 ::dispatch_source_set_cancel_handler(source, ^{
1667 dispatch_release(source);
1669 ::dispatch_source_set_event_handler(source, ^{
1673 wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, 0);
1674 if (wait_pid >= 0) {
1676 int exit_status = 0;
1677 const char *status_cstr = NULL;
1678 if (WIFEXITED(status)) {
1679 exit_status = WEXITSTATUS(status);
1680 status_cstr =
"EXITED";
1681 }
else if (WIFSIGNALED(status)) {
1682 signal = WTERMSIG(status);
1683 status_cstr =
"SIGNALED";
1686 llvm_unreachable(
"Unknown status");
1690 "::waitpid (pid = %llu, &status, 0) => pid = %i, status "
1691 "= 0x%8.8x (%s), signal = %i, exit_status = %i",
1692 pid, wait_pid, status, status_cstr, signal, exit_status);
1695 callback_copy(pid, signal, exit_status);
1697 ::dispatch_source_cancel(source);
1701 ::dispatch_resume(source);
1703 return HostThread();
static llvm::raw_ostream & error(Stream &strm)
#define CPU_SUBTYPE_X86_64_H
#define CPU_TYPE_ARM64_32
static llvm::Error GetProcessList(std::vector< struct kinfo_proc > &kinfos)
Fetches the list of all processes into kinfos.
static Status LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
static Status LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info)
#define _POSIX_SPAWN_DISABLE_ASLR
int __pthread_chdir(const char *path)
static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info)
static std::once_flag g_os_log_once
static bool GetMacOSXProcessCPUType(ProcessInstanceInfo &process_info)
static void finalize_xpc(void *xpc_object)
int __pthread_fchdir(int fildes)
static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info)
static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Status &error)
static bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr, ProcessInstanceInfo &process_info)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOGF(log,...)
#define LLDB_LOG_ERROR(log, error,...)
static int setup_posix_spawn_responsible_flag(posix_spawnattr_t *attr)
An architecture specification class.
bool IsValid() const
Tests if this ArchSpec is valid.
void Clear()
Clears the object state.
llvm::Triple & GetTriple()
Architecture triple accessor.
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.
uint32_t GetMachOCPUSubType() const
uint32_t GetMachOCPUType() const
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
A command line argument class.
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
const char ** GetConstArgumentVector() const
Gets the argument vector.
void Clear()
Clear the arguments.
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.
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.
char *const * get() const
static std::string compose(const value_type &KeyValue)
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
Represents a file descriptor action to be performed during process launch.
Action GetAction() const
Get the type of action.
int GetActionArgument() const
Get the action-specific argument.
const FileSpec & GetFileSpec() const
Get the file specification for open actions.
int GetFD() const
Get the file descriptor this action applies to.
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
void AppendPathComponent(llvm::StringRef component)
void SetFilename(llvm::StringRef filename)
Filename string set accessor.
llvm::StringRef GetFilename() const
Filename string const get accessor.
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
void Clear()
Clears the object state.
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.
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)
Open a URL with the host's default handler (Launch Services on macOS, xdg-open on other Unix).
static Status ShellExpandArguments(ProcessLaunchInfo &launch_info)
Perform expansion of the command-line for this launch info This can potentially involve wildcard expa...
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)
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
std::function< void(lldb::pid_t pid, int signal, int status)> MonitorChildProcessCallback
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)
bool ProcessIDIsValid() const
void SetArg0(llvm::StringRef arg)
lldb::pid_t GetProcessID() const
void SetProcessID(lldb::pid_t pid)
FileSpec & GetExecutableFile()
llvm::StringRef GetName() const
uint32_t GetUserID() const
Environment & GetEnvironment()
void SetUserID(uint32_t uid)
ArchSpec & GetArchitecture()
NameMatch GetNameMatchType() const
bool Matches(const ProcessInstanceInfo &proc_info) const
bool GetMatchAllUsers() 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
bool MonitorProcess() const
const FileAction * GetFileActionAtIndex(size_t idx) const
const FileAction * GetFileActionForFD(int fd) const
bool GetLaunchInSeparateProcessGroup() const
void SetWorkingDirectory(const FileSpec &working_dir)
const FileSpec & GetWorkingDirectory() const
size_t GetNumFileActions() const
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
bool Fail() const
Test for error condition.
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
bool Success() const
Test for success condition.
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.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
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.
#define LLDB_INVALID_CPUTYPE
#define UNUSED_IF_ASSERT_DISABLED(x)
#define LLDB_INVALID_PROCESS_ID
lldb::ByteOrder InlHostByteOrder()
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.
bool NameMatches(llvm::StringRef name, NameMatch match_type, llvm::StringRef match)
std::vector< ProcessInstanceInfo > ProcessInstanceInfoList
Severity
Used for expressing severity in logs and diagnostics.
ConnectionStatus
Connection Status Types.
@ eConnectionStatusSuccess
Success.
@ eErrorTypeGeneric
Generic errors that can be any value.
@ eErrorTypePOSIX
POSIX error codes.