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