]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Host/macosx/Host.mm
Vendor import of lldb trunk r256945:
[FreeBSD/FreeBSD.git] / source / Host / macosx / Host.mm
1 //===-- Host.mm -------------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Host/Host.h"
11
12 #include <AvailabilityMacros.h>
13
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 
16 #endif
17
18 #if !defined(NO_XPC_SERVICES)
19 #define __XPC_PRIVATE_H__
20 #include <xpc/xpc.h>
21
22 #define LaunchUsingXPCRightName "com.apple.dt.Xcode.RootDebuggingXPCService"
23
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"
36
37 #endif
38
39 #include "llvm/Support/Host.h"
40
41 #include <asl.h>
42 #include <crt_externs.h>
43 #include <grp.h>
44 #include <libproc.h>
45 #include <pwd.h>
46 #include <spawn.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <sys/proc.h>
50 #include <sys/stat.h>
51 #include <sys/sysctl.h>
52 #include <sys/types.h>
53 #include <unistd.h>
54
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"
75
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"
81
82
83 #include <objc/objc-auto.h>
84
85 #include <CoreFoundation/CoreFoundation.h>
86 #include <Foundation/Foundation.h>
87
88 #ifndef _POSIX_SPAWN_DISABLE_ASLR
89 #define _POSIX_SPAWN_DISABLE_ASLR       0x0100
90 #endif
91
92 extern "C" 
93 {
94     int __pthread_chdir(const char *path);
95     int __pthread_fchdir (int fildes);
96 }
97
98 using namespace lldb;
99 using namespace lldb_private;
100
101 bool
102 Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle_directory)
103 {
104 #if defined (__APPLE__)
105     if (file.GetFileType () == FileSpec::eFileTypeDirectory)
106     {
107         char path[PATH_MAX];
108         if (file.GetPath(path, sizeof(path)))
109         {
110             CFCBundle bundle (path);
111             if (bundle.GetPath (path, sizeof(path)))
112             {
113                 bundle_directory.SetFile (path, false);
114                 return true;
115             }
116         }
117     }
118 #endif
119     bundle_directory.Clear();
120     return false;
121 }
122
123
124 bool
125 Host::ResolveExecutableInBundle (FileSpec &file)
126 {
127 #if defined (__APPLE__)
128     if (file.GetFileType () == FileSpec::eFileTypeDirectory)
129     {
130         char path[PATH_MAX];
131         if (file.GetPath(path, sizeof(path)))
132         {
133             CFCBundle bundle (path);
134             CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
135             if (url.get())
136             {
137                 if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
138                 {
139                     file.SetFile(path, false);
140                     return true;
141                 }
142             }
143         }
144     }
145 #endif
146   return false;
147 }
148
149 static void *
150 AcceptPIDFromInferior (void *arg)
151 {
152     const char *connect_url = (const char *)arg;
153     ConnectionFileDescriptor file_conn;
154     Error error;
155     if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
156     {
157         char pid_str[256];
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);
161         if (pid_str_len > 0)
162         {
163             int pid = atoi (pid_str);
164             return (void *)(intptr_t)pid;
165         }
166     }
167     return NULL;
168 }
169
170 static bool
171 WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
172 {
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++)
176     {
177         struct proc_bsdinfo bsd_info;
178         int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO, 
179                                     (uint64_t) 0, 
180                                     &bsd_info, 
181                                     PROC_PIDTBSDINFO_SIZE);
182         
183         switch (error)
184         {
185         case EINVAL:
186         case ENOTSUP:
187         case ESRCH:
188         case EPERM:
189             return false;
190         
191         default:
192             break;
193
194         case 0:
195             if (bsd_info.pbi_status == SSTOP)
196                 return true;
197         }
198         ::usleep (time_delta_usecs);
199     }
200     return false;
201 }
202 #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
203
204 //static lldb::pid_t
205 //LaunchInNewTerminalWithCommandFile 
206 //(
207 //    const char **argv, 
208 //    const char **envp,
209 //    const char *working_dir,
210 //    const ArchSpec *arch_spec,
211 //    bool stop_at_entry,
212 //    bool disable_aslr
213 //)
214 //{
215 //    if (!argv || !argv[0])
216 //        return LLDB_INVALID_PROCESS_ID;
217 //
218 //    OSStatus error = 0;
219 //    
220 //    FileSpec program (argv[0], false);
221 //    
222 //    
223 //    std::string unix_socket_name;
224 //
225 //    char temp_file_path[PATH_MAX];
226 //    const char *tmpdir = ::getenv ("TMPDIR");
227 //    if (tmpdir == NULL)
228 //        tmpdir = "/tmp/";
229 //    ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString());
230 //    
231 //    if (::mktemp (temp_file_path) == NULL)
232 //        return LLDB_INVALID_PROCESS_ID;
233 //
234 //    unix_socket_name.assign (temp_file_path);
235 //
236 //    ::strlcat (temp_file_path, ".command", sizeof (temp_file_path));
237 //
238 //    StreamFile command_file;
239 //    command_file.GetFile().Open (temp_file_path, 
240 //                                 File::eOpenOptionWrite | File::eOpenOptionCanCreate,
241 //                                 lldb::eFilePermissionsDefault);
242 //    
243 //    if (!command_file.GetFile().IsValid())
244 //        return LLDB_INVALID_PROCESS_ID;
245 //    
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");
250 //
251 //    if (!darwin_debug_file_spec.Exists())
252 //        return LLDB_INVALID_PROCESS_ID;
253 //
254 //    char launcher_path[PATH_MAX];
255 //    darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
256 //    command_file.Printf("\"%s\" ", launcher_path);
257 //
258 //    command_file.Printf("--unix-socket=%s ", unix_socket_name.c_str());
259 //
260 //    if (arch_spec && arch_spec->IsValid())
261 //    {
262 //        command_file.Printf("--arch=%s ", arch_spec->GetArchitectureName());
263 //    }
264 //
265 //    if (disable_aslr)
266 //    {
267 //        command_file.PutCString("--disable-aslr ");
268 //    }
269 //
270 //    command_file.PutCString("-- ");
271 //
272 //    if (argv)
273 //    {
274 //        for (size_t i=0; argv[i] != NULL; ++i)
275 //        {
276 //            command_file.Printf("\"%s\" ", argv[i]);
277 //        }
278 //    }
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;
283 //
284 //    CFCMutableDictionary cf_env_dict;
285 //
286 //    const bool can_create = true;
287 //    if (envp)
288 //    {
289 //        for (size_t i=0; envp[i] != NULL; ++i)
290 //        {
291 //            const char *env_entry = envp[i];
292 //            const char *equal_pos = strchr(env_entry, '=');
293 //            if (equal_pos)
294 //            {
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);
300 //            }
301 //        }
302 //    }
303 //
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();
309 //
310 //    CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL,
311 //                                                                                       (const UInt8 *)temp_file_path,
312 //                                                                                       strlen(temp_file_path),
313 //                                                                                       false));
314 //
315 //    CFCMutableArray urls;
316 //
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());
321 //
322 //
323 //    lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
324 //
325 //    Error lldb_error;
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());
329 //
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,
334 //                                                       connect_url,
335 //                                                       &lldb_error);
336 //
337 //    ProcessSerialNumber psn;
338 //    error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1);
339 //    if (error == noErr)
340 //    {
341 //        thread_result_t accept_thread_result = NULL;
342 //        if (Host::ThreadJoin (accept_thread, &accept_thread_result, &lldb_error))
343 //        {
344 //            if (accept_thread_result)
345 //            {
346 //                pid = (intptr_t)accept_thread_result;
347 //
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);
352 //            }
353 //        }
354 //    }
355 //    else
356 //    {
357 //        Host::ThreadCancel (accept_thread, &lldb_error);
358 //    }
359 //
360 //    return pid;
361 //}
362
363 const char *applscript_in_new_tty = 
364 "tell application \"Terminal\"\n"
365 "       do script \"%s\"\n"
366 "end tell\n";
367
368
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\
380                                         return\n\
381                                 end if\n\
382                         end if\n\
383                 end repeat\n\
384         end repeat\n\
385         do script the_shell_script\n\
386 end tell\n";
387
388
389 static Error
390 LaunchInNewTerminalWithAppleScript (const char *exe_path, ProcessLaunchInfo &launch_info)
391 {
392     Error error;
393     char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";    
394     if (::mktemp (unix_socket_name) == NULL)
395     {
396         error.SetErrorString ("failed to make temporary path for a unix socket");
397         return error;
398     }
399     
400     StreamString command;
401     FileSpec darwin_debug_file_spec;
402     if (!HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, darwin_debug_file_spec))
403     {
404         error.SetErrorString ("can't locate the 'darwin-debug' executable");
405         return error;
406     }
407
408     darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
409         
410     if (!darwin_debug_file_spec.Exists())
411     {
412         error.SetErrorStringWithFormat ("the 'darwin-debug' executable doesn't exists at '%s'", 
413                                         darwin_debug_file_spec.GetPath().c_str());
414         return error;
415     }
416     
417     char launcher_path[PATH_MAX];
418     darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
419
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());
424
425     command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name);
426
427     if (arch_spec.IsValid())
428         command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
429
430     FileSpec working_dir{launch_info.GetWorkingDirectory()};
431     if (working_dir)
432         command.Printf(" --working-dir '%s'", working_dir.GetCString());
433     else
434     {
435         char cwd[PATH_MAX];
436         if (getcwd(cwd, PATH_MAX))
437             command.Printf(" --working-dir '%s'", cwd);
438     }
439     
440     if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
441         command.PutCString(" --disable-aslr");
442     
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 ();
448
449     StringList host_env;
450     const size_t host_env_count = Host::GetEnvironment (host_env);
451
452     if (envp && envp[0])
453     {
454         const char *env_entry;
455         for (size_t env_idx = 0; (env_entry = envp[env_idx]) != NULL; ++env_idx)
456         {
457             bool add_entry = true;
458             for (size_t i=0; i<host_env_count; ++i)
459             {
460                 const char *host_env_entry = host_env.GetStringAtIndex(i);
461                 if (strcmp(env_entry, host_env_entry) == 0)
462                 {
463                     add_entry = false;
464                     break;
465                 }
466             }
467             if (add_entry)
468             {
469                 command.Printf(" --env='%s'", env_entry);
470             }
471         }
472     }
473
474     command.PutCString(" -- ");
475
476     const char **argv = launch_info.GetArguments().GetConstArgumentVector ();
477     if (argv)
478     {
479         for (size_t i=0; argv[i] != NULL; ++i)
480         {
481             if (i==0)
482                 command.Printf(" '%s'", exe_path);
483             else
484                 command.Printf(" '%s'", argv[i]);
485         }
486     }
487     else
488     {
489         command.Printf(" '%s'", exe_path);
490     }
491     command.PutCString (" ; echo Process exited with status $?");
492     if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))
493         command.PutCString (" ; exit");
494     
495     StreamString applescript_source;
496
497     const char *tty_command = command.GetString().c_str();
498 //    if (tty_name && tty_name[0])
499 //    {
500 //        applescript_source.Printf (applscript_in_existing_tty, 
501 //                                   tty_command,
502 //                                   tty_name);
503 //    }
504 //    else
505 //    {
506         applescript_source.Printf (applscript_in_new_tty, 
507                                    tty_command);
508 //    }
509
510     
511
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]];
515
516     lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
517
518     Error lldb_error;
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);
523
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);
531
532     [applescript executeAndReturnError:nil];
533     
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)
537     {
538         pid = (intptr_t)accept_thread_result;
539
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);
544     }
545
546     FileSystem::Unlink(FileSpec{unix_socket_name, false});
547     [applescript release];
548     if (pid != LLDB_INVALID_PROCESS_ID)
549         launch_info.SetProcessID (pid);
550     return error;
551 }
552
553 #endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
554
555
556 // On MacOSX CrashReporter will display a string for each shared library if
557 // the shared library has an exported symbol named "__crashreporter_info__".
558
559 static Mutex&
560 GetCrashReporterMutex ()
561 {
562     static Mutex g_mutex;
563     return g_mutex;
564 }
565
566 extern "C" {
567     const char *__crashreporter_info__ = NULL;
568 }
569
570 asm(".desc ___crashreporter_info__, 0x10");
571
572 void
573 Host::SetCrashDescriptionWithFormat (const char *format, ...)
574 {
575     static StreamString g_crash_description;
576     Mutex::Locker locker (GetCrashReporterMutex ());
577     
578     if (format)
579     {
580         va_list args;
581         va_start (args, format);
582         g_crash_description.GetString().clear();
583         g_crash_description.PrintfVarArg(format, args);
584         va_end (args);
585         __crashreporter_info__ = g_crash_description.GetData();
586     }
587     else
588     {
589         __crashreporter_info__ = NULL;
590     }
591 }
592
593 void
594 Host::SetCrashDescription (const char *cstr)
595 {
596     Mutex::Locker locker (GetCrashReporterMutex ());
597     static std::string g_crash_description;
598     if (cstr)
599     {
600         g_crash_description.assign (cstr);
601         __crashreporter_info__ = g_crash_description.c_str();
602     }
603     else
604     {
605         __crashreporter_info__ = NULL;
606     }
607 }
608
609 bool
610 Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
611 {
612 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
613     return false;
614 #else
615     // We attach this to an 'odoc' event to specify a particular selection
616     typedef struct {
617         int16_t   reserved0;  // must be zero
618         int16_t   fLineNumber;
619         int32_t   fSelStart;
620         int32_t   fSelEnd;
621         uint32_t  reserved1;  // must be zero
622         uint32_t  reserved2;  // must be zero
623     } BabelAESelInfo;
624     
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, 
630                                                                      file_cfstr.get(), 
631                                                                      kCFURLPOSIXPathStyle, 
632                                                                      false));
633                                                                      
634     if (log)
635         log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
636     
637     long error; 
638     BabelAESelInfo file_and_line_info = 
639     {
640         0,                         // reserved0
641         (int16_t)(line_no - 1),    // fLineNumber (zero based line number)
642         1,                         // fSelStart
643         1024,                      // fSelEnd
644         0,                         // reserved1
645         0                          // reserved2
646     };
647
648     AEKeyDesc file_and_line_desc;
649     
650     error = ::AECreateDesc (typeUTF8Text, 
651                             &file_and_line_info, 
652                             sizeof (file_and_line_info), 
653                             &(file_and_line_desc.descContent));
654     
655     if (error != noErr)
656     {
657         if (log)
658             log->Printf("Error creating AEDesc: %ld.\n", error);
659         return false;
660     }
661     
662     file_and_line_desc.descKey = keyAEPosition;
663     
664     static std::string g_app_name;
665     static FSRef g_app_fsref;
666
667     LSApplicationParameters app_params;
668     ::memset (&app_params, 0, sizeof (app_params));
669     app_params.flags = kLSLaunchDefaults | 
670                        kLSLaunchDontAddToRecents | 
671                        kLSLaunchDontSwitch;
672     
673     char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
674     
675     if (external_editor)
676     {
677         if (log)
678             log->Printf("Looking for external editor \"%s\".\n", external_editor);
679
680         if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
681         {
682             CFCString editor_name (external_editor, kCFStringEncodingUTF8);
683             error = ::LSFindApplicationForInfo (kLSUnknownCreator, 
684                                                 NULL, 
685                                                 editor_name.get(), 
686                                                 &g_app_fsref, 
687                                                 NULL);
688             
689             // If we found the app, then store away the name so we don't have to re-look it up.
690             if (error != noErr)
691             {
692                 if (log)
693                     log->Printf("Could not find External Editor application, error: %ld.\n", error);
694                 return false;
695             }
696                 
697         }
698         app_params.application = &g_app_fsref;
699     }
700
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(), 
704                                   kLSRolesAll, 
705                                   &file_and_line_desc, 
706                                   &app_params, 
707                                   &psn, 
708                                   1);
709     
710     AEDisposeDesc (&(file_and_line_desc.descContent));
711
712     if (error != noErr)
713     {
714         if (log)
715             log->Printf("LSOpenURLsWithRole failed, error: %ld.\n", error);
716
717         return false;
718     }
719
720     return true;
721 #endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
722 }
723
724 size_t
725 Host::GetEnvironment (StringList &env)
726 {
727     char **host_env = *_NSGetEnviron();
728     char *env_entry;
729     size_t i;
730     for (i=0; (env_entry = host_env[i]) != NULL; ++i)
731         env.AppendString(env_entry);
732     return i;
733         
734 }
735
736 static bool
737 GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info)
738 {
739     if (process_info.ProcessIDIsValid())
740     {
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)) 
745             return false;
746     
747         mib[mib_len] = process_info.GetProcessID();
748         mib_len++;
749
750         cpu_type_t cpu, sub = 0;
751         size_t len = sizeof(cpu);
752         if (::sysctl (mib, mib_len, &cpu, &len, 0, 0) == 0)
753         {
754             switch (cpu)
755             {
756                 case CPU_TYPE_I386:      sub = CPU_SUBTYPE_I386_ALL;     break;
757                 case CPU_TYPE_X86_64:    sub = CPU_SUBTYPE_X86_64_ALL;   break;
758
759 #if defined (CPU_TYPE_ARM64) && defined (CPU_SUBTYPE_ARM64_ALL)
760                 case CPU_TYPE_ARM64:     sub = CPU_SUBTYPE_ARM64_ALL;      break;
761 #endif
762
763                 case CPU_TYPE_ARM:
764                     {
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)
770                             sub = cpusubtype;
771
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;
777                         else
778                             host_cpu_is_64bit = false;
779
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.
782
783                         if (host_cpu_is_64bit)
784                         {
785                             sub = CPU_SUBTYPE_ARM_V7;
786                         }
787                     }
788                     break;
789
790                 default:
791                     break;
792             }
793             process_info.GetArchitecture ().SetArchitecture (eArchTypeMachO, cpu, sub);
794             return true;
795         }
796     }
797     process_info.GetArchitecture().Clear();
798     return false;
799 }
800
801 static bool
802 GetMacOSXProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
803                       ProcessInstanceInfo &process_info)
804 {
805     if (process_info.ProcessIDIsValid())
806     {
807         int proc_args_mib[3] = { CTL_KERN, KERN_PROCARGS2, (int)process_info.GetProcessID() };
808
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;
812
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)
818         {
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);
826             if (cstr)
827             {
828                 process_info.GetExecutableFile().SetFile(cstr, false);
829
830                 if (match_info_ptr == NULL || 
831                     NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
832                                  match_info_ptr->GetNameMatchType(),
833                                  match_info_ptr->GetProcessInfo().GetName()))
834                 {
835                     // Skip NULLs
836                     while (1)
837                     {
838                         const uint8_t *p = data.PeekData(offset, 1);
839                         if ((p == NULL) || (*p != '\0'))
840                             break;
841                         ++offset;
842                     }
843                     // Now extract all arguments
844                     Args &proc_args = process_info.GetArguments();
845                     for (int i=0; i<static_cast<int>(argc); ++i)
846                     {
847                         cstr = data.GetCStr(&offset);
848                         if (cstr)
849                             proc_args.AppendArgument(cstr);
850                     }
851                     
852                     Args &proc_env = process_info.GetEnvironmentEntries ();
853                     while ((cstr = data.GetCStr(&offset)))
854                     {
855                         if (cstr[0] == '\0')
856                             break;
857                         
858                         if (check_for_ios_simulator)
859                         {
860                             if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == 0)
861                                 process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::IOS);
862                             else
863                                 process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::MacOSX);
864                         }
865
866                         proc_env.AppendArgument(cstr);
867                     }
868                     return true;
869                 }
870             }
871         }
872     }
873     return false;
874 }
875
876 static bool
877 GetMacOSXProcessUserAndGroup (ProcessInstanceInfo &process_info)
878 {
879     if (process_info.ProcessIDIsValid())
880     {
881         int mib[4];
882         mib[0] = CTL_KERN;
883         mib[1] = KERN_PROC;
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);
888
889         if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
890         {
891             if (proc_kinfo_size > 0)
892             {
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]);
899                 else
900                     process_info.SetEffectiveGroupID (UINT32_MAX);            
901                 return true;
902             }
903         }
904     }
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);            
910     return false;
911 }
912
913
914 uint32_t
915 Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
916 {
917     std::vector<struct kinfo_proc> kinfos;
918     
919     int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
920     
921     size_t pid_data_size = 0;
922     if (::sysctl (mib, 4, NULL, &pid_data_size, NULL, 0) != 0)
923         return 0;
924     
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;
927
928     kinfos.resize (estimated_pid_count);
929     pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
930     
931     if (::sysctl (mib, 4, &kinfos[0], &pid_data_size, NULL, 0) != 0)
932         return 0;
933
934     const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
935
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++)
940     {
941         const struct kinfo_proc &kinfo = kinfos[i];
942         
943         bool kinfo_user_matches = false;
944         if (all_users)
945             kinfo_user_matches = true;
946         else
947             kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
948
949         // Special case, if lldb is being run as root we can attach to anything.
950         if (our_uid == 0)
951           kinfo_user_matches = true;
952
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)
960             continue;
961
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]);
970         else
971             process_info.SetEffectiveGroupID (UINT32_MAX);            
972
973         // Make sure our info matches before we go fetch the name and cpu type
974         if (match_info.Matches (process_info))
975         {
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))
978             {
979                 if (GetMacOSXProcessArgs (&match_info, process_info))
980                 {
981                     if (match_info.Matches (process_info))
982                         process_infos.Append (process_info);
983                 }
984             }
985         }
986     }    
987     return process_infos.GetSize();
988 }
989
990 bool
991 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
992 {
993     process_info.SetProcessID(pid);
994     bool success = false;
995
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))
998         success = true;
999     
1000     if (GetMacOSXProcessArgs (NULL, process_info))
1001         success = true;
1002     
1003     if (GetMacOSXProcessUserAndGroup (process_info))
1004         success = true;
1005     
1006     if (success)
1007         return true;
1008     
1009     process_info.Clear();
1010     return false;
1011 }
1012
1013 #if !NO_XPC_SERVICES
1014 static void
1015 PackageXPCArguments (xpc_object_t message, const char *prefix, const Args& args)
1016 {
1017     size_t count = args.GetArgumentCount();
1018     char buf[50]; // long enough for 'argXXX'
1019     memset(buf, 0, 50);
1020     sprintf(buf, "%sCount", prefix);
1021         xpc_dictionary_set_int64(message, buf, count);
1022     for (size_t i=0; i<count; i++) {
1023         memset(buf, 0, 50);
1024         sprintf(buf, "%s%zi", prefix, i);
1025         xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
1026     }
1027 }
1028
1029 /*
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.
1034  */
1035 static AuthorizationRef authorizationRef = NULL;
1036 static Error
1037 getXPCAuthorization (ProcessLaunchInfo &launch_info)
1038 {
1039     Error error;
1040     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1041     
1042     if ((launch_info.GetUserID() == 0) && !authorizationRef)
1043     {
1044         OSStatus createStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
1045         if (createStatus != errAuthorizationSuccess)
1046         {
1047             error.SetError(1, eErrorTypeGeneric);
1048             error.SetErrorString("Can't create authorizationRef.");
1049             if (log)
1050             {
1051                 error.PutToLog(log, "%s", error.AsCString());
1052             }
1053             return error;
1054         }
1055         
1056         OSStatus rightsStatus = AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
1057         if (rightsStatus != errAuthorizationSuccess)
1058         {
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);
1064             
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);
1070             CFRelease(dict);
1071         }
1072             
1073         OSStatus copyRightStatus = errAuthorizationDenied;
1074         if (rightsStatus == errAuthorizationSuccess)
1075         {
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);
1081         }
1082         
1083         if (copyRightStatus != errAuthorizationSuccess)
1084         {
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.");
1090             if (log)
1091             {
1092                 error.PutToLog(log, "%s", error.AsCString());
1093             }
1094             
1095             if (authorizationRef)
1096             {
1097                 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1098                 authorizationRef = NULL;
1099             }
1100         }
1101     }
1102
1103     return error;
1104 }
1105 #endif
1106
1107 static Error
1108 LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
1109 {
1110 #if !NO_XPC_SERVICES
1111     Error error = getXPCAuthorization(launch_info);
1112     if (error.Fail())
1113         return error;
1114     
1115     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1116     
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)
1122     {
1123         if (AuthorizationMakeExternalForm(authorizationRef, &extForm) == errAuthorizationSuccess)
1124         {
1125             send_auth = true;
1126         }
1127         else
1128         {
1129             error.SetError(3, eErrorTypeGeneric);
1130             error.SetErrorStringWithFormat("Launching root via XPC needs to externalize authorization reference.");
1131             if (log)
1132             {
1133                 error.PutToLog(log, "%s", error.AsCString());
1134             }
1135             return error;
1136         }
1137         xpc_service = LaunchUsingXPCRightName;
1138     }
1139     else
1140     {
1141         error.SetError(4, eErrorTypeGeneric);
1142         error.SetErrorStringWithFormat("Launching via XPC is only currently available for root.");
1143         if (log)
1144         {
1145             error.PutToLog(log, "%s", error.AsCString());
1146         }
1147         return error;
1148     }
1149     
1150     xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
1151     
1152         xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
1153         xpc_type_t      type = xpc_get_type(event);
1154         
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.
1160                 return;
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");
1165                 return;
1166             } else {
1167                 // printf("Unexpected error from service: %s", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
1168             }
1169             
1170         } else {
1171             // printf("Received unexpected event in handler");
1172         }
1173     });
1174     
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);
1178     
1179     if (send_auth)
1180     {
1181         xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes, sizeof(AuthorizationExternalForm));
1182     }
1183     
1184     PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey, launch_info.GetArguments());
1185     PackageXPCArguments(message, LauncherXPCServiceEnvPrefxKey, launch_info.GetEnvironmentEntries());
1186     
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())
1192     {
1193         xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey, file_action->GetPath());
1194     }
1195     file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
1196     if (file_action && file_action->GetPath())
1197     {
1198         xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey, file_action->GetPath());
1199     }
1200     file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
1201     if (file_action && file_action->GetPath())
1202     {
1203         xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey, file_action->GetPath());
1204     }
1205     
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)
1209     {
1210         pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
1211         if (pid == 0)
1212         {
1213             int errorType = xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
1214             int errorCode = xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
1215             
1216             error.SetError(errorCode, eErrorTypeGeneric);
1217             error.SetErrorStringWithFormat("Problems with launching via XPC. Error type : %i, code : %i", errorType, errorCode);
1218             if (log)
1219             {
1220                 error.PutToLog(log, "%s", error.AsCString());
1221             }
1222             
1223             if (authorizationRef)
1224             {
1225                 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1226                 authorizationRef = NULL;
1227             }
1228         }
1229     }
1230     else if (returnType == XPC_TYPE_ERROR)
1231     {
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));
1234         if (log)
1235         {
1236             error.PutToLog(log, "%s", error.AsCString());
1237         }
1238     }
1239     
1240     return error;
1241 #else
1242     Error error;
1243     return error;
1244 #endif
1245 }
1246
1247 static bool
1248 ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info)
1249 {
1250     bool result = false;
1251
1252 #if !NO_XPC_SERVICES    
1253     bool launchingAsRoot = launch_info.GetUserID() == 0;
1254     bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
1255     
1256     if (launchingAsRoot && !currentUserIsRoot)
1257     {
1258         // If current user is already root, we don't need XPC's help.
1259         result = true;
1260     }
1261 #endif
1262     
1263     return result;
1264 }
1265
1266 Error
1267 Host::LaunchProcess (ProcessLaunchInfo &launch_info)
1268 {
1269     Error error;
1270     char exe_path[PATH_MAX];
1271     PlatformSP host_platform_sp (Platform::GetHostPlatform ());
1272
1273     ModuleSpec exe_module_spec(launch_info.GetExecutableFile(), launch_info.GetArchitecture());
1274
1275     FileSpec::FileType file_type = exe_module_spec.GetFileSpec().GetFileType();
1276     if (file_type != FileSpec::eFileTypeRegular)
1277     {
1278         lldb::ModuleSP exe_module_sp;
1279         error = host_platform_sp->ResolveExecutable (exe_module_spec,
1280                                                      exe_module_sp,
1281                                                      NULL);
1282         
1283         if (error.Fail())
1284             return error;
1285         
1286         if (exe_module_sp)
1287             exe_module_spec.GetFileSpec() = exe_module_sp->GetFileSpec();
1288     }
1289     
1290     if (exe_module_spec.GetFileSpec().Exists())
1291     {
1292         exe_module_spec.GetFileSpec().GetPath (exe_path, sizeof(exe_path));
1293     }
1294     else
1295     {
1296         launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
1297         error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
1298         return error;
1299     }
1300     
1301     if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
1302     {
1303 #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
1304         return LaunchInNewTerminalWithAppleScript (exe_path, launch_info);
1305 #else
1306         error.SetErrorString ("launching a process in a new terminal is not supported on iOS devices");
1307         return error;
1308 #endif
1309     }
1310
1311     lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
1312
1313     if (ShouldLaunchUsingXPC(launch_info))
1314     {
1315         error = LaunchProcessXPC(exe_path, launch_info, pid);
1316     }
1317     else
1318     {
1319         error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
1320     }
1321     
1322     if (pid != LLDB_INVALID_PROCESS_ID)
1323     {
1324         // If all went well, then set the process ID into the launch info
1325         launch_info.SetProcessID(pid);
1326         
1327         // Make sure we reap any processes we spawn or we will have zombies.
1328         if (!launch_info.MonitorProcess())
1329         {
1330             const bool monitor_signals = false;
1331             Host::MonitorChildProcessCallback callback = nullptr;
1332             
1333             if (!launch_info.GetFlags().Test(lldb::eLaunchFlagDontSetExitStatus))
1334                 callback = Process::SetProcessExitStatus;
1335
1336             StartMonitoringChildProcess (callback,
1337                                          NULL, 
1338                                          pid, 
1339                                          monitor_signals);
1340         }
1341     }
1342     else
1343     {
1344         // Invalid process ID, something didn't go well
1345         if (error.Success())
1346             error.SetErrorString ("process launch failed for unknown reasons");
1347     }
1348     return error;
1349 }
1350
1351 Error
1352 Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
1353 {
1354     Error error;
1355     if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
1356     {
1357         FileSpec expand_tool_spec;
1358         if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
1359         {
1360             error.SetErrorString("could not get support executable directory for lldb-argdumper tool");
1361             return error;
1362         }
1363         expand_tool_spec.AppendPathComponent("lldb-argdumper");
1364         if (!expand_tool_spec.Exists())
1365         {
1366             error.SetErrorStringWithFormat("could not find the lldb-argdumper tool: %s", expand_tool_spec.GetPath().c_str());
1367             return error;
1368         }
1369         
1370         StreamString expand_tool_spec_stream;
1371         expand_tool_spec_stream.Printf("\"%s\"",expand_tool_spec.GetPath().c_str());
1372
1373         Args expand_command(expand_tool_spec_stream.GetData());
1374         expand_command.AppendArguments (launch_info.GetArguments());
1375         
1376         int status;
1377         std::string output;
1378         FileSpec cwd(launch_info.GetWorkingDirectory());
1379         if (!cwd.Exists())
1380         {
1381             char *wd = getcwd(nullptr, 0);
1382             if (wd == nullptr)
1383             {
1384                 error.SetErrorStringWithFormat("cwd does not exist; cannot launch with shell argument expansion");
1385                 return error;
1386             }
1387             else
1388             {
1389                 FileSpec working_dir(wd, false);
1390                 free(wd);
1391                 launch_info.SetWorkingDirectory(working_dir);
1392
1393             }
1394         }
1395         RunShellCommand(expand_command, cwd, &status, nullptr, &output, 10);
1396         
1397         if (status != 0)
1398         {
1399             error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
1400             return error;
1401         }
1402         
1403         auto data_sp = StructuredData::ParseJSON(output);
1404         if (!data_sp)
1405         {
1406             error.SetErrorString("invalid JSON");
1407             return error;
1408         }
1409         
1410         auto dict_sp = data_sp->GetAsDictionary();
1411         if (!data_sp)
1412         {
1413             error.SetErrorString("invalid JSON");
1414             return error;
1415         }
1416         
1417         auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
1418         if (!args_sp)
1419         {
1420             error.SetErrorString("invalid JSON");
1421             return error;
1422         }
1423
1424         auto args_array_sp = args_sp->GetAsArray();
1425         if (!args_array_sp)
1426         {
1427             error.SetErrorString("invalid JSON");
1428             return error;
1429         }
1430         
1431         launch_info.GetArguments().Clear();
1432         
1433         for (size_t i = 0;
1434              i < args_array_sp->GetSize();
1435              i++)
1436         {
1437             auto item_sp = args_array_sp->GetItemAtIndex(i);
1438             if (!item_sp)
1439                 continue;
1440             auto str_sp = item_sp->GetAsString();
1441             if (!str_sp)
1442                 continue;
1443             
1444             launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
1445         }
1446     }
1447     
1448     return error;
1449 }
1450
1451 HostThread
1452 Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
1453 {
1454     unsigned long mask = DISPATCH_PROC_EXIT;
1455     if (monitor_signals)
1456         mask |= DISPATCH_PROC_SIGNAL;
1457
1458     Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1459
1460
1461     dispatch_source_t source = ::dispatch_source_create (DISPATCH_SOURCE_TYPE_PROC, 
1462                                                          pid, 
1463                                                          mask, 
1464                                                          ::dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0));
1465
1466     if (log)
1467         log->Printf ("Host::StartMonitoringChildProcess (callback=%p, baton=%p, pid=%i, monitor_signals=%i) source = %p\n", 
1468                      callback, 
1469                      callback_baton, 
1470                      (int)pid, 
1471                      monitor_signals, 
1472                      source);
1473
1474     if (source)
1475     {
1476         ::dispatch_source_set_cancel_handler (source, ^{
1477             ::dispatch_release (source);
1478         });
1479         ::dispatch_source_set_event_handler (source, ^{
1480             
1481             int status= 0;
1482             int wait_pid = 0;
1483             bool cancel = false;
1484             bool exited = false;
1485             do
1486             {
1487                 wait_pid = ::waitpid (pid, &status, 0);
1488             } while (wait_pid < 0 && errno == EINTR);
1489
1490             if (wait_pid >= 0)
1491             {
1492                 int signal = 0;
1493                 int exit_status = 0;
1494                 const char *status_cstr = NULL;
1495                 if (WIFSTOPPED(status))
1496                 {
1497                     signal = WSTOPSIG(status);
1498                     status_cstr = "STOPPED";
1499                 }
1500                 else if (WIFEXITED(status))
1501                 {
1502                     exit_status = WEXITSTATUS(status);
1503                     status_cstr = "EXITED";
1504                     exited = true;
1505                 }
1506                 else if (WIFSIGNALED(status))
1507                 {
1508                     signal = WTERMSIG(status);
1509                     status_cstr = "SIGNALED";
1510                     exited = true;
1511                     exit_status = -1;
1512                 }
1513                 else
1514                 {
1515                     status_cstr = "???";
1516                 }
1517
1518                 if (log)
1519                     log->Printf ("::waitpid (pid = %llu, &status, 0) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_status = %i",
1520                                  pid,
1521                                  wait_pid,
1522                                  status,
1523                                  status_cstr,
1524                                  signal,
1525                                  exit_status);
1526                 
1527                 if (callback)
1528                     cancel = callback (callback_baton, pid, exited, signal, exit_status);
1529                 
1530                 if (exited || cancel)
1531                 {
1532                     ::dispatch_source_cancel(source);
1533                 }
1534             }
1535         });
1536
1537         ::dispatch_resume (source);
1538     }
1539     return HostThread();
1540 }
1541
1542 //----------------------------------------------------------------------
1543 // Log to both stderr and to ASL Logging when running on MacOSX.
1544 //----------------------------------------------------------------------
1545 void
1546 Host::SystemLog (SystemLogType type, const char *format, va_list args)
1547 {
1548     if (format && format[0])
1549     {
1550         static aslmsg g_aslmsg = NULL;
1551         if (g_aslmsg == NULL)
1552         {
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);
1557         }
1558         
1559         // Copy the va_list so we can log this message twice
1560         va_list copy_args;
1561         va_copy (copy_args, args);
1562         // Log to stderr
1563         ::vfprintf (stderr, format, copy_args);
1564         va_end (copy_args);
1565
1566         int asl_level;
1567         switch (type)
1568         {
1569             case eSystemLogError:
1570                 asl_level = ASL_LEVEL_ERR;
1571                 break;
1572                 
1573             case eSystemLogWarning:
1574                 asl_level = ASL_LEVEL_WARNING;
1575                 break;
1576         }
1577         
1578         // Log to ASL
1579         ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
1580     }
1581 }
1582
1583 lldb::DataBufferSP
1584 Host::GetAuxvData(lldb_private::Process *process)
1585 {
1586     return lldb::DataBufferSP();
1587 }