1 //===-- Host.mm -------------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Host/Host.h"
12 #include <AvailabilityMacros.h>
14 #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
15 #define NO_XPC_SERVICES 1
18 #if !defined(NO_XPC_SERVICES)
19 #define __XPC_PRIVATE_H__
22 #define LaunchUsingXPCRightName "com.apple.dt.Xcode.RootDebuggingXPCService"
24 // These XPC messaging keys are used for communication between Host.mm and the XPC service.
25 #define LauncherXPCServiceAuthKey "auth-key"
26 #define LauncherXPCServiceArgPrefxKey "arg"
27 #define LauncherXPCServiceEnvPrefxKey "env"
28 #define LauncherXPCServiceCPUTypeKey "cpuType"
29 #define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags"
30 #define LauncherXPCServiceStdInPathKeyKey "stdInPath"
31 #define LauncherXPCServiceStdOutPathKeyKey "stdOutPath"
32 #define LauncherXPCServiceStdErrPathKeyKey "stdErrPath"
33 #define LauncherXPCServiceChildPIDKey "childPID"
34 #define LauncherXPCServiceErrorTypeKey "errorType"
35 #define LauncherXPCServiceCodeTypeKey "errorCode"
39 #include "llvm/Support/Host.h"
42 #include <crt_externs.h>
51 #include <sys/sysctl.h>
52 #include <sys/types.h>
55 #include "lldb/Core/ArchSpec.h"
56 #include "lldb/Core/Communication.h"
57 #include "lldb/Core/DataBufferHeap.h"
58 #include "lldb/Core/DataExtractor.h"
59 #include "lldb/Core/Log.h"
60 #include "lldb/Core/Module.h"
61 #include "lldb/Core/ModuleSpec.h"
62 #include "lldb/Core/StreamFile.h"
63 #include "lldb/Core/StreamString.h"
64 #include "lldb/Core/StructuredData.h"
65 #include "lldb/Host/ConnectionFileDescriptor.h"
66 #include "lldb/Host/Endian.h"
67 #include "lldb/Host/FileSpec.h"
68 #include "lldb/Host/FileSystem.h"
69 #include "lldb/Host/HostInfo.h"
70 #include "lldb/Host/ThreadLauncher.h"
71 #include "lldb/Target/Platform.h"
72 #include "lldb/Target/Process.h"
73 #include "lldb/Utility/CleanUp.h"
74 #include "lldb/Utility/NameMatches.h"
76 #include "cfcpp/CFCBundle.h"
77 #include "cfcpp/CFCMutableArray.h"
78 #include "cfcpp/CFCMutableDictionary.h"
79 #include "cfcpp/CFCReleaser.h"
80 #include "cfcpp/CFCString.h"
83 #include <objc/objc-auto.h>
85 #include <CoreFoundation/CoreFoundation.h>
86 #include <Foundation/Foundation.h>
88 #ifndef _POSIX_SPAWN_DISABLE_ASLR
89 #define _POSIX_SPAWN_DISABLE_ASLR 0x0100
94 int __pthread_chdir(const char *path);
95 int __pthread_fchdir (int fildes);
99 using namespace lldb_private;
102 Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle_directory)
104 #if defined (__APPLE__)
105 if (file.GetFileType () == FileSpec::eFileTypeDirectory)
108 if (file.GetPath(path, sizeof(path)))
110 CFCBundle bundle (path);
111 if (bundle.GetPath (path, sizeof(path)))
113 bundle_directory.SetFile (path, false);
119 bundle_directory.Clear();
125 Host::ResolveExecutableInBundle (FileSpec &file)
127 #if defined (__APPLE__)
128 if (file.GetFileType () == FileSpec::eFileTypeDirectory)
131 if (file.GetPath(path, sizeof(path)))
133 CFCBundle bundle (path);
134 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
137 if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
139 file.SetFile(path, false);
150 AcceptPIDFromInferior (void *arg)
152 const char *connect_url = (const char *)arg;
153 ConnectionFileDescriptor file_conn;
155 if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
158 ::memset (pid_str, 0, sizeof(pid_str));
159 ConnectionStatus status;
160 const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
163 int pid = atoi (pid_str);
164 return (void *)(intptr_t)pid;
171 WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
173 const int time_delta_usecs = 100000;
174 const int num_retries = timeout_in_seconds/time_delta_usecs;
175 for (int i=0; i<num_retries; i++)
177 struct proc_bsdinfo bsd_info;
178 int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
181 PROC_PIDTBSDINFO_SIZE);
195 if (bsd_info.pbi_status == SSTOP)
198 ::usleep (time_delta_usecs);
202 #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
205 //LaunchInNewTerminalWithCommandFile
207 // const char **argv,
208 // const char **envp,
209 // const char *working_dir,
210 // const ArchSpec *arch_spec,
211 // bool stop_at_entry,
215 // if (!argv || !argv[0])
216 // return LLDB_INVALID_PROCESS_ID;
218 // OSStatus error = 0;
220 // FileSpec program (argv[0], false);
223 // std::string unix_socket_name;
225 // char temp_file_path[PATH_MAX];
226 // const char *tmpdir = ::getenv ("TMPDIR");
227 // if (tmpdir == NULL)
229 // ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString());
231 // if (::mktemp (temp_file_path) == NULL)
232 // return LLDB_INVALID_PROCESS_ID;
234 // unix_socket_name.assign (temp_file_path);
236 // ::strlcat (temp_file_path, ".command", sizeof (temp_file_path));
238 // StreamFile command_file;
239 // command_file.GetFile().Open (temp_file_path,
240 // File::eOpenOptionWrite | File::eOpenOptionCanCreate,
241 // lldb::eFilePermissionsDefault);
243 // if (!command_file.GetFile().IsValid())
244 // return LLDB_INVALID_PROCESS_ID;
246 // FileSpec darwin_debug_file_spec;
247 // if (!HostInfo::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
248 // return LLDB_INVALID_PROCESS_ID;
249 // darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
251 // if (!darwin_debug_file_spec.Exists())
252 // return LLDB_INVALID_PROCESS_ID;
254 // char launcher_path[PATH_MAX];
255 // darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
256 // command_file.Printf("\"%s\" ", launcher_path);
258 // command_file.Printf("--unix-socket=%s ", unix_socket_name.c_str());
260 // if (arch_spec && arch_spec->IsValid())
262 // command_file.Printf("--arch=%s ", arch_spec->GetArchitectureName());
267 // command_file.PutCString("--disable-aslr ");
270 // command_file.PutCString("-- ");
274 // for (size_t i=0; argv[i] != NULL; ++i)
276 // command_file.Printf("\"%s\" ", argv[i]);
279 // command_file.PutCString("\necho Process exited with status $?\n");
280 // command_file.GetFile().Close();
281 // if (::chmod (temp_file_path, S_IRWXU | S_IRWXG) != 0)
282 // return LLDB_INVALID_PROCESS_ID;
284 // CFCMutableDictionary cf_env_dict;
286 // const bool can_create = true;
289 // for (size_t i=0; envp[i] != NULL; ++i)
291 // const char *env_entry = envp[i];
292 // const char *equal_pos = strchr(env_entry, '=');
295 // std::string env_key (env_entry, equal_pos);
296 // std::string env_val (equal_pos + 1);
297 // CFCString cf_env_key (env_key.c_str(), kCFStringEncodingUTF8);
298 // CFCString cf_env_val (env_val.c_str(), kCFStringEncodingUTF8);
299 // cf_env_dict.AddValue (cf_env_key.get(), cf_env_val.get(), can_create);
304 // LSApplicationParameters app_params;
305 // ::memset (&app_params, 0, sizeof (app_params));
306 // app_params.flags = kLSLaunchDontAddToRecents | kLSLaunchAsync;
307 // app_params.argv = NULL;
308 // app_params.environment = (CFDictionaryRef)cf_env_dict.get();
310 // CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL,
311 // (const UInt8 *)temp_file_path,
312 // strlen(temp_file_path),
315 // CFCMutableArray urls;
317 // // Terminal.app will open the ".command" file we have created
318 // // and run our process inside it which will wait at the entry point
319 // // for us to attach.
320 // urls.AppendValue(command_file_url.get());
323 // lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
326 // // Sleep and wait a bit for debugserver to start to listen...
327 // char connect_url[128];
328 // ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name.c_str());
330 // // Spawn a new thread to accept incoming connection on the connect_url
331 // // so we can grab the pid from the inferior
332 // lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name.c_str(),
333 // AcceptPIDFromInferior,
337 // ProcessSerialNumber psn;
338 // error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1);
339 // if (error == noErr)
341 // thread_result_t accept_thread_result = NULL;
342 // if (Host::ThreadJoin (accept_thread, &accept_thread_result, &lldb_error))
344 // if (accept_thread_result)
346 // pid = (intptr_t)accept_thread_result;
348 // // Wait for process to be stopped the entry point by watching
349 // // for the process status to be set to SSTOP which indicates it it
350 // // SIGSTOP'ed at the entry point
351 // WaitForProcessToSIGSTOP (pid, 5);
357 // Host::ThreadCancel (accept_thread, &lldb_error);
363 const char *applscript_in_new_tty =
364 "tell application \"Terminal\"\n"
365 " do script \"%s\"\n"
369 const char *applscript_in_existing_tty = "\
370 set the_shell_script to \"%s\"\n\
371 tell application \"Terminal\"\n\
372 repeat with the_window in (get windows)\n\
373 repeat with the_tab in tabs of the_window\n\
374 set the_tty to tty in the_tab\n\
375 if the_tty contains \"%s\" then\n\
376 if the_tab is not busy then\n\
377 set selected of the_tab to true\n\
378 set frontmost of the_window to true\n\
379 do script the_shell_script in the_tab\n\
385 do script the_shell_script\n\
390 LaunchInNewTerminalWithAppleScript (const char *exe_path, ProcessLaunchInfo &launch_info)
393 char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
394 if (::mktemp (unix_socket_name) == NULL)
396 error.SetErrorString ("failed to make temporary path for a unix socket");
400 StreamString command;
401 FileSpec darwin_debug_file_spec;
402 if (!HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, darwin_debug_file_spec))
404 error.SetErrorString ("can't locate the 'darwin-debug' executable");
408 darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
410 if (!darwin_debug_file_spec.Exists())
412 error.SetErrorStringWithFormat ("the 'darwin-debug' executable doesn't exists at '%s'",
413 darwin_debug_file_spec.GetPath().c_str());
417 char launcher_path[PATH_MAX];
418 darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
420 const ArchSpec &arch_spec = launch_info.GetArchitecture();
421 // Only set the architecture if it is valid and if it isn't Haswell (x86_64h).
422 if (arch_spec.IsValid() && arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h)
423 command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());
425 command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name);
427 if (arch_spec.IsValid())
428 command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
430 FileSpec working_dir{launch_info.GetWorkingDirectory()};
432 command.Printf(" --working-dir '%s'", working_dir.GetCString());
436 if (getcwd(cwd, PATH_MAX))
437 command.Printf(" --working-dir '%s'", cwd);
440 if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
441 command.PutCString(" --disable-aslr");
443 // We are launching on this host in a terminal. So compare the environment on the host
444 // to what is supplied in the launch_info. Any items that aren't in the host environment
445 // need to be sent to darwin-debug. If we send all environment entries, we might blow the
446 // max command line length, so we only send user modified entries.
447 const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector ();
450 const size_t host_env_count = Host::GetEnvironment (host_env);
454 const char *env_entry;
455 for (size_t env_idx = 0; (env_entry = envp[env_idx]) != NULL; ++env_idx)
457 bool add_entry = true;
458 for (size_t i=0; i<host_env_count; ++i)
460 const char *host_env_entry = host_env.GetStringAtIndex(i);
461 if (strcmp(env_entry, host_env_entry) == 0)
469 command.Printf(" --env='%s'", env_entry);
474 command.PutCString(" -- ");
476 const char **argv = launch_info.GetArguments().GetConstArgumentVector ();
479 for (size_t i=0; argv[i] != NULL; ++i)
482 command.Printf(" '%s'", exe_path);
484 command.Printf(" '%s'", argv[i]);
489 command.Printf(" '%s'", exe_path);
491 command.PutCString (" ; echo Process exited with status $?");
492 if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))
493 command.PutCString (" ; exit");
495 StreamString applescript_source;
497 const char *tty_command = command.GetString().c_str();
498 // if (tty_name && tty_name[0])
500 // applescript_source.Printf (applscript_in_existing_tty,
506 applescript_source.Printf (applscript_in_new_tty,
512 const char *script_source = applescript_source.GetString().c_str();
513 //puts (script_source);
514 NSAppleScript* applescript = [[NSAppleScript alloc] initWithSource:[NSString stringWithCString:script_source encoding:NSUTF8StringEncoding]];
516 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
519 // Sleep and wait a bit for debugserver to start to listen...
520 ConnectionFileDescriptor file_conn;
521 char connect_url[128];
522 ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
524 // Spawn a new thread to accept incoming connection on the connect_url
525 // so we can grab the pid from the inferior. We have to do this because we
526 // are sending an AppleScript that will launch a process in Terminal.app,
527 // in a shell and the shell will fork/exec a couple of times before we get
528 // to the process that we wanted to launch. So when our process actually
529 // gets launched, we will handshake with it and get the process ID for it.
530 HostThread accept_thread = ThreadLauncher::LaunchThread(unix_socket_name, AcceptPIDFromInferior, connect_url, &lldb_error);
532 [applescript executeAndReturnError:nil];
534 thread_result_t accept_thread_result = NULL;
535 lldb_error = accept_thread.Join(&accept_thread_result);
536 if (lldb_error.Success() && accept_thread_result)
538 pid = (intptr_t)accept_thread_result;
540 // Wait for process to be stopped at the entry point by watching
541 // for the process status to be set to SSTOP which indicates it it
542 // SIGSTOP'ed at the entry point
543 WaitForProcessToSIGSTOP(pid, 5);
546 FileSystem::Unlink(FileSpec{unix_socket_name, false});
547 [applescript release];
548 if (pid != LLDB_INVALID_PROCESS_ID)
549 launch_info.SetProcessID (pid);
553 #endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
556 // On MacOSX CrashReporter will display a string for each shared library if
557 // the shared library has an exported symbol named "__crashreporter_info__".
560 GetCrashReporterMutex ()
562 static Mutex g_mutex;
567 const char *__crashreporter_info__ = NULL;
570 asm(".desc ___crashreporter_info__, 0x10");
573 Host::SetCrashDescriptionWithFormat (const char *format, ...)
575 static StreamString g_crash_description;
576 Mutex::Locker locker (GetCrashReporterMutex ());
581 va_start (args, format);
582 g_crash_description.GetString().clear();
583 g_crash_description.PrintfVarArg(format, args);
585 __crashreporter_info__ = g_crash_description.GetData();
589 __crashreporter_info__ = NULL;
594 Host::SetCrashDescription (const char *cstr)
596 Mutex::Locker locker (GetCrashReporterMutex ());
597 static std::string g_crash_description;
600 g_crash_description.assign (cstr);
601 __crashreporter_info__ = g_crash_description.c_str();
605 __crashreporter_info__ = NULL;
610 Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
612 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
615 // We attach this to an 'odoc' event to specify a particular selection
617 int16_t reserved0; // must be zero
621 uint32_t reserved1; // must be zero
622 uint32_t reserved2; // must be zero
625 Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
626 char file_path[PATH_MAX];
627 file_spec.GetPath(file_path, PATH_MAX);
628 CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
629 CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,
631 kCFURLPOSIXPathStyle,
635 log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
638 BabelAESelInfo file_and_line_info =
641 (int16_t)(line_no - 1), // fLineNumber (zero based line number)
648 AEKeyDesc file_and_line_desc;
650 error = ::AECreateDesc (typeUTF8Text,
652 sizeof (file_and_line_info),
653 &(file_and_line_desc.descContent));
658 log->Printf("Error creating AEDesc: %ld.\n", error);
662 file_and_line_desc.descKey = keyAEPosition;
664 static std::string g_app_name;
665 static FSRef g_app_fsref;
667 LSApplicationParameters app_params;
668 ::memset (&app_params, 0, sizeof (app_params));
669 app_params.flags = kLSLaunchDefaults |
670 kLSLaunchDontAddToRecents |
673 char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
678 log->Printf("Looking for external editor \"%s\".\n", external_editor);
680 if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
682 CFCString editor_name (external_editor, kCFStringEncodingUTF8);
683 error = ::LSFindApplicationForInfo (kLSUnknownCreator,
689 // If we found the app, then store away the name so we don't have to re-look it up.
693 log->Printf("Could not find External Editor application, error: %ld.\n", error);
698 app_params.application = &g_app_fsref;
701 ProcessSerialNumber psn;
702 CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
703 error = ::LSOpenURLsWithRole (file_array.get(),
710 AEDisposeDesc (&(file_and_line_desc.descContent));
715 log->Printf("LSOpenURLsWithRole failed, error: %ld.\n", error);
721 #endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
725 Host::GetEnvironment (StringList &env)
727 char **host_env = *_NSGetEnviron();
730 for (i=0; (env_entry = host_env[i]) != NULL; ++i)
731 env.AppendString(env_entry);
737 GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info)
739 if (process_info.ProcessIDIsValid())
741 // Make a new mib to stay thread safe
742 int mib[CTL_MAXNAME]={0,};
743 size_t mib_len = CTL_MAXNAME;
744 if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len))
747 mib[mib_len] = process_info.GetProcessID();
750 cpu_type_t cpu, sub = 0;
751 size_t len = sizeof(cpu);
752 if (::sysctl (mib, mib_len, &cpu, &len, 0, 0) == 0)
756 case CPU_TYPE_I386: sub = CPU_SUBTYPE_I386_ALL; break;
757 case CPU_TYPE_X86_64: sub = CPU_SUBTYPE_X86_64_ALL; break;
759 #if defined (CPU_TYPE_ARM64) && defined (CPU_SUBTYPE_ARM64_ALL)
760 case CPU_TYPE_ARM64: sub = CPU_SUBTYPE_ARM64_ALL; break;
765 // Note that we fetched the cpu type from the PROCESS but we can't get a cpusubtype of the
766 // process -- we can only get the host's cpu subtype.
767 uint32_t cpusubtype = 0;
768 len = sizeof(cpusubtype);
769 if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
772 bool host_cpu_is_64bit;
773 uint32_t is64bit_capable;
774 size_t is64bit_capable_len = sizeof (is64bit_capable);
775 if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, &is64bit_capable_len, NULL, 0) == 0)
776 host_cpu_is_64bit = true;
778 host_cpu_is_64bit = false;
780 // if the host is an armv8 device, its cpusubtype will be in CPU_SUBTYPE_ARM64 numbering
781 // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value instead.
783 if (host_cpu_is_64bit)
785 sub = CPU_SUBTYPE_ARM_V7;
793 process_info.GetArchitecture ().SetArchitecture (eArchTypeMachO, cpu, sub);
797 process_info.GetArchitecture().Clear();
802 GetMacOSXProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
803 ProcessInstanceInfo &process_info)
805 if (process_info.ProcessIDIsValid())
807 int proc_args_mib[3] = { CTL_KERN, KERN_PROCARGS2, (int)process_info.GetProcessID() };
809 size_t arg_data_size = 0;
810 if (::sysctl (proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) || arg_data_size == 0)
811 arg_data_size = 8192;
813 // Add a few bytes to the calculated length, I know we need to add at least one byte
814 // to this number otherwise we get junk back, so add 128 just in case...
815 DataBufferHeap arg_data(arg_data_size+128, 0);
816 arg_data_size = arg_data.GetByteSize();
817 if (::sysctl (proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size , NULL, 0) == 0)
819 DataExtractor data (arg_data.GetBytes(), arg_data_size, endian::InlHostByteOrder(), sizeof(void *));
820 lldb::offset_t offset = 0;
821 uint32_t argc = data.GetU32 (&offset);
822 llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
823 const llvm::Triple::ArchType triple_arch = triple.getArch();
824 const bool check_for_ios_simulator = (triple_arch == llvm::Triple::x86 || triple_arch == llvm::Triple::x86_64);
825 const char *cstr = data.GetCStr (&offset);
828 process_info.GetExecutableFile().SetFile(cstr, false);
830 if (match_info_ptr == NULL ||
831 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
832 match_info_ptr->GetNameMatchType(),
833 match_info_ptr->GetProcessInfo().GetName()))
838 const uint8_t *p = data.PeekData(offset, 1);
839 if ((p == NULL) || (*p != '\0'))
843 // Now extract all arguments
844 Args &proc_args = process_info.GetArguments();
845 for (int i=0; i<static_cast<int>(argc); ++i)
847 cstr = data.GetCStr(&offset);
849 proc_args.AppendArgument(cstr);
852 Args &proc_env = process_info.GetEnvironmentEntries ();
853 while ((cstr = data.GetCStr(&offset)))
858 if (check_for_ios_simulator)
860 if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == 0)
861 process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::IOS);
863 process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::MacOSX);
866 proc_env.AppendArgument(cstr);
877 GetMacOSXProcessUserAndGroup (ProcessInstanceInfo &process_info)
879 if (process_info.ProcessIDIsValid())
884 mib[2] = KERN_PROC_PID;
885 mib[3] = process_info.GetProcessID();
886 struct kinfo_proc proc_kinfo;
887 size_t proc_kinfo_size = sizeof(struct kinfo_proc);
889 if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
891 if (proc_kinfo_size > 0)
893 process_info.SetParentProcessID (proc_kinfo.kp_eproc.e_ppid);
894 process_info.SetUserID (proc_kinfo.kp_eproc.e_pcred.p_ruid);
895 process_info.SetGroupID (proc_kinfo.kp_eproc.e_pcred.p_rgid);
896 process_info.SetEffectiveUserID (proc_kinfo.kp_eproc.e_ucred.cr_uid);
897 if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
898 process_info.SetEffectiveGroupID (proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
900 process_info.SetEffectiveGroupID (UINT32_MAX);
905 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
906 process_info.SetUserID (UINT32_MAX);
907 process_info.SetGroupID (UINT32_MAX);
908 process_info.SetEffectiveUserID (UINT32_MAX);
909 process_info.SetEffectiveGroupID (UINT32_MAX);
915 Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
917 std::vector<struct kinfo_proc> kinfos;
919 int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
921 size_t pid_data_size = 0;
922 if (::sysctl (mib, 4, NULL, &pid_data_size, NULL, 0) != 0)
925 // Add a few extra in case a few more show up
926 const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
928 kinfos.resize (estimated_pid_count);
929 pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
931 if (::sysctl (mib, 4, &kinfos[0], &pid_data_size, NULL, 0) != 0)
934 const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
936 bool all_users = match_info.GetMatchAllUsers();
937 const lldb::pid_t our_pid = getpid();
938 const uid_t our_uid = getuid();
939 for (size_t i = 0; i < actual_pid_count; i++)
941 const struct kinfo_proc &kinfo = kinfos[i];
943 bool kinfo_user_matches = false;
945 kinfo_user_matches = true;
947 kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
949 // Special case, if lldb is being run as root we can attach to anything.
951 kinfo_user_matches = true;
953 if (kinfo_user_matches == false || // Make sure the user is acceptable
954 static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) == our_pid || // Skip this process
955 kinfo.kp_proc.p_pid == 0 || // Skip kernel (kernel pid is zero)
956 kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains...
957 kinfo.kp_proc.p_flag & P_TRACED || // Being debugged?
958 kinfo.kp_proc.p_flag & P_WEXIT || // Working on exiting?
959 kinfo.kp_proc.p_flag & P_TRANSLATED) // Skip translated ppc (Rosetta)
962 ProcessInstanceInfo process_info;
963 process_info.SetProcessID (kinfo.kp_proc.p_pid);
964 process_info.SetParentProcessID (kinfo.kp_eproc.e_ppid);
965 process_info.SetUserID (kinfo.kp_eproc.e_pcred.p_ruid);
966 process_info.SetGroupID (kinfo.kp_eproc.e_pcred.p_rgid);
967 process_info.SetEffectiveUserID (kinfo.kp_eproc.e_ucred.cr_uid);
968 if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
969 process_info.SetEffectiveGroupID (kinfo.kp_eproc.e_ucred.cr_groups[0]);
971 process_info.SetEffectiveGroupID (UINT32_MAX);
973 // Make sure our info matches before we go fetch the name and cpu type
974 if (match_info.Matches (process_info))
976 // Get CPU type first so we can know to look for iOS simulator is we have x86 or x86_64
977 if (GetMacOSXProcessCPUType (process_info))
979 if (GetMacOSXProcessArgs (&match_info, process_info))
981 if (match_info.Matches (process_info))
982 process_infos.Append (process_info);
987 return process_infos.GetSize();
991 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
993 process_info.SetProcessID(pid);
994 bool success = false;
996 // Get CPU type first so we can know to look for iOS simulator is we have x86 or x86_64
997 if (GetMacOSXProcessCPUType (process_info))
1000 if (GetMacOSXProcessArgs (NULL, process_info))
1003 if (GetMacOSXProcessUserAndGroup (process_info))
1009 process_info.Clear();
1013 #if !NO_XPC_SERVICES
1015 PackageXPCArguments (xpc_object_t message, const char *prefix, const Args& args)
1017 size_t count = args.GetArgumentCount();
1018 char buf[50]; // long enough for 'argXXX'
1020 sprintf(buf, "%sCount", prefix);
1021 xpc_dictionary_set_int64(message, buf, count);
1022 for (size_t i=0; i<count; i++) {
1024 sprintf(buf, "%s%zi", prefix, i);
1025 xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
1030 A valid authorizationRef means that
1031 - there is the LaunchUsingXPCRightName rights in the /etc/authorization
1032 - we have successfully copied the rights to be send over the XPC wire
1033 Once obtained, it will be valid for as long as the process lives.
1035 static AuthorizationRef authorizationRef = NULL;
1037 getXPCAuthorization (ProcessLaunchInfo &launch_info)
1040 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1042 if ((launch_info.GetUserID() == 0) && !authorizationRef)
1044 OSStatus createStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
1045 if (createStatus != errAuthorizationSuccess)
1047 error.SetError(1, eErrorTypeGeneric);
1048 error.SetErrorString("Can't create authorizationRef.");
1051 error.PutToLog(log, "%s", error.AsCString());
1056 OSStatus rightsStatus = AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
1057 if (rightsStatus != errAuthorizationSuccess)
1059 // No rights in the security database, Create it with the right prompt.
1060 CFStringRef prompt = CFSTR("Xcode is trying to take control of a root process.");
1061 CFStringRef keys[] = { CFSTR("en") };
1062 CFTypeRef values[] = { prompt };
1063 CFDictionaryRef promptDict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1065 CFStringRef keys1[] = { CFSTR("class"), CFSTR("group"), CFSTR("comment"), CFSTR("default-prompt"), CFSTR("shared") };
1066 CFTypeRef values1[] = { CFSTR("user"), CFSTR("admin"), CFSTR(LaunchUsingXPCRightName), promptDict, kCFBooleanFalse };
1067 CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1068 rightsStatus = AuthorizationRightSet(authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
1069 CFRelease(promptDict);
1073 OSStatus copyRightStatus = errAuthorizationDenied;
1074 if (rightsStatus == errAuthorizationSuccess)
1076 AuthorizationItem item1 = { LaunchUsingXPCRightName, 0, NULL, 0 };
1077 AuthorizationItem items[] = {item1};
1078 AuthorizationRights requestedRights = {1, items };
1079 AuthorizationFlags authorizationFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
1080 copyRightStatus = AuthorizationCopyRights(authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment, authorizationFlags, NULL);
1083 if (copyRightStatus != errAuthorizationSuccess)
1085 // Eventually when the commandline supports running as root and the user is not
1086 // logged in in the current audit session, we will need the trick in gdb where
1087 // we ask the user to type in the root passwd in the terminal.
1088 error.SetError(2, eErrorTypeGeneric);
1089 error.SetErrorStringWithFormat("Launching as root needs root authorization.");
1092 error.PutToLog(log, "%s", error.AsCString());
1095 if (authorizationRef)
1097 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1098 authorizationRef = NULL;
1108 LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
1110 #if !NO_XPC_SERVICES
1111 Error error = getXPCAuthorization(launch_info);
1115 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1117 uid_t requested_uid = launch_info.GetUserID();
1118 const char *xpc_service = nil;
1119 bool send_auth = false;
1120 AuthorizationExternalForm extForm;
1121 if (requested_uid == 0)
1123 if (AuthorizationMakeExternalForm(authorizationRef, &extForm) == errAuthorizationSuccess)
1129 error.SetError(3, eErrorTypeGeneric);
1130 error.SetErrorStringWithFormat("Launching root via XPC needs to externalize authorization reference.");
1133 error.PutToLog(log, "%s", error.AsCString());
1137 xpc_service = LaunchUsingXPCRightName;
1141 error.SetError(4, eErrorTypeGeneric);
1142 error.SetErrorStringWithFormat("Launching via XPC is only currently available for root.");
1145 error.PutToLog(log, "%s", error.AsCString());
1150 xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
1152 xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
1153 xpc_type_t type = xpc_get_type(event);
1155 if (type == XPC_TYPE_ERROR) {
1156 if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
1157 // The service has either canceled itself, crashed, or been terminated.
1158 // The XPC connection is still valid and sending a message to it will re-launch the service.
1159 // If the service is state-full, this is the time to initialize the new service.
1161 } else if (event == XPC_ERROR_CONNECTION_INVALID) {
1162 // The service is invalid. Either the service name supplied to xpc_connection_create() is incorrect
1163 // or we (this process) have canceled the service; we can do any cleanup of application state at this point.
1164 // printf("Service disconnected");
1167 // printf("Unexpected error from service: %s", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
1171 // printf("Received unexpected event in handler");
1175 xpc_connection_set_finalizer_f (conn, xpc_finalizer_t(xpc_release));
1176 xpc_connection_resume (conn);
1177 xpc_object_t message = xpc_dictionary_create (nil, nil, 0);
1181 xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes, sizeof(AuthorizationExternalForm));
1184 PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey, launch_info.GetArguments());
1185 PackageXPCArguments(message, LauncherXPCServiceEnvPrefxKey, launch_info.GetEnvironmentEntries());
1187 // Posix spawn stuff.
1188 xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey, launch_info.GetArchitecture().GetMachOCPUType());
1189 xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey, Host::GetPosixspawnFlags(launch_info));
1190 const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
1191 if (file_action && file_action->GetPath())
1193 xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey, file_action->GetPath());
1195 file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
1196 if (file_action && file_action->GetPath())
1198 xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey, file_action->GetPath());
1200 file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
1201 if (file_action && file_action->GetPath())
1203 xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey, file_action->GetPath());
1206 xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, message);
1207 xpc_type_t returnType = xpc_get_type(reply);
1208 if (returnType == XPC_TYPE_DICTIONARY)
1210 pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
1213 int errorType = xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
1214 int errorCode = xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
1216 error.SetError(errorCode, eErrorTypeGeneric);
1217 error.SetErrorStringWithFormat("Problems with launching via XPC. Error type : %i, code : %i", errorType, errorCode);
1220 error.PutToLog(log, "%s", error.AsCString());
1223 if (authorizationRef)
1225 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1226 authorizationRef = NULL;
1230 else if (returnType == XPC_TYPE_ERROR)
1232 error.SetError(5, eErrorTypeGeneric);
1233 error.SetErrorStringWithFormat("Problems with launching via XPC. XPC error : %s", xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
1236 error.PutToLog(log, "%s", error.AsCString());
1248 ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info)
1250 bool result = false;
1252 #if !NO_XPC_SERVICES
1253 bool launchingAsRoot = launch_info.GetUserID() == 0;
1254 bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
1256 if (launchingAsRoot && !currentUserIsRoot)
1258 // If current user is already root, we don't need XPC's help.
1267 Host::LaunchProcess (ProcessLaunchInfo &launch_info)
1270 char exe_path[PATH_MAX];
1271 PlatformSP host_platform_sp (Platform::GetHostPlatform ());
1273 ModuleSpec exe_module_spec(launch_info.GetExecutableFile(), launch_info.GetArchitecture());
1275 FileSpec::FileType file_type = exe_module_spec.GetFileSpec().GetFileType();
1276 if (file_type != FileSpec::eFileTypeRegular)
1278 lldb::ModuleSP exe_module_sp;
1279 error = host_platform_sp->ResolveExecutable (exe_module_spec,
1287 exe_module_spec.GetFileSpec() = exe_module_sp->GetFileSpec();
1290 if (exe_module_spec.GetFileSpec().Exists())
1292 exe_module_spec.GetFileSpec().GetPath (exe_path, sizeof(exe_path));
1296 launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
1297 error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
1301 if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
1303 #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
1304 return LaunchInNewTerminalWithAppleScript (exe_path, launch_info);
1306 error.SetErrorString ("launching a process in a new terminal is not supported on iOS devices");
1311 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
1313 if (ShouldLaunchUsingXPC(launch_info))
1315 error = LaunchProcessXPC(exe_path, launch_info, pid);
1319 error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
1322 if (pid != LLDB_INVALID_PROCESS_ID)
1324 // If all went well, then set the process ID into the launch info
1325 launch_info.SetProcessID(pid);
1327 // Make sure we reap any processes we spawn or we will have zombies.
1328 if (!launch_info.MonitorProcess())
1330 const bool monitor_signals = false;
1331 Host::MonitorChildProcessCallback callback = nullptr;
1333 if (!launch_info.GetFlags().Test(lldb::eLaunchFlagDontSetExitStatus))
1334 callback = Process::SetProcessExitStatus;
1336 StartMonitoringChildProcess (callback,
1344 // Invalid process ID, something didn't go well
1345 if (error.Success())
1346 error.SetErrorString ("process launch failed for unknown reasons");
1352 Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
1355 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
1357 FileSpec expand_tool_spec;
1358 if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
1360 error.SetErrorString("could not get support executable directory for lldb-argdumper tool");
1363 expand_tool_spec.AppendPathComponent("lldb-argdumper");
1364 if (!expand_tool_spec.Exists())
1366 error.SetErrorStringWithFormat("could not find the lldb-argdumper tool: %s", expand_tool_spec.GetPath().c_str());
1370 StreamString expand_tool_spec_stream;
1371 expand_tool_spec_stream.Printf("\"%s\"",expand_tool_spec.GetPath().c_str());
1373 Args expand_command(expand_tool_spec_stream.GetData());
1374 expand_command.AppendArguments (launch_info.GetArguments());
1378 FileSpec cwd(launch_info.GetWorkingDirectory());
1381 char *wd = getcwd(nullptr, 0);
1384 error.SetErrorStringWithFormat("cwd does not exist; cannot launch with shell argument expansion");
1389 FileSpec working_dir(wd, false);
1391 launch_info.SetWorkingDirectory(working_dir);
1395 RunShellCommand(expand_command, cwd, &status, nullptr, &output, 10);
1399 error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
1403 auto data_sp = StructuredData::ParseJSON(output);
1406 error.SetErrorString("invalid JSON");
1410 auto dict_sp = data_sp->GetAsDictionary();
1413 error.SetErrorString("invalid JSON");
1417 auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
1420 error.SetErrorString("invalid JSON");
1424 auto args_array_sp = args_sp->GetAsArray();
1427 error.SetErrorString("invalid JSON");
1431 launch_info.GetArguments().Clear();
1434 i < args_array_sp->GetSize();
1437 auto item_sp = args_array_sp->GetItemAtIndex(i);
1440 auto str_sp = item_sp->GetAsString();
1444 launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
1452 Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
1454 unsigned long mask = DISPATCH_PROC_EXIT;
1455 if (monitor_signals)
1456 mask |= DISPATCH_PROC_SIGNAL;
1458 Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1461 dispatch_source_t source = ::dispatch_source_create (DISPATCH_SOURCE_TYPE_PROC,
1464 ::dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0));
1467 log->Printf ("Host::StartMonitoringChildProcess (callback=%p, baton=%p, pid=%i, monitor_signals=%i) source = %p\n",
1476 ::dispatch_source_set_cancel_handler (source, ^{
1477 ::dispatch_release (source);
1479 ::dispatch_source_set_event_handler (source, ^{
1483 bool cancel = false;
1484 bool exited = false;
1487 wait_pid = ::waitpid (pid, &status, 0);
1488 } while (wait_pid < 0 && errno == EINTR);
1493 int exit_status = 0;
1494 const char *status_cstr = NULL;
1495 if (WIFSTOPPED(status))
1497 signal = WSTOPSIG(status);
1498 status_cstr = "STOPPED";
1500 else if (WIFEXITED(status))
1502 exit_status = WEXITSTATUS(status);
1503 status_cstr = "EXITED";
1506 else if (WIFSIGNALED(status))
1508 signal = WTERMSIG(status);
1509 status_cstr = "SIGNALED";
1515 status_cstr = "???";
1519 log->Printf ("::waitpid (pid = %llu, &status, 0) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_status = %i",
1528 cancel = callback (callback_baton, pid, exited, signal, exit_status);
1530 if (exited || cancel)
1532 ::dispatch_source_cancel(source);
1537 ::dispatch_resume (source);
1539 return HostThread();
1542 //----------------------------------------------------------------------
1543 // Log to both stderr and to ASL Logging when running on MacOSX.
1544 //----------------------------------------------------------------------
1546 Host::SystemLog (SystemLogType type, const char *format, va_list args)
1548 if (format && format[0])
1550 static aslmsg g_aslmsg = NULL;
1551 if (g_aslmsg == NULL)
1553 g_aslmsg = ::asl_new (ASL_TYPE_MSG);
1554 char asl_key_sender[PATH_MAX];
1555 snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.LLDB.framework");
1556 ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
1559 // Copy the va_list so we can log this message twice
1561 va_copy (copy_args, args);
1563 ::vfprintf (stderr, format, copy_args);
1569 case eSystemLogError:
1570 asl_level = ASL_LEVEL_ERR;
1573 case eSystemLogWarning:
1574 asl_level = ASL_LEVEL_WARNING;
1579 ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
1584 Host::GetAuxvData(lldb_private::Process *process)
1586 return lldb::DataBufferSP();