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#include "launcherXPCService/LauncherXPCService.h"
22#endif
23
24#include <asl.h>
25#include <crt_externs.h>
26#include <execinfo.h>
27#include <grp.h>
28#include <libproc.h>
29#include <pwd.h>
30#include <spawn.h>
31#include <stdio.h>
32#include <sys/proc.h>
33#include <sys/stat.h>
34#include <sys/sysctl.h>
35#include <sys/types.h>
36#include <unistd.h>
37
38#include "lldb/Core/ArchSpec.h"
39#include "lldb/Core/Communication.h"
40#include "lldb/Core/ConnectionFileDescriptor.h"
41#include "lldb/Core/DataExtractor.h"
42#include "lldb/Core/Log.h"
43#include "lldb/Core/Module.h"
44#include "lldb/Core/StreamFile.h"
45#include "lldb/Core/StreamString.h"
46#include "lldb/Host/Endian.h"
47#include "lldb/Host/FileSpec.h"
48#include "lldb/Target/Platform.h"
49#include "lldb/Target/Process.h"
50#include "lldb/Utility/CleanUp.h"
51
52#include "cfcpp/CFCBundle.h"
53#include "cfcpp/CFCMutableArray.h"
54#include "cfcpp/CFCMutableDictionary.h"
55#include "cfcpp/CFCReleaser.h"
56#include "cfcpp/CFCString.h"
57
58#include "llvm/Support/Host.h"
59#include "llvm/Support/MachO.h"
60
61#include <objc/objc-auto.h>
62
63#include <CoreFoundation/CoreFoundation.h>
64#include <Foundation/Foundation.h>
65
66#if !defined(__arm__)
67#include <Carbon/Carbon.h>
68#endif
69
70#ifndef _POSIX_SPAWN_DISABLE_ASLR
71#define _POSIX_SPAWN_DISABLE_ASLR       0x0100
72#endif
73
74extern "C" 
75{
76    int __pthread_chdir(const char *path);
77    int __pthread_fchdir (int fildes);
78}
79
80using namespace lldb;
81using namespace lldb_private;
82
83static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
84static pthread_key_t g_thread_create_key = 0;
85
86class MacOSXDarwinThread
87{
88public:
89    MacOSXDarwinThread(const char *thread_name) :
90        m_pool (nil)
91    {
92        // Register our thread with the collector if garbage collection is enabled.
93        if (objc_collectingEnabled())
94        {
95#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
96            // On Leopard and earlier there is no way objc_registerThreadWithCollector
97            // function, so we do it manually.
98            auto_zone_register_thread(auto_zone());
99#else
100            // On SnowLeopard and later we just call the thread registration function.
101            objc_registerThreadWithCollector();
102#endif
103        }
104        else
105        {
106            m_pool = [[NSAutoreleasePool alloc] init];
107        }
108
109
110        Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
111    }
112
113    ~MacOSXDarwinThread()
114    {
115        if (m_pool)
116        {
117            [m_pool drain];
118            m_pool = nil;
119        }
120    }
121
122    static void PThreadDestructor (void *v)
123    {
124        if (v)
125            delete static_cast<MacOSXDarwinThread*>(v);
126        ::pthread_setspecific (g_thread_create_key, NULL);
127    }
128
129protected:
130    NSAutoreleasePool * m_pool;
131private:
132    DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread);
133};
134
135static void
136InitThreadCreated()
137{
138    ::pthread_key_create (&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor);
139}
140
141void
142Host::ThreadCreated (const char *thread_name)
143{
144    ::pthread_once (&g_thread_create_once, InitThreadCreated);
145    if (g_thread_create_key)
146    {
147        ::pthread_setspecific (g_thread_create_key, new MacOSXDarwinThread(thread_name));
148    }
149}
150
151std::string
152Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
153{
154    std::string thread_name;
155#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
156    // We currently can only get the name of a thread in the current process.
157    if (pid == Host::GetCurrentProcessID())
158    {
159        char pthread_name[1024];
160        if (::pthread_getname_np (::pthread_from_mach_thread_np (tid), pthread_name, sizeof(pthread_name)) == 0)
161        {
162            if (pthread_name[0])
163            {
164                thread_name = pthread_name;
165            }
166        }
167        else
168        {
169            dispatch_queue_t current_queue = ::dispatch_get_current_queue ();
170            if (current_queue != NULL)
171            {
172                const char *queue_name = dispatch_queue_get_label (current_queue);
173                if (queue_name && queue_name[0])
174                {
175                    thread_name = queue_name;
176                }
177            }
178        }
179    }
180#endif
181    return thread_name;
182}
183
184bool
185Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle_directory)
186{
187#if defined (__APPLE__)
188    if (file.GetFileType () == FileSpec::eFileTypeDirectory)
189    {
190        char path[PATH_MAX];
191        if (file.GetPath(path, sizeof(path)))
192        {
193            CFCBundle bundle (path);
194            if (bundle.GetPath (path, sizeof(path)))
195            {
196                bundle_directory.SetFile (path, false);
197                return true;
198            }
199        }
200    }
201#endif
202    bundle_directory.Clear();
203    return false;
204}
205
206
207bool
208Host::ResolveExecutableInBundle (FileSpec &file)
209{
210#if defined (__APPLE__)
211    if (file.GetFileType () == FileSpec::eFileTypeDirectory)
212    {
213        char path[PATH_MAX];
214        if (file.GetPath(path, sizeof(path)))
215        {
216            CFCBundle bundle (path);
217            CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
218            if (url.get())
219            {
220                if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
221                {
222                    file.SetFile(path, false);
223                    return true;
224                }
225            }
226        }
227    }
228#endif
229  return false;
230}
231
232lldb::pid_t
233Host::LaunchApplication (const FileSpec &app_file_spec)
234{
235#if defined (__arm__)
236    return LLDB_INVALID_PROCESS_ID;
237#else
238    char app_path[PATH_MAX];
239    app_file_spec.GetPath(app_path, sizeof(app_path));
240
241    LSApplicationParameters app_params;
242    ::memset (&app_params, 0, sizeof (app_params));
243    app_params.flags = kLSLaunchDefaults | 
244                       kLSLaunchDontAddToRecents | 
245                       kLSLaunchNewInstance;
246    
247    
248    FSRef app_fsref;
249    CFCString app_cfstr (app_path, kCFStringEncodingUTF8);
250    
251    OSStatus error = ::FSPathMakeRef ((const UInt8 *)app_path, &app_fsref, NULL);
252    
253    // If we found the app, then store away the name so we don't have to re-look it up.
254    if (error != noErr)
255        return LLDB_INVALID_PROCESS_ID;
256    
257    app_params.application = &app_fsref;
258
259    ProcessSerialNumber psn;
260
261    error = ::LSOpenApplication (&app_params, &psn);
262
263    if (error != noErr)
264        return LLDB_INVALID_PROCESS_ID;
265
266    ::pid_t pid = LLDB_INVALID_PROCESS_ID;
267    error = ::GetProcessPID(&psn, &pid);
268    if (error != noErr)
269        return LLDB_INVALID_PROCESS_ID;
270    return pid;
271#endif
272}
273
274
275static void *
276AcceptPIDFromInferior (void *arg)
277{
278    const char *connect_url = (const char *)arg;
279    ConnectionFileDescriptor file_conn;
280    Error error;
281    if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
282    {
283        char pid_str[256];
284        ::memset (pid_str, 0, sizeof(pid_str));
285        ConnectionStatus status;
286        const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
287        if (pid_str_len > 0)
288        {
289            int pid = atoi (pid_str);
290            return (void *)(intptr_t)pid;
291        }
292    }
293    return NULL;
294}
295
296static bool
297WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
298{
299    const int time_delta_usecs = 100000;
300    const int num_retries = timeout_in_seconds/time_delta_usecs;
301    for (int i=0; i<num_retries; i++)
302    {
303        struct proc_bsdinfo bsd_info;
304        int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO, 
305                                    (uint64_t) 0, 
306                                    &bsd_info, 
307                                    PROC_PIDTBSDINFO_SIZE);
308        
309        switch (error)
310        {
311        case EINVAL:
312        case ENOTSUP:
313        case ESRCH:
314        case EPERM:
315            return false;
316        
317        default:
318            break;
319
320        case 0:
321            if (bsd_info.pbi_status == SSTOP)
322                return true;
323        }
324        ::usleep (time_delta_usecs);
325    }
326    return false;
327}
328#if !defined(__arm__)
329
330//static lldb::pid_t
331//LaunchInNewTerminalWithCommandFile 
332//(
333//    const char **argv, 
334//    const char **envp,
335//    const char *working_dir,
336//    const ArchSpec *arch_spec,
337//    bool stop_at_entry,
338//    bool disable_aslr
339//)
340//{
341//    if (!argv || !argv[0])
342//        return LLDB_INVALID_PROCESS_ID;
343//
344//    OSStatus error = 0;
345//    
346//    FileSpec program (argv[0], false);
347//    
348//    
349//    std::string unix_socket_name;
350//
351//    char temp_file_path[PATH_MAX];
352//    const char *tmpdir = ::getenv ("TMPDIR");
353//    if (tmpdir == NULL)
354//        tmpdir = "/tmp/";
355//    ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString());
356//    
357//    if (::mktemp (temp_file_path) == NULL)
358//        return LLDB_INVALID_PROCESS_ID;
359//
360//    unix_socket_name.assign (temp_file_path);
361//
362//    ::strlcat (temp_file_path, ".command", sizeof (temp_file_path));
363//
364//    StreamFile command_file;
365//    command_file.GetFile().Open (temp_file_path, 
366//                                 File::eOpenOptionWrite | File::eOpenOptionCanCreate,
367//                                 File::ePermissionsDefault);
368//    
369//    if (!command_file.GetFile().IsValid())
370//        return LLDB_INVALID_PROCESS_ID;
371//    
372//    FileSpec darwin_debug_file_spec;
373//    if (!Host::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
374//        return LLDB_INVALID_PROCESS_ID;
375//    darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
376//        
377//    if (!darwin_debug_file_spec.Exists())
378//        return LLDB_INVALID_PROCESS_ID;
379//    
380//    char launcher_path[PATH_MAX];
381//    darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
382//    command_file.Printf("\"%s\" ", launcher_path);
383//    
384//    command_file.Printf("--unix-socket=%s ", unix_socket_name.c_str());
385//    
386//    if (arch_spec && arch_spec->IsValid())
387//    {
388//        command_file.Printf("--arch=%s ", arch_spec->GetArchitectureName());
389//    }
390//
391//    if (disable_aslr)
392//    {
393//        command_file.PutCString("--disable-aslr ");
394//    }
395//        
396//    command_file.PutCString("-- ");
397//
398//    if (argv)
399//    {
400//        for (size_t i=0; argv[i] != NULL; ++i)
401//        {
402//            command_file.Printf("\"%s\" ", argv[i]);
403//        }
404//    }
405//    command_file.PutCString("\necho Process exited with status $?\n");
406//    command_file.GetFile().Close();
407//    if (::chmod (temp_file_path, S_IRWXU | S_IRWXG) != 0)
408//        return LLDB_INVALID_PROCESS_ID;
409//            
410//    CFCMutableDictionary cf_env_dict;
411//    
412//    const bool can_create = true;
413//    if (envp)
414//    {
415//        for (size_t i=0; envp[i] != NULL; ++i)
416//        {
417//            const char *env_entry = envp[i];            
418//            const char *equal_pos = strchr(env_entry, '=');
419//            if (equal_pos)
420//            {
421//                std::string env_key (env_entry, equal_pos);
422//                std::string env_val (equal_pos + 1);
423//                CFCString cf_env_key (env_key.c_str(), kCFStringEncodingUTF8);
424//                CFCString cf_env_val (env_val.c_str(), kCFStringEncodingUTF8);
425//                cf_env_dict.AddValue (cf_env_key.get(), cf_env_val.get(), can_create);
426//            }
427//        }
428//    }
429//    
430//    LSApplicationParameters app_params;
431//    ::memset (&app_params, 0, sizeof (app_params));
432//    app_params.flags = kLSLaunchDontAddToRecents | kLSLaunchAsync;
433//    app_params.argv = NULL;
434//    app_params.environment = (CFDictionaryRef)cf_env_dict.get();
435//
436//    CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL, 
437//                                                                                       (const UInt8 *)temp_file_path, 
438//                                                                                       strlen(temp_file_path),
439//                                                                                       false));
440//    
441//    CFCMutableArray urls;
442//    
443//    // Terminal.app will open the ".command" file we have created
444//    // and run our process inside it which will wait at the entry point
445//    // for us to attach.
446//    urls.AppendValue(command_file_url.get());
447//
448//
449//    lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
450//
451//    Error lldb_error;
452//    // Sleep and wait a bit for debugserver to start to listen...
453//    char connect_url[128];
454//    ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name.c_str());
455//
456//    // Spawn a new thread to accept incoming connection on the connect_url
457//    // so we can grab the pid from the inferior
458//    lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name.c_str(),
459//                                                       AcceptPIDFromInferior,
460//                                                       connect_url,
461//                                                       &lldb_error);
462//    
463//    ProcessSerialNumber psn;
464//    error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1);
465//    if (error == noErr)
466//    {
467//        thread_result_t accept_thread_result = NULL;
468//        if (Host::ThreadJoin (accept_thread, &accept_thread_result, &lldb_error))
469//        {
470//            if (accept_thread_result)
471//            {
472//                pid = (intptr_t)accept_thread_result;
473//            
474//                // Wait for process to be stopped the the entry point by watching
475//                // for the process status to be set to SSTOP which indicates it it
476//                // SIGSTOP'ed at the entry point
477//                WaitForProcessToSIGSTOP (pid, 5);
478//            }
479//        }
480//    }
481//    else
482//    {
483//        Host::ThreadCancel (accept_thread, &lldb_error);
484//    }
485//
486//    return pid;
487//}
488
489const char *applscript_in_new_tty = 
490"tell application \"Terminal\"\n"
491"	do script \"%s\"\n"
492"end tell\n";
493
494
495const char *applscript_in_existing_tty = "\
496set the_shell_script to \"%s\"\n\
497tell application \"Terminal\"\n\
498	repeat with the_window in (get windows)\n\
499		repeat with the_tab in tabs of the_window\n\
500			set the_tty to tty in the_tab\n\
501			if the_tty contains \"%s\" then\n\
502				if the_tab is not busy then\n\
503					set selected of the_tab to true\n\
504					set frontmost of the_window to true\n\
505					do script the_shell_script in the_tab\n\
506					return\n\
507				end if\n\
508			end if\n\
509		end repeat\n\
510	end repeat\n\
511	do script the_shell_script\n\
512end tell\n";
513
514
515static Error
516LaunchInNewTerminalWithAppleScript (const char *exe_path, ProcessLaunchInfo &launch_info)
517{
518    Error error;
519    char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";    
520    if (::mktemp (unix_socket_name) == NULL)
521    {
522        error.SetErrorString ("failed to make temporary path for a unix socket");
523        return error;
524    }
525    
526    StreamString command;
527    FileSpec darwin_debug_file_spec;
528    if (!Host::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
529    {
530        error.SetErrorString ("can't locate the 'darwin-debug' executable");
531        return error;
532    }
533
534    darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
535        
536    if (!darwin_debug_file_spec.Exists())
537    {
538        error.SetErrorStringWithFormat ("the 'darwin-debug' executable doesn't exists at '%s'", 
539                                        darwin_debug_file_spec.GetPath().c_str());
540        return error;
541    }
542    
543    char launcher_path[PATH_MAX];
544    darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
545
546    const ArchSpec &arch_spec = launch_info.GetArchitecture();
547    if (arch_spec.IsValid())
548        command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());
549
550    command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name);
551
552    if (arch_spec.IsValid())
553        command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
554
555    const char *working_dir = launch_info.GetWorkingDirectory();
556    if (working_dir)
557        command.Printf(" --working-dir '%s'", working_dir);
558    else
559    {
560        char cwd[PATH_MAX];
561        if (getcwd(cwd, PATH_MAX))
562            command.Printf(" --working-dir '%s'", cwd);
563    }
564    
565    if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
566        command.PutCString(" --disable-aslr");
567    
568    // We are launching on this host in a terminal. So compare the environemnt on the host
569    // to what is supplied in the launch_info. Any items that aren't in the host environemnt
570    // need to be sent to darwin-debug. If we send all environment entries, we might blow the
571    // max command line length, so we only send user modified entries.
572    const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector ();
573    StringList host_env;
574    const size_t host_env_count = Host::GetEnvironment (host_env);
575    const char *env_entry;
576    for (size_t env_idx = 0; (env_entry = envp[env_idx]) != NULL; ++env_idx)
577    {
578        bool add_entry = true;
579        for (size_t i=0; i<host_env_count; ++i)
580        {
581            const char *host_env_entry = host_env.GetStringAtIndex(i);
582            if (strcmp(env_entry, host_env_entry) == 0)
583            {
584                add_entry = false;
585                break;
586            }
587        }
588        if (add_entry)
589        {
590            command.Printf(" --env='%s'", env_entry);
591        }
592    }
593
594    command.PutCString(" -- ");
595
596    const char **argv = launch_info.GetArguments().GetConstArgumentVector ();
597    if (argv)
598    {
599        for (size_t i=0; argv[i] != NULL; ++i)
600        {
601            if (i==0)
602                command.Printf(" '%s'", exe_path);
603            else
604                command.Printf(" '%s'", argv[i]);
605        }
606    }
607    else
608    {
609        command.Printf(" '%s'", exe_path);
610    }
611    command.PutCString (" ; echo Process exited with status $?");
612    
613    StreamString applescript_source;
614
615    const char *tty_command = command.GetString().c_str();
616//    if (tty_name && tty_name[0])
617//    {
618//        applescript_source.Printf (applscript_in_existing_tty, 
619//                                   tty_command,
620//                                   tty_name);
621//    }
622//    else
623//    {
624        applescript_source.Printf (applscript_in_new_tty, 
625                                   tty_command);
626//    }
627
628    
629
630    const char *script_source = applescript_source.GetString().c_str();
631    //puts (script_source);
632    NSAppleScript* applescript = [[NSAppleScript alloc] initWithSource:[NSString stringWithCString:script_source encoding:NSUTF8StringEncoding]];
633
634    lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
635
636    Error lldb_error;
637    // Sleep and wait a bit for debugserver to start to listen...
638    ConnectionFileDescriptor file_conn;
639    char connect_url[128];
640    ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
641
642    // Spawn a new thread to accept incoming connection on the connect_url
643    // so we can grab the pid from the inferior. We have to do this because we
644    // are sending an AppleScript that will launch a process in Terminal.app,
645    // in a shell and the shell will fork/exec a couple of times before we get
646    // to the process that we wanted to launch. So when our process actually
647    // gets launched, we will handshake with it and get the process ID for it.
648    lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name,
649                                                       AcceptPIDFromInferior,
650                                                       connect_url,
651                                                       &lldb_error);
652    
653
654    [applescript executeAndReturnError:nil];
655    
656    thread_result_t accept_thread_result = NULL;
657    if (Host::ThreadJoin (accept_thread, &accept_thread_result, &lldb_error))
658    {
659        if (accept_thread_result)
660        {
661            pid = (intptr_t)accept_thread_result;
662        
663            // Wait for process to be stopped the the entry point by watching
664            // for the process status to be set to SSTOP which indicates it it
665            // SIGSTOP'ed at the entry point
666            WaitForProcessToSIGSTOP (pid, 5);
667        }
668    }
669    ::unlink (unix_socket_name);
670    [applescript release];
671    if (pid != LLDB_INVALID_PROCESS_ID)
672        launch_info.SetProcessID (pid);
673    return error;
674}
675
676#endif // #if !defined(__arm__)
677
678
679// On MacOSX CrashReporter will display a string for each shared library if
680// the shared library has an exported symbol named "__crashreporter_info__".
681
682static Mutex&
683GetCrashReporterMutex ()
684{
685    static Mutex g_mutex;
686    return g_mutex;
687}
688
689extern "C" {
690    const char *__crashreporter_info__ = NULL;
691}
692
693asm(".desc ___crashreporter_info__, 0x10");
694
695void
696Host::SetCrashDescriptionWithFormat (const char *format, ...)
697{
698    static StreamString g_crash_description;
699    Mutex::Locker locker (GetCrashReporterMutex ());
700    
701    if (format)
702    {
703        va_list args;
704        va_start (args, format);
705        g_crash_description.GetString().clear();
706        g_crash_description.PrintfVarArg(format, args);
707        va_end (args);
708        __crashreporter_info__ = g_crash_description.GetData();
709    }
710    else
711    {
712        __crashreporter_info__ = NULL;
713    }
714}
715
716void
717Host::SetCrashDescription (const char *cstr)
718{
719    Mutex::Locker locker (GetCrashReporterMutex ());
720    static std::string g_crash_description;
721    if (cstr)
722    {
723        g_crash_description.assign (cstr);
724        __crashreporter_info__ = g_crash_description.c_str();
725    }
726    else
727    {
728        __crashreporter_info__ = NULL;
729    }
730}
731
732bool
733Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
734{
735#if defined(__arm__)
736    return false;
737#else
738    // We attach this to an 'odoc' event to specify a particular selection
739    typedef struct {
740        int16_t   reserved0;  // must be zero
741        int16_t   fLineNumber;
742        int32_t   fSelStart;
743        int32_t   fSelEnd;
744        uint32_t  reserved1;  // must be zero
745        uint32_t  reserved2;  // must be zero
746    } BabelAESelInfo;
747    
748    Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
749    char file_path[PATH_MAX];
750    file_spec.GetPath(file_path, PATH_MAX);
751    CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
752    CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL, 
753                                                                     file_cfstr.get(), 
754                                                                     kCFURLPOSIXPathStyle, 
755                                                                     false));
756                                                                     
757    if (log)
758        log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
759    
760    long error;	
761    BabelAESelInfo file_and_line_info = 
762    {
763        0,                         // reserved0
764        (int16_t)(line_no - 1),    // fLineNumber (zero based line number)
765        1,                         // fSelStart
766        1024,                      // fSelEnd
767        0,                         // reserved1
768        0                          // reserved2
769    };
770
771    AEKeyDesc file_and_line_desc;
772    
773    error = ::AECreateDesc (typeUTF8Text, 
774                            &file_and_line_info, 
775                            sizeof (file_and_line_info), 
776                            &(file_and_line_desc.descContent));
777    
778    if (error != noErr)
779    {
780        if (log)
781            log->Printf("Error creating AEDesc: %ld.\n", error);
782        return false;
783    }
784    
785    file_and_line_desc.descKey = keyAEPosition;
786    
787    static std::string g_app_name;
788    static FSRef g_app_fsref;
789
790    LSApplicationParameters app_params;
791    ::memset (&app_params, 0, sizeof (app_params));
792    app_params.flags = kLSLaunchDefaults | 
793                       kLSLaunchDontAddToRecents | 
794                       kLSLaunchDontSwitch;
795    
796    char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
797    
798    if (external_editor)
799    {
800        if (log)
801            log->Printf("Looking for external editor \"%s\".\n", external_editor);
802
803        if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
804        {
805            CFCString editor_name (external_editor, kCFStringEncodingUTF8);
806            error = ::LSFindApplicationForInfo (kLSUnknownCreator, 
807                                                NULL, 
808                                                editor_name.get(), 
809                                                &g_app_fsref, 
810                                                NULL);
811            
812            // If we found the app, then store away the name so we don't have to re-look it up.
813            if (error != noErr)
814            {
815                if (log)
816                    log->Printf("Could not find External Editor application, error: %ld.\n", error);
817                return false;
818            }
819                
820        }
821        app_params.application = &g_app_fsref;
822    }
823
824    ProcessSerialNumber psn;
825    CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
826    error = ::LSOpenURLsWithRole (file_array.get(), 
827                                  kLSRolesAll, 
828                                  &file_and_line_desc, 
829                                  &app_params, 
830                                  &psn, 
831                                  1);
832    
833    AEDisposeDesc (&(file_and_line_desc.descContent));
834
835    if (error != noErr)
836    {
837        if (log)
838            log->Printf("LSOpenURLsWithRole failed, error: %ld.\n", error);
839
840        return false;
841    }
842    
843    ProcessInfoRec which_process;
844    ::memset(&which_process, 0, sizeof(which_process));
845    unsigned char ap_name[PATH_MAX];
846    which_process.processName = ap_name;
847    error = ::GetProcessInformation (&psn, &which_process);
848    
849    bool using_xcode;
850    if (error != noErr)
851    {
852        if (log)
853            log->Printf("GetProcessInformation failed, error: %ld.\n", error);
854        using_xcode = false;
855    }
856    else
857        using_xcode = strncmp((char *) ap_name+1, "Xcode", (int) ap_name[0]) == 0;
858    
859    // Xcode doesn't obey the line number in the Open Apple Event.  So I have to send
860    // it an AppleScript to focus on the right line.
861    
862    if (using_xcode)
863    {
864        static ComponentInstance osa_component = NULL;
865        static const char *as_template = "tell application \"Xcode\"\n"
866                                   "set doc to the first document whose path is \"%s\"\n"
867                                   "set the selection to paragraph %d of doc\n"
868                                   "--- set the selected paragraph range to {%d, %d} of doc\n"
869                                   "end tell\n";
870        const int chars_for_int = 32;
871        static int as_template_len = strlen (as_template);
872
873      
874        char *as_str;
875        AEDesc as_desc;
876      
877        if (osa_component == NULL)
878        {
879            osa_component = ::OpenDefaultComponent (kOSAComponentType,
880                                                    kAppleScriptSubtype);
881        }
882        
883        if (osa_component == NULL)
884        {
885            if (log)
886                log->Printf("Could not get default AppleScript component.\n");
887            return false;
888        }
889
890        uint32_t as_str_size = as_template_len + strlen (file_path) + 3 * chars_for_int + 1;     
891        as_str = (char *) malloc (as_str_size);
892        ::snprintf (as_str, 
893                    as_str_size - 1, 
894                    as_template, 
895                    file_path, 
896                    line_no, 
897                    line_no, 
898                    line_no);
899
900        error = ::AECreateDesc (typeChar, 
901                                as_str, 
902                                strlen (as_str),
903                                &as_desc);
904        
905        ::free (as_str);
906
907        if (error != noErr)
908        {
909            if (log)
910                log->Printf("Failed to create AEDesc for Xcode AppleEvent: %ld.\n", error);
911            return false;
912        }
913            
914        OSAID ret_OSAID;
915        error = ::OSACompileExecute (osa_component, 
916                                     &as_desc, 
917                                     kOSANullScript, 
918                                     kOSAModeNeverInteract, 
919                                     &ret_OSAID);
920        
921        ::OSADispose (osa_component, ret_OSAID);
922
923        ::AEDisposeDesc (&as_desc);
924
925        if (error != noErr)
926        {
927            if (log)
928                log->Printf("Sending AppleEvent to Xcode failed, error: %ld.\n", error);
929            return false;
930        }
931    }
932    return true;
933#endif // #if !defined(__arm__)
934}
935
936
937void
938Host::Backtrace (Stream &strm, uint32_t max_frames)
939{
940    if (max_frames > 0)
941    {
942        std::vector<void *> frame_buffer (max_frames, NULL);
943        int num_frames = ::backtrace (&frame_buffer[0], frame_buffer.size());
944        char** strs = ::backtrace_symbols (&frame_buffer[0], num_frames);
945        if (strs)
946        {
947            // Start at 1 to skip the "Host::Backtrace" frame
948            for (int i = 1; i < num_frames; ++i)
949                strm.Printf("%s\n", strs[i]);
950            ::free (strs);
951        }
952    }
953}
954
955size_t
956Host::GetEnvironment (StringList &env)
957{
958    char **host_env = *_NSGetEnviron();
959    char *env_entry;
960    size_t i;
961    for (i=0; (env_entry = host_env[i]) != NULL; ++i)
962        env.AppendString(env_entry);
963    return i;
964        
965}
966
967
968bool
969Host::GetOSBuildString (std::string &s)
970{
971    int mib[2] = { CTL_KERN, KERN_OSVERSION };
972    char cstr[PATH_MAX];
973    size_t cstr_len = sizeof(cstr);
974    if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
975    {
976        s.assign (cstr, cstr_len);
977        return true;
978    }
979    
980    s.clear();
981    return false;
982}
983
984bool
985Host::GetOSKernelDescription (std::string &s)
986{
987    int mib[2] = { CTL_KERN, KERN_VERSION };
988    char cstr[PATH_MAX];
989    size_t cstr_len = sizeof(cstr);
990    if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
991    {
992        s.assign (cstr, cstr_len);
993        return true;
994    }
995    s.clear();
996    return false;
997}
998    
999#include <libxml/parser.h>
1000#include <libxml/tree.h>
1001
1002bool
1003Host::GetOSVersion 
1004(
1005    uint32_t &major, 
1006    uint32_t &minor, 
1007    uint32_t &update
1008)
1009{
1010    static const char *version_plist_file = "/System/Library/CoreServices/SystemVersion.plist";
1011    char buffer[256];
1012    const char *product_version_str = NULL;
1013    
1014    CFCReleaser<CFURLRef> plist_url(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
1015                                                                            (UInt8 *) version_plist_file,
1016                                                                            strlen (version_plist_file), NO));
1017    if (plist_url.get())
1018    {
1019        CFCReleaser<CFPropertyListRef> property_list;
1020        CFCReleaser<CFStringRef>       error_string;
1021        CFCReleaser<CFDataRef>         resource_data;
1022        SInt32                         error_code;
1023 
1024        // Read the XML file.
1025        if (CFURLCreateDataAndPropertiesFromResource (kCFAllocatorDefault,
1026                                                      plist_url.get(),
1027                                                      resource_data.ptr_address(),
1028                                                      NULL,
1029                                                      NULL,
1030                                                      &error_code))
1031        {
1032               // Reconstitute the dictionary using the XML data.
1033            property_list = CFPropertyListCreateFromXMLData (kCFAllocatorDefault,
1034                                                              resource_data.get(),
1035                                                              kCFPropertyListImmutable,
1036                                                              error_string.ptr_address());
1037            if (CFGetTypeID(property_list.get()) == CFDictionaryGetTypeID())
1038            {
1039                CFDictionaryRef property_dict = (CFDictionaryRef) property_list.get();
1040                CFStringRef product_version_key = CFSTR("ProductVersion");
1041                CFPropertyListRef product_version_value;
1042                product_version_value = CFDictionaryGetValue(property_dict, product_version_key);
1043                if (product_version_value && CFGetTypeID(product_version_value) == CFStringGetTypeID())
1044                {
1045                    CFStringRef product_version_cfstr = (CFStringRef) product_version_value;
1046                    product_version_str = CFStringGetCStringPtr(product_version_cfstr, kCFStringEncodingUTF8);
1047                    if (product_version_str != NULL) {
1048                        if (CFStringGetCString(product_version_cfstr, buffer, 256, kCFStringEncodingUTF8))
1049                            product_version_str = buffer;
1050                    }
1051                }
1052            }
1053        }
1054    }
1055    
1056
1057    if (product_version_str)
1058    {
1059        Args::StringToVersion(product_version_str, major, minor, update);
1060        return true;
1061    }
1062    else
1063        return false;
1064
1065}
1066
1067static bool
1068GetMacOSXProcessName (const ProcessInstanceInfoMatch *match_info_ptr,
1069                      ProcessInstanceInfo &process_info)
1070{
1071    if (process_info.ProcessIDIsValid())
1072    {
1073        char process_name[MAXCOMLEN * 2 + 1];
1074        int name_len = ::proc_name(process_info.GetProcessID(), process_name, MAXCOMLEN * 2);
1075        if (name_len == 0)
1076            return false;
1077        
1078        if (match_info_ptr == NULL || NameMatches(process_name,
1079                                                  match_info_ptr->GetNameMatchType(),
1080                                                  match_info_ptr->GetProcessInfo().GetName()))
1081        {
1082            process_info.GetExecutableFile().SetFile (process_name, false);
1083            return true;
1084        }
1085    }
1086    process_info.GetExecutableFile().Clear();
1087    return false;
1088}
1089
1090
1091static bool
1092GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info)
1093{
1094    if (process_info.ProcessIDIsValid())
1095    {
1096        // Make a new mib to stay thread safe
1097        int mib[CTL_MAXNAME]={0,};
1098        size_t mib_len = CTL_MAXNAME;
1099        if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len)) 
1100            return false;
1101    
1102        mib[mib_len] = process_info.GetProcessID();
1103        mib_len++;
1104    
1105        cpu_type_t cpu, sub = 0;
1106        size_t len = sizeof(cpu);
1107        if (::sysctl (mib, mib_len, &cpu, &len, 0, 0) == 0)
1108        {
1109            switch (cpu)
1110            {
1111                case llvm::MachO::CPUTypeI386:      sub = llvm::MachO::CPUSubType_I386_ALL;     break;
1112                case llvm::MachO::CPUTypeX86_64:    sub = llvm::MachO::CPUSubType_X86_64_ALL;   break;
1113                case llvm::MachO::CPUTypeARM:
1114                    {
1115                        uint32_t cpusubtype = 0;
1116                        len = sizeof(cpusubtype);
1117                        if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
1118                            sub = cpusubtype;
1119                    }
1120                    break;
1121
1122                default:
1123                    break;
1124            }
1125            process_info.GetArchitecture ().SetArchitecture (eArchTypeMachO, cpu, sub);
1126            return true;
1127        }
1128    }
1129    process_info.GetArchitecture().Clear();
1130    return false;
1131}
1132
1133static bool
1134GetMacOSXProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
1135                      ProcessInstanceInfo &process_info)
1136{
1137    if (process_info.ProcessIDIsValid())
1138    {
1139        int proc_args_mib[3] = { CTL_KERN, KERN_PROCARGS2, (int)process_info.GetProcessID() };
1140
1141        char arg_data[8192];
1142        size_t arg_data_size = sizeof(arg_data);
1143        if (::sysctl (proc_args_mib, 3, arg_data, &arg_data_size , NULL, 0) == 0)
1144        {
1145            DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
1146            lldb::offset_t offset = 0;
1147            uint32_t argc = data.GetU32 (&offset);
1148            const char *cstr;
1149            
1150            cstr = data.GetCStr (&offset);
1151            if (cstr)
1152            {
1153                process_info.GetExecutableFile().SetFile(cstr, false);
1154
1155                if (match_info_ptr == NULL || 
1156                    NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
1157                                 match_info_ptr->GetNameMatchType(),
1158                                 match_info_ptr->GetProcessInfo().GetName()))
1159                {
1160                    // Skip NULLs
1161                    while (1)
1162                    {
1163                        const uint8_t *p = data.PeekData(offset, 1);
1164                        if ((p == NULL) || (*p != '\0'))
1165                            break;
1166                        ++offset;
1167                    }
1168                    // Now extract all arguments
1169                    Args &proc_args = process_info.GetArguments();
1170                    for (int i=0; i<argc; ++i)
1171                    {
1172                        cstr = data.GetCStr(&offset);
1173                        if (cstr)
1174                            proc_args.AppendArgument(cstr);
1175                    }
1176                    return true;
1177                }
1178            }
1179        }
1180    }
1181    return false;
1182}
1183
1184static bool
1185GetMacOSXProcessUserAndGroup (ProcessInstanceInfo &process_info)
1186{
1187    if (process_info.ProcessIDIsValid())
1188    {
1189        int mib[4];
1190        mib[0] = CTL_KERN;
1191        mib[1] = KERN_PROC;
1192        mib[2] = KERN_PROC_PID;
1193        mib[3] = process_info.GetProcessID();
1194        struct kinfo_proc proc_kinfo;
1195        size_t proc_kinfo_size = sizeof(struct kinfo_proc);
1196
1197        if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
1198        {
1199            if (proc_kinfo_size > 0)
1200            {
1201                process_info.SetParentProcessID (proc_kinfo.kp_eproc.e_ppid);
1202                process_info.SetUserID (proc_kinfo.kp_eproc.e_pcred.p_ruid);
1203                process_info.SetGroupID (proc_kinfo.kp_eproc.e_pcred.p_rgid);
1204                process_info.SetEffectiveUserID (proc_kinfo.kp_eproc.e_ucred.cr_uid);
1205                if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
1206                    process_info.SetEffectiveGroupID (proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
1207                else
1208                    process_info.SetEffectiveGroupID (UINT32_MAX);            
1209                return true;
1210            }
1211        }
1212    }
1213    process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
1214    process_info.SetUserID (UINT32_MAX);
1215    process_info.SetGroupID (UINT32_MAX);
1216    process_info.SetEffectiveUserID (UINT32_MAX);
1217    process_info.SetEffectiveGroupID (UINT32_MAX);            
1218    return false;
1219}
1220
1221
1222uint32_t
1223Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
1224{
1225    std::vector<struct kinfo_proc> kinfos;
1226    
1227    int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
1228    
1229    size_t pid_data_size = 0;
1230    if (::sysctl (mib, 4, NULL, &pid_data_size, NULL, 0) != 0)
1231        return 0;
1232    
1233    // Add a few extra in case a few more show up
1234    const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
1235
1236    kinfos.resize (estimated_pid_count);
1237    pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
1238    
1239    if (::sysctl (mib, 4, &kinfos[0], &pid_data_size, NULL, 0) != 0)
1240        return 0;
1241
1242    const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
1243
1244    bool all_users = match_info.GetMatchAllUsers();
1245    const lldb::pid_t our_pid = getpid();
1246    const uid_t our_uid = getuid();
1247    for (int i = 0; i < actual_pid_count; i++)
1248    {
1249        const struct kinfo_proc &kinfo = kinfos[i];
1250        
1251        bool kinfo_user_matches = false;
1252        if (all_users)
1253            kinfo_user_matches = true;
1254        else
1255            kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
1256
1257        // Special case, if lldb is being run as root we can attach to anything.
1258        if (our_uid == 0)
1259          kinfo_user_matches = true;
1260
1261        if (kinfo_user_matches == false         || // Make sure the user is acceptable
1262            kinfo.kp_proc.p_pid == our_pid      || // Skip this process
1263            kinfo.kp_proc.p_pid == 0            || // Skip kernel (kernel pid is zero)
1264            kinfo.kp_proc.p_stat == SZOMB       || // Zombies are bad, they like brains...
1265            kinfo.kp_proc.p_flag & P_TRACED     || // Being debugged?
1266            kinfo.kp_proc.p_flag & P_WEXIT      || // Working on exiting?
1267            kinfo.kp_proc.p_flag & P_TRANSLATED)   // Skip translated ppc (Rosetta)
1268            continue;
1269
1270        ProcessInstanceInfo process_info;
1271        process_info.SetProcessID (kinfo.kp_proc.p_pid);
1272        process_info.SetParentProcessID (kinfo.kp_eproc.e_ppid);
1273        process_info.SetUserID (kinfo.kp_eproc.e_pcred.p_ruid);
1274        process_info.SetGroupID (kinfo.kp_eproc.e_pcred.p_rgid);
1275        process_info.SetEffectiveUserID (kinfo.kp_eproc.e_ucred.cr_uid);
1276        if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
1277            process_info.SetEffectiveGroupID (kinfo.kp_eproc.e_ucred.cr_groups[0]);
1278        else
1279            process_info.SetEffectiveGroupID (UINT32_MAX);            
1280
1281        // Make sure our info matches before we go fetch the name and cpu type
1282        if (match_info.Matches (process_info))
1283        {
1284            if (GetMacOSXProcessArgs (&match_info, process_info))
1285            {
1286                GetMacOSXProcessCPUType (process_info);
1287                if (match_info.Matches (process_info))
1288                    process_infos.Append (process_info);
1289            }
1290        }
1291    }    
1292    return process_infos.GetSize();
1293}
1294
1295bool
1296Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
1297{
1298    process_info.SetProcessID(pid);
1299    bool success = false;
1300    
1301    if (GetMacOSXProcessArgs (NULL, process_info))
1302        success = true;
1303    
1304    if (GetMacOSXProcessCPUType (process_info))
1305        success = true;
1306    
1307    if (GetMacOSXProcessUserAndGroup (process_info))
1308        success = true;
1309    
1310    if (success)
1311        return true;
1312    
1313    process_info.Clear();
1314    return false;
1315}
1316
1317static short
1318GetPosixspawnFlags (ProcessLaunchInfo &launch_info)
1319{
1320    short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
1321    if (launch_info.GetFlags().Test (eLaunchFlagExec))
1322        flags |= POSIX_SPAWN_SETEXEC;           // Darwin specific posix_spawn flag
1323    
1324    if (launch_info.GetFlags().Test (eLaunchFlagDebug))
1325        flags |= POSIX_SPAWN_START_SUSPENDED;   // Darwin specific posix_spawn flag
1326    
1327    if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
1328        flags |= _POSIX_SPAWN_DISABLE_ASLR;     // Darwin specific posix_spawn flag
1329        
1330    if (launch_info.GetLaunchInSeparateProcessGroup())
1331        flags |= POSIX_SPAWN_SETPGROUP;
1332    
1333//#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
1334//    // Close all files exception those with file actions if this is supported.
1335//    flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;       
1336//#endif
1337    
1338    return flags;
1339}
1340
1341#if !NO_XPC_SERVICES
1342static void
1343PackageXPCArguments (xpc_object_t message, const char *prefix, const Args& args)
1344{
1345    size_t count = args.GetArgumentCount();
1346    char buf[50]; // long enough for 'argXXX'
1347    memset(buf, 0, 50);
1348    sprintf(buf, "%sCount", prefix);
1349	xpc_dictionary_set_int64(message, buf, count);
1350    for (int i=0; i<count; i++) {
1351        memset(buf, 0, 50);
1352        sprintf(buf, "%s%i", prefix, i);
1353        xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
1354    }
1355}
1356
1357/*
1358 A valid authorizationRef means that 
1359    - there is the LaunchUsingXPCRightName rights in the /etc/authorization
1360    - we have successfully copied the rights to be send over the XPC wire
1361 Once obtained, it will be valid for as long as the process lives.
1362 */
1363static AuthorizationRef authorizationRef = NULL;
1364static Error
1365getXPCAuthorization (ProcessLaunchInfo &launch_info)
1366{
1367    Error error;
1368    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1369    
1370    if ((launch_info.GetUserID() == 0) && !authorizationRef)
1371    {
1372        OSStatus createStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
1373        if (createStatus != errAuthorizationSuccess)
1374        {
1375            error.SetError(1, eErrorTypeGeneric);
1376            error.SetErrorString("Can't create authorizationRef.");
1377            if (log)
1378            {
1379                error.PutToLog(log, "%s", error.AsCString());
1380            }
1381            return error;
1382        }
1383        
1384        OSStatus rightsStatus = AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
1385        if (rightsStatus != errAuthorizationSuccess)
1386        {
1387            // No rights in the security database, Create it with the right prompt.
1388            CFStringRef prompt = CFSTR("Xcode is trying to take control of a root process.");
1389            CFStringRef keys[] = { CFSTR("en") };
1390            CFTypeRef values[] = { prompt };
1391            CFDictionaryRef promptDict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1392            
1393            CFStringRef keys1[] = { CFSTR("class"), CFSTR("group"), CFSTR("comment"),               CFSTR("default-prompt"), CFSTR("shared") };
1394            CFTypeRef values1[] = { CFSTR("user"),  CFSTR("admin"), CFSTR(LaunchUsingXPCRightName), promptDict,              kCFBooleanFalse };
1395            CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1396            rightsStatus = AuthorizationRightSet(authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
1397            CFRelease(promptDict);
1398            CFRelease(dict);
1399        }
1400            
1401        OSStatus copyRightStatus = errAuthorizationDenied;
1402        if (rightsStatus == errAuthorizationSuccess)
1403        {
1404            AuthorizationItem item1 = { LaunchUsingXPCRightName, 0, NULL, 0 };
1405            AuthorizationItem items[] = {item1};
1406            AuthorizationRights requestedRights = {1, items };
1407            AuthorizationFlags authorizationFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
1408            copyRightStatus = AuthorizationCopyRights(authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment, authorizationFlags, NULL);
1409        }
1410        
1411        if (copyRightStatus != errAuthorizationSuccess)
1412        {
1413            // Eventually when the commandline supports running as root and the user is not
1414            // logged in in the current audit session, we will need the trick in gdb where
1415            // we ask the user to type in the root passwd in the terminal.
1416            error.SetError(2, eErrorTypeGeneric);
1417            error.SetErrorStringWithFormat("Launching as root needs root authorization.");
1418            if (log)
1419            {
1420                error.PutToLog(log, "%s", error.AsCString());
1421            }
1422            
1423            if (authorizationRef)
1424            {
1425                AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1426                authorizationRef = NULL;
1427            }
1428        }
1429    }
1430
1431    return error;
1432}
1433#endif
1434
1435static Error
1436LaunchProcessXPC (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid)
1437{
1438#if !NO_XPC_SERVICES
1439    Error error = getXPCAuthorization(launch_info);
1440    if (error.Fail())
1441        return error;
1442    
1443    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1444    
1445    uid_t requested_uid = launch_info.GetUserID();
1446    const char *xpc_service  = nil;
1447    bool send_auth = false;
1448    AuthorizationExternalForm extForm;
1449    if ((requested_uid == UINT32_MAX) || (requested_uid == Host::GetEffectiveUserID()))
1450    {
1451        xpc_service = "com.apple.lldb.launcherXPCService";
1452    }
1453    else if (requested_uid == 0)
1454    {
1455        if (AuthorizationMakeExternalForm(authorizationRef, &extForm) == errAuthorizationSuccess)
1456        {
1457            send_auth = true;
1458        }
1459        else
1460        {
1461            error.SetError(3, eErrorTypeGeneric);
1462            error.SetErrorStringWithFormat("Launching root via XPC needs to externalize authorization reference.");
1463            if (log)
1464            {
1465                error.PutToLog(log, "%s", error.AsCString());
1466            }
1467            return error;
1468        }
1469        xpc_service = "com.apple.lldb.launcherRootXPCService";
1470    }
1471    else
1472    {
1473        error.SetError(4, eErrorTypeGeneric);
1474        error.SetErrorStringWithFormat("Launching via XPC is only currently available for either the login user or root.");
1475        if (log)
1476        {
1477            error.PutToLog(log, "%s", error.AsCString());
1478        }
1479        return error;
1480    }
1481    
1482    xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
1483    
1484	xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
1485        xpc_type_t	type = xpc_get_type(event);
1486        
1487        if (type == XPC_TYPE_ERROR) {
1488            if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
1489                // The service has either canceled itself, crashed, or been terminated.
1490                // The XPC connection is still valid and sending a message to it will re-launch the service.
1491                // If the service is state-full, this is the time to initialize the new service.
1492                return;
1493            } else if (event == XPC_ERROR_CONNECTION_INVALID) {
1494                // The service is invalid. Either the service name supplied to xpc_connection_create() is incorrect
1495                // or we (this process) have canceled the service; we can do any cleanup of appliation state at this point.
1496                // printf("Service disconnected");
1497                return;
1498            } else {
1499                // printf("Unexpected error from service: %s", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
1500            }
1501            
1502        } else {
1503            // printf("Received unexpected event in handler");
1504        }
1505    });
1506    
1507    xpc_connection_set_finalizer_f (conn, xpc_finalizer_t(xpc_release));
1508	xpc_connection_resume (conn);
1509    xpc_object_t message = xpc_dictionary_create (nil, nil, 0);
1510    
1511    if (send_auth)
1512    {
1513        xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes, sizeof(AuthorizationExternalForm));
1514    }
1515    
1516    PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey, launch_info.GetArguments());
1517    PackageXPCArguments(message, LauncherXPCServiceEnvPrefxKey, launch_info.GetEnvironmentEntries());
1518    
1519    // Posix spawn stuff.
1520    xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey, launch_info.GetArchitecture().GetMachOCPUType());
1521    xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey, GetPosixspawnFlags(launch_info));
1522    
1523    xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, message);
1524    xpc_type_t returnType = xpc_get_type(reply);
1525    if (returnType == XPC_TYPE_DICTIONARY)
1526    {
1527        pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
1528        if (pid == 0)
1529        {
1530            int errorType = xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
1531            int errorCode = xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
1532            
1533            error.SetError(errorCode, eErrorTypeGeneric);
1534            error.SetErrorStringWithFormat("Problems with launching via XPC. Error type : %i, code : %i", errorType, errorCode);
1535            if (log)
1536            {
1537                error.PutToLog(log, "%s", error.AsCString());
1538            }
1539            
1540            if (authorizationRef)
1541            {
1542                AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1543                authorizationRef = NULL;
1544            }
1545        }
1546    }
1547    else if (returnType == XPC_TYPE_ERROR)
1548    {
1549        error.SetError(5, eErrorTypeGeneric);
1550        error.SetErrorStringWithFormat("Problems with launching via XPC. XPC error : %s", xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
1551        if (log)
1552        {
1553            error.PutToLog(log, "%s", error.AsCString());
1554        }
1555    }
1556    
1557    return error;
1558#else
1559    Error error;
1560    return error;
1561#endif
1562}
1563
1564static Error
1565LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid)
1566{
1567    Error error;
1568    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1569    
1570    posix_spawnattr_t attr;
1571    error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
1572    
1573    if (error.Fail() || log)
1574        error.PutToLog(log, "::posix_spawnattr_init ( &attr )");
1575    if (error.Fail())
1576        return error;
1577
1578    // Make a quick class that will cleanup the posix spawn attributes in case
1579    // we return in the middle of this function.
1580    lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy);
1581    
1582    sigset_t no_signals;
1583    sigset_t all_signals;
1584    sigemptyset (&no_signals);
1585    sigfillset (&all_signals);
1586    ::posix_spawnattr_setsigmask(&attr, &no_signals);
1587    ::posix_spawnattr_setsigdefault(&attr, &all_signals);
1588
1589    short flags = GetPosixspawnFlags(launch_info);
1590    error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX);
1591    if (error.Fail() || log)
1592        error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags);
1593    if (error.Fail())
1594        return error;
1595    
1596#if !defined(__arm__)
1597    
1598    // We don't need to do this for ARM, and we really shouldn't now that we
1599    // have multiple CPU subtypes and no posix_spawnattr call that allows us
1600    // to set which CPU subtype to launch...
1601    const ArchSpec &arch_spec = launch_info.GetArchitecture();
1602    cpu_type_t cpu = arch_spec.GetMachOCPUType();
1603    if (cpu != 0 && 
1604        cpu != UINT32_MAX && 
1605        cpu != LLDB_INVALID_CPUTYPE)
1606    {
1607        size_t ocount = 0;
1608        error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
1609        if (error.Fail() || log)
1610            error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu, (uint64_t)ocount);
1611        
1612        if (error.Fail() || ocount != 1)
1613            return error;
1614    }
1615    
1616#endif
1617    
1618    const char *tmp_argv[2];
1619    char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector();
1620    char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector();
1621    if (argv == NULL)
1622    {
1623        // posix_spawn gets very unhappy if it doesn't have at least the program
1624        // name in argv[0]. One of the side affects I have noticed is the environment
1625        // variables don't make it into the child process if "argv == NULL"!!!
1626        tmp_argv[0] = exe_path;
1627        tmp_argv[1] = NULL;
1628        argv = (char * const*)tmp_argv;
1629    }
1630
1631    const char *working_dir = launch_info.GetWorkingDirectory();
1632    if (working_dir)
1633    {
1634        // No more thread specific current working directory
1635        if (__pthread_chdir (working_dir) < 0) {
1636            if (errno == ENOENT) {
1637                error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
1638            } else if (errno == ENOTDIR) {
1639                error.SetErrorStringWithFormat("Path doesn't name a directory: %s", working_dir);
1640            } else {
1641                error.SetErrorStringWithFormat("An unknown error occurred when changing directory for process execution.");
1642            }
1643            return error;
1644        }
1645    }
1646    
1647    const size_t num_file_actions = launch_info.GetNumFileActions ();
1648    if (num_file_actions > 0)
1649    {
1650        posix_spawn_file_actions_t file_actions;
1651        error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
1652        if (error.Fail() || log)
1653            error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )");
1654        if (error.Fail())
1655            return error;
1656
1657        // Make a quick class that will cleanup the posix spawn attributes in case
1658        // we return in the middle of this function.
1659        lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> posix_spawn_file_actions_cleanup (&file_actions, posix_spawn_file_actions_destroy);
1660
1661        for (size_t i=0; i<num_file_actions; ++i)
1662        {
1663            const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
1664            if (launch_file_action)
1665            {
1666                if (!ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions,
1667                                                                             launch_file_action,
1668                                                                             log,
1669                                                                             error))
1670                    return error;
1671            }
1672        }
1673        
1674        error.SetError (::posix_spawnp (&pid, 
1675                                        exe_path, 
1676                                        &file_actions, 
1677                                        &attr, 
1678                                        argv,
1679                                        envp),
1680                        eErrorTypePOSIX);
1681
1682        if (error.Fail() || log)
1683        {
1684            error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )",
1685                           pid, 
1686                           exe_path, 
1687                           &file_actions, 
1688                           &attr, 
1689                           argv, 
1690                           envp);
1691            if (log)
1692            {
1693                for (int ii=0; argv[ii]; ++ii)
1694                    log->Printf("argv[%i] = '%s'", ii, argv[ii]);
1695            }
1696        }
1697
1698    }
1699    else
1700    {
1701        error.SetError (::posix_spawnp (&pid, 
1702                                        exe_path, 
1703                                        NULL, 
1704                                        &attr, 
1705                                        argv,
1706                                        envp),
1707                        eErrorTypePOSIX);
1708
1709        if (error.Fail() || log)
1710        {
1711            error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )",
1712                           pid, 
1713                           exe_path, 
1714                           &attr, 
1715                           argv, 
1716                           envp);
1717            if (log)
1718            {
1719                for (int ii=0; argv[ii]; ++ii)
1720                    log->Printf("argv[%i] = '%s'", ii, argv[ii]);
1721            }
1722        }
1723    }
1724    
1725    if (working_dir)
1726    {
1727        // No more thread specific current working directory
1728        __pthread_fchdir (-1);
1729    }
1730    
1731    return error;
1732}
1733
1734static bool
1735ShouldLaunchUsingXPC(const char *exe_path, ProcessLaunchInfo &launch_info)
1736{
1737    bool result = false;
1738
1739#if !NO_XPC_SERVICES    
1740    const char *debugserver = "/debugserver";
1741    int len = strlen(debugserver);
1742    int exe_len = strlen(exe_path);
1743    if (exe_len >= len)
1744    {
1745        const char *part = exe_path + (exe_len - len);
1746        if (strcmp(part, debugserver) == 0)
1747        {
1748            // We are dealing with debugserver.
1749            uid_t requested_uid = launch_info.GetUserID();
1750            if (requested_uid == 0)
1751            {
1752                // Launching XPC works for root. It also works for the non-attaching case for current login
1753                // but unfortunately, we can't detect it here.
1754                result = true;
1755            }
1756        }
1757    }
1758#endif
1759    
1760    return result;
1761}
1762
1763Error
1764Host::LaunchProcess (ProcessLaunchInfo &launch_info)
1765{
1766    Error error;
1767    char exe_path[PATH_MAX];
1768    PlatformSP host_platform_sp (Platform::GetDefaultPlatform ());
1769    
1770    const ArchSpec &arch_spec = launch_info.GetArchitecture();
1771    
1772    FileSpec exe_spec(launch_info.GetExecutableFile());
1773    
1774    FileSpec::FileType file_type = exe_spec.GetFileType();
1775    if (file_type != FileSpec::eFileTypeRegular)
1776    {
1777        lldb::ModuleSP exe_module_sp;
1778        error = host_platform_sp->ResolveExecutable (exe_spec,
1779                                                     arch_spec,
1780                                                     exe_module_sp,
1781                                                     NULL);
1782        
1783        if (error.Fail())
1784            return error;
1785        
1786        if (exe_module_sp)
1787            exe_spec = exe_module_sp->GetFileSpec();
1788    }
1789    
1790    if (exe_spec.Exists())
1791    {
1792        exe_spec.GetPath (exe_path, sizeof(exe_path));
1793    }
1794    else
1795    {
1796        launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
1797        error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
1798        return error;
1799    }
1800    
1801    if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
1802    {
1803#if !defined(__arm__)
1804        return LaunchInNewTerminalWithAppleScript (exe_path, launch_info);
1805#else
1806        error.SetErrorString ("launching a processs in a new terminal is not supported on iOS devices");
1807        return error;
1808#endif
1809    }
1810    
1811    ::pid_t pid = LLDB_INVALID_PROCESS_ID;
1812    
1813    if (ShouldLaunchUsingXPC(exe_path, launch_info))
1814    {
1815        error = LaunchProcessXPC(exe_path, launch_info, pid);
1816    }
1817    else
1818    {
1819        error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
1820    }
1821    
1822    if (pid != LLDB_INVALID_PROCESS_ID)
1823    {
1824        // If all went well, then set the process ID into the launch info
1825        launch_info.SetProcessID(pid);
1826        
1827        // Make sure we reap any processes we spawn or we will have zombies.
1828        if (!launch_info.MonitorProcess())
1829        {
1830            const bool monitor_signals = false;
1831            StartMonitoringChildProcess (Process::SetProcessExitStatus, 
1832                                         NULL, 
1833                                         pid, 
1834                                         monitor_signals);
1835        }
1836    }
1837    else
1838    {
1839        // Invalid process ID, something didn't go well
1840        if (error.Success())
1841            error.SetErrorString ("process launch failed for unknown reasons");
1842    }
1843    return error;
1844}
1845
1846lldb::thread_t
1847Host::StartMonitoringChildProcess (Host::MonitorChildProcessCallback callback,
1848                                   void *callback_baton,
1849                                   lldb::pid_t pid,
1850                                   bool monitor_signals)
1851{
1852    lldb::thread_t thread = LLDB_INVALID_HOST_THREAD;
1853    unsigned long mask = DISPATCH_PROC_EXIT;
1854    if (monitor_signals)
1855        mask |= DISPATCH_PROC_SIGNAL;
1856
1857    Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
1858
1859
1860    dispatch_source_t source = ::dispatch_source_create (DISPATCH_SOURCE_TYPE_PROC, 
1861                                                         pid, 
1862                                                         mask, 
1863                                                         ::dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0));
1864
1865    if (log)
1866        log->Printf ("Host::StartMonitoringChildProcess (callback=%p, baton=%p, pid=%i, monitor_signals=%i) source = %p\n", 
1867                     callback, 
1868                     callback_baton, 
1869                     (int)pid, 
1870                     monitor_signals, 
1871                     source);
1872
1873    if (source)
1874    {
1875        ::dispatch_source_set_cancel_handler (source, ^{
1876            ::dispatch_release (source);
1877        });
1878        ::dispatch_source_set_event_handler (source, ^{
1879            
1880            int status= 0;
1881            int wait_pid = 0;
1882            bool cancel = false;
1883            bool exited = false;
1884            do
1885            {
1886                wait_pid = ::waitpid (pid, &status, 0);
1887            } while (wait_pid < 0 && errno == EINTR);
1888
1889            if (wait_pid >= 0)
1890            {
1891                int signal = 0;
1892                int exit_status = 0;
1893                const char *status_cstr = NULL;
1894                if (WIFSTOPPED(status))
1895                {
1896                    signal = WSTOPSIG(status);
1897                    status_cstr = "STOPPED";
1898                }
1899                else if (WIFEXITED(status))
1900                {
1901                    exit_status = WEXITSTATUS(status);
1902                    status_cstr = "EXITED";
1903                    exited = true;
1904                }
1905                else if (WIFSIGNALED(status))
1906                {
1907                    signal = WTERMSIG(status);
1908                    status_cstr = "SIGNALED";
1909                    exited = true;
1910                    exit_status = -1;
1911                }
1912                else
1913                {
1914                    status_cstr = "???";
1915                }
1916
1917                if (log)
1918                    log->Printf ("::waitpid (pid = %llu, &status, 0) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_status = %i",
1919                                 pid,
1920                                 wait_pid,
1921                                 status,
1922                                 status_cstr,
1923                                 signal,
1924                                 exit_status);
1925                
1926                if (callback)
1927                    cancel = callback (callback_baton, pid, exited, signal, exit_status);
1928                
1929                if (exited || cancel)
1930                {
1931                    ::dispatch_source_cancel(source);
1932                }
1933            }
1934        });
1935
1936        ::dispatch_resume (source);
1937    }
1938    return thread;
1939}
1940
1941//----------------------------------------------------------------------
1942// Log to both stderr and to ASL Logging when running on MacOSX.
1943//----------------------------------------------------------------------
1944void
1945Host::SystemLog (SystemLogType type, const char *format, va_list args)
1946{
1947    if (format && format[0])
1948    {
1949        static aslmsg g_aslmsg = NULL;
1950        if (g_aslmsg == NULL)
1951        {
1952            g_aslmsg = ::asl_new (ASL_TYPE_MSG);
1953            char asl_key_sender[PATH_MAX];
1954            snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.LLDB.framework");
1955            ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
1956        }
1957        
1958        // Copy the va_list so we can log this message twice
1959        va_list copy_args;
1960        va_copy (copy_args, args);
1961        // Log to stderr
1962        ::vfprintf (stderr, format, copy_args);
1963        va_end (copy_args);
1964
1965        int asl_level;
1966        switch (type)
1967        {
1968            case eSystemLogError:
1969                asl_level = ASL_LEVEL_ERR;
1970                break;
1971                
1972            case eSystemLogWarning:
1973                asl_level = ASL_LEVEL_WARNING;
1974                break;
1975        }
1976        
1977        // Log to ASL
1978        ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
1979    }
1980}
1981
1982lldb::DataBufferSP
1983Host::GetAuxvData(lldb_private::Process *process)
1984{
1985    return lldb::DataBufferSP();
1986}
1987