1//===-- Host.mm -------------------------------------------------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "lldb/Host/Host.h" 10 11#include <AvailabilityMacros.h> 12#include <TargetConditionals.h> 13 14#if TARGET_OS_OSX 15#define __XPC_PRIVATE_H__ 16#include <xpc/xpc.h> 17 18#define LaunchUsingXPCRightName "com.apple.lldb.RootDebuggingXPCService" 19 20// These XPC messaging keys are used for communication between Host.mm and the 21// XPC service. 22#define LauncherXPCServiceAuthKey "auth-key" 23#define LauncherXPCServiceArgPrefxKey "arg" 24#define LauncherXPCServiceEnvPrefxKey "env" 25#define LauncherXPCServiceCPUTypeKey "cpuType" 26#define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags" 27#define LauncherXPCServiceStdInPathKeyKey "stdInPath" 28#define LauncherXPCServiceStdOutPathKeyKey "stdOutPath" 29#define LauncherXPCServiceStdErrPathKeyKey "stdErrPath" 30#define LauncherXPCServiceChildPIDKey "childPID" 31#define LauncherXPCServiceErrorTypeKey "errorType" 32#define LauncherXPCServiceCodeTypeKey "errorCode" 33 34#endif 35 36#include "llvm/Support/Host.h" 37 38#include <asl.h> 39#include <crt_externs.h> 40#include <grp.h> 41#include <libproc.h> 42#include <pwd.h> 43#include <spawn.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <sys/proc.h> 47#include <sys/stat.h> 48#include <sys/sysctl.h> 49#include <sys/types.h> 50#include <unistd.h> 51 52#include "lldb/Host/ConnectionFileDescriptor.h" 53#include "lldb/Host/FileSystem.h" 54#include "lldb/Host/HostInfo.h" 55#include "lldb/Host/ProcessLaunchInfo.h" 56#include "lldb/Host/ThreadLauncher.h" 57#include "lldb/Utility/ArchSpec.h" 58#include "lldb/Utility/DataBufferHeap.h" 59#include "lldb/Utility/DataExtractor.h" 60#include "lldb/Utility/Endian.h" 61#include "lldb/Utility/FileSpec.h" 62#include "lldb/Utility/Log.h" 63#include "lldb/Utility/NameMatches.h" 64#include "lldb/Utility/ProcessInfo.h" 65#include "lldb/Utility/StreamString.h" 66#include "lldb/Utility/StructuredData.h" 67#include "lldb/lldb-defines.h" 68 69#include "llvm/ADT/ScopeExit.h" 70#include "llvm/Support/Errno.h" 71#include "llvm/Support/FileSystem.h" 72 73#include "../cfcpp/CFCBundle.h" 74#include "../cfcpp/CFCMutableArray.h" 75#include "../cfcpp/CFCMutableDictionary.h" 76#include "../cfcpp/CFCReleaser.h" 77#include "../cfcpp/CFCString.h" 78 79#include <objc/objc-auto.h> 80 81#include <CoreFoundation/CoreFoundation.h> 82#include <Foundation/Foundation.h> 83 84#ifndef _POSIX_SPAWN_DISABLE_ASLR 85#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 86#endif 87 88extern "C" { 89int __pthread_chdir(const char *path); 90int __pthread_fchdir(int fildes); 91} 92 93using namespace lldb; 94using namespace lldb_private; 95 96bool Host::GetBundleDirectory(const FileSpec &file, 97 FileSpec &bundle_directory) { 98#if defined(__APPLE__) 99 if (FileSystem::Instance().IsDirectory(file)) { 100 char path[PATH_MAX]; 101 if (file.GetPath(path, sizeof(path))) { 102 CFCBundle bundle(path); 103 if (bundle.GetPath(path, sizeof(path))) { 104 bundle_directory.SetFile(path, FileSpec::Style::native); 105 return true; 106 } 107 } 108 } 109#endif 110 bundle_directory.Clear(); 111 return false; 112} 113 114bool Host::ResolveExecutableInBundle(FileSpec &file) { 115#if defined(__APPLE__) 116 if (FileSystem::Instance().IsDirectory(file)) { 117 char path[PATH_MAX]; 118 if (file.GetPath(path, sizeof(path))) { 119 CFCBundle bundle(path); 120 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL()); 121 if (url.get()) { 122 if (::CFURLGetFileSystemRepresentation(url.get(), YES, (UInt8 *)path, 123 sizeof(path))) { 124 file.SetFile(path, FileSpec::Style::native); 125 return true; 126 } 127 } 128 } 129 } 130#endif 131 return false; 132} 133 134#if TARGET_OS_OSX 135 136static void *AcceptPIDFromInferior(void *arg) { 137 const char *connect_url = (const char *)arg; 138 ConnectionFileDescriptor file_conn; 139 Status error; 140 if (file_conn.Connect(connect_url, &error) == eConnectionStatusSuccess) { 141 char pid_str[256]; 142 ::memset(pid_str, 0, sizeof(pid_str)); 143 ConnectionStatus status; 144 const size_t pid_str_len = file_conn.Read( 145 pid_str, sizeof(pid_str), std::chrono::seconds(0), status, NULL); 146 if (pid_str_len > 0) { 147 int pid = atoi(pid_str); 148 return (void *)(intptr_t)pid; 149 } 150 } 151 return NULL; 152} 153 154const char *applscript_in_new_tty = "tell application \"Terminal\"\n" 155 " activate\n" 156 " do script \"/bin/bash -c '%s';exit\"\n" 157 "end tell\n"; 158 159const char *applscript_in_existing_tty = "\ 160set the_shell_script to \"/bin/bash -c '%s';exit\"\n\ 161tell application \"Terminal\"\n\ 162 repeat with the_window in (get windows)\n\ 163 repeat with the_tab in tabs of the_window\n\ 164 set the_tty to tty in the_tab\n\ 165 if the_tty contains \"%s\" then\n\ 166 if the_tab is not busy then\n\ 167 set selected of the_tab to true\n\ 168 set frontmost of the_window to true\n\ 169 do script the_shell_script in the_tab\n\ 170 return\n\ 171 end if\n\ 172 end if\n\ 173 end repeat\n\ 174 end repeat\n\ 175 do script the_shell_script\n\ 176end tell\n"; 177 178static Status 179LaunchInNewTerminalWithAppleScript(const char *exe_path, 180 ProcessLaunchInfo &launch_info) { 181 Status error; 182 char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX"; 183 if (::mktemp(unix_socket_name) == NULL) { 184 error.SetErrorString("failed to make temporary path for a unix socket"); 185 return error; 186 } 187 188 StreamString command; 189 FileSpec darwin_debug_file_spec = HostInfo::GetSupportExeDir(); 190 if (!darwin_debug_file_spec) { 191 error.SetErrorString("can't locate the 'darwin-debug' executable"); 192 return error; 193 } 194 195 darwin_debug_file_spec.GetFilename().SetCString("darwin-debug"); 196 197 if (!FileSystem::Instance().Exists(darwin_debug_file_spec)) { 198 error.SetErrorStringWithFormat( 199 "the 'darwin-debug' executable doesn't exists at '%s'", 200 darwin_debug_file_spec.GetPath().c_str()); 201 return error; 202 } 203 204 char launcher_path[PATH_MAX]; 205 darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path)); 206 207 const ArchSpec &arch_spec = launch_info.GetArchitecture(); 208 // Only set the architecture if it is valid and if it isn't Haswell (x86_64h). 209 if (arch_spec.IsValid() && 210 arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h) 211 command.Printf("arch -arch %s ", arch_spec.GetArchitectureName()); 212 213 command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name); 214 215 if (arch_spec.IsValid()) 216 command.Printf(" --arch=%s", arch_spec.GetArchitectureName()); 217 218 FileSpec working_dir{launch_info.GetWorkingDirectory()}; 219 if (working_dir) 220 command.Printf(" --working-dir '%s'", working_dir.GetCString()); 221 else { 222 char cwd[PATH_MAX]; 223 if (getcwd(cwd, PATH_MAX)) 224 command.Printf(" --working-dir '%s'", cwd); 225 } 226 227 if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) 228 command.PutCString(" --disable-aslr"); 229 230 // We are launching on this host in a terminal. So compare the environment on 231 // the host to what is supplied in the launch_info. Any items that aren't in 232 // the host environment need to be sent to darwin-debug. If we send all 233 // environment entries, we might blow the max command line length, so we only 234 // send user modified entries. 235 Environment host_env = Host::GetEnvironment(); 236 237 for (const auto &KV : launch_info.GetEnvironment()) { 238 auto host_entry = host_env.find(KV.first()); 239 if (host_entry == host_env.end() || host_entry->second != KV.second) 240 command.Format(" --env='{0}'", Environment::compose(KV)); 241 } 242 243 command.PutCString(" -- "); 244 245 const char **argv = launch_info.GetArguments().GetConstArgumentVector(); 246 if (argv) { 247 for (size_t i = 0; argv[i] != NULL; ++i) { 248 if (i == 0) 249 command.Printf(" '%s'", exe_path); 250 else 251 command.Printf(" '%s'", argv[i]); 252 } 253 } else { 254 command.Printf(" '%s'", exe_path); 255 } 256 command.PutCString(" ; echo Process exited with status $?"); 257 if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit)) 258 command.PutCString(" ; exit"); 259 260 StreamString applescript_source; 261 262 applescript_source.Printf(applscript_in_new_tty, 263 command.GetString().str().c_str()); 264 NSAppleScript *applescript = [[NSAppleScript alloc] 265 initWithSource:[NSString stringWithCString:applescript_source.GetString() 266 .str() 267 .c_str() 268 encoding:NSUTF8StringEncoding]]; 269 270 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 271 272 Status lldb_error; 273 // Sleep and wait a bit for debugserver to start to listen... 274 ConnectionFileDescriptor file_conn; 275 char connect_url[128]; 276 ::snprintf(connect_url, sizeof(connect_url), "unix-accept://%s", 277 unix_socket_name); 278 279 // Spawn a new thread to accept incoming connection on the connect_url 280 // so we can grab the pid from the inferior. We have to do this because we 281 // are sending an AppleScript that will launch a process in Terminal.app, 282 // in a shell and the shell will fork/exec a couple of times before we get 283 // to the process that we wanted to launch. So when our process actually 284 // gets launched, we will handshake with it and get the process ID for it. 285 llvm::Expected<HostThread> accept_thread = ThreadLauncher::LaunchThread( 286 unix_socket_name, AcceptPIDFromInferior, connect_url); 287 288 if (!accept_thread) 289 return Status(accept_thread.takeError()); 290 291 [applescript executeAndReturnError:nil]; 292 293 thread_result_t accept_thread_result = NULL; 294 lldb_error = accept_thread->Join(&accept_thread_result); 295 if (lldb_error.Success() && accept_thread_result) { 296 pid = (intptr_t)accept_thread_result; 297 } 298 299 llvm::sys::fs::remove(unix_socket_name); 300 [applescript release]; 301 if (pid != LLDB_INVALID_PROCESS_ID) 302 launch_info.SetProcessID(pid); 303 return error; 304} 305 306#endif // TARGET_OS_OSX 307 308bool Host::OpenFileInExternalEditor(const FileSpec &file_spec, 309 uint32_t line_no) { 310#if !TARGET_OS_OSX 311 return false; 312#else // !TARGET_OS_OSX 313 // We attach this to an 'odoc' event to specify a particular selection 314 typedef struct { 315 int16_t reserved0; // must be zero 316 int16_t fLineNumber; 317 int32_t fSelStart; 318 int32_t fSelEnd; 319 uint32_t reserved1; // must be zero 320 uint32_t reserved2; // must be zero 321 } BabelAESelInfo; 322 323 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_HOST)); 324 char file_path[PATH_MAX]; 325 file_spec.GetPath(file_path, PATH_MAX); 326 CFCString file_cfstr(file_path, kCFStringEncodingUTF8); 327 CFCReleaser<CFURLRef> file_URL(::CFURLCreateWithFileSystemPath( 328 NULL, file_cfstr.get(), kCFURLPOSIXPathStyle, false)); 329 330 LLDB_LOGF(log, 331 "Sending source file: \"%s\" and line: %d to external editor.\n", 332 file_path, line_no); 333 334 long error; 335 BabelAESelInfo file_and_line_info = { 336 0, // reserved0 337 (int16_t)(line_no - 1), // fLineNumber (zero based line number) 338 1, // fSelStart 339 1024, // fSelEnd 340 0, // reserved1 341 0 // reserved2 342 }; 343 344 AEKeyDesc file_and_line_desc; 345 346 error = ::AECreateDesc(typeUTF8Text, &file_and_line_info, 347 sizeof(file_and_line_info), 348 &(file_and_line_desc.descContent)); 349 350 if (error != noErr) { 351 LLDB_LOGF(log, "Error creating AEDesc: %ld.\n", error); 352 return false; 353 } 354 355 file_and_line_desc.descKey = keyAEPosition; 356 357 static std::string g_app_name; 358 static FSRef g_app_fsref; 359 360 LSApplicationParameters app_params; 361 ::memset(&app_params, 0, sizeof(app_params)); 362 app_params.flags = 363 kLSLaunchDefaults | kLSLaunchDontAddToRecents | kLSLaunchDontSwitch; 364 365 char *external_editor = ::getenv("LLDB_EXTERNAL_EDITOR"); 366 367 if (external_editor) { 368 LLDB_LOGF(log, "Looking for external editor \"%s\".\n", external_editor); 369 370 if (g_app_name.empty() || 371 strcmp(g_app_name.c_str(), external_editor) != 0) { 372 CFCString editor_name(external_editor, kCFStringEncodingUTF8); 373 error = ::LSFindApplicationForInfo(kLSUnknownCreator, NULL, 374 editor_name.get(), &g_app_fsref, NULL); 375 376 // If we found the app, then store away the name so we don't have to 377 // re-look it up. 378 if (error != noErr) { 379 LLDB_LOGF(log, 380 "Could not find External Editor application, error: %ld.\n", 381 error); 382 return false; 383 } 384 } 385 app_params.application = &g_app_fsref; 386 } 387 388 ProcessSerialNumber psn; 389 CFCReleaser<CFArrayRef> file_array( 390 CFArrayCreate(NULL, (const void **)file_URL.ptr_address(false), 1, NULL)); 391 error = ::LSOpenURLsWithRole(file_array.get(), kLSRolesAll, 392 &file_and_line_desc, &app_params, &psn, 1); 393 394 AEDisposeDesc(&(file_and_line_desc.descContent)); 395 396 if (error != noErr) { 397 LLDB_LOGF(log, "LSOpenURLsWithRole failed, error: %ld.\n", error); 398 399 return false; 400 } 401 402 return true; 403#endif // TARGET_OS_OSX 404} 405 406Environment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); } 407 408static bool GetMacOSXProcessCPUType(ProcessInstanceInfo &process_info) { 409 if (process_info.ProcessIDIsValid()) { 410 // Make a new mib to stay thread safe 411 int mib[CTL_MAXNAME] = { 412 0, 413 }; 414 size_t mib_len = CTL_MAXNAME; 415 if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len)) 416 return false; 417 418 mib[mib_len] = process_info.GetProcessID(); 419 mib_len++; 420 421 cpu_type_t cpu, sub = 0; 422 size_t len = sizeof(cpu); 423 if (::sysctl(mib, mib_len, &cpu, &len, 0, 0) == 0) { 424 switch (cpu) { 425 case CPU_TYPE_I386: 426 sub = CPU_SUBTYPE_I386_ALL; 427 break; 428 case CPU_TYPE_X86_64: 429 sub = CPU_SUBTYPE_X86_64_ALL; 430 break; 431 432#if defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64_ALL) 433 case CPU_TYPE_ARM64: 434 sub = CPU_SUBTYPE_ARM64_ALL; 435 break; 436#endif 437 438#if defined(CPU_TYPE_ARM64_32) && defined(CPU_SUBTYPE_ARM64_32_ALL) 439 case CPU_TYPE_ARM64_32: 440 sub = CPU_SUBTYPE_ARM64_32_ALL; 441 break; 442#endif 443 444 case CPU_TYPE_ARM: { 445 // Note that we fetched the cpu type from the PROCESS but we can't get a 446 // cpusubtype of the 447 // process -- we can only get the host's cpu subtype. 448 uint32_t cpusubtype = 0; 449 len = sizeof(cpusubtype); 450 if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) 451 sub = cpusubtype; 452 453 bool host_cpu_is_64bit; 454 uint32_t is64bit_capable; 455 size_t is64bit_capable_len = sizeof(is64bit_capable); 456 host_cpu_is_64bit = 457 sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, 458 &is64bit_capable_len, NULL, 0) == 0; 459 460 // if the host is an armv8 device, its cpusubtype will be in 461 // CPU_SUBTYPE_ARM64 numbering 462 // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value 463 // instead. 464 465 if (host_cpu_is_64bit) { 466 sub = CPU_SUBTYPE_ARM_V7; 467 } 468 } break; 469 470 default: 471 break; 472 } 473 process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, sub); 474 return true; 475 } 476 } 477 process_info.GetArchitecture().Clear(); 478 return false; 479} 480 481static bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr, 482 ProcessInstanceInfo &process_info) { 483 if (process_info.ProcessIDIsValid()) { 484 int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2, 485 (int)process_info.GetProcessID()}; 486 487 size_t arg_data_size = 0; 488 if (::sysctl(proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) || 489 arg_data_size == 0) 490 arg_data_size = 8192; 491 492 // Add a few bytes to the calculated length, I know we need to add at least 493 // one byte 494 // to this number otherwise we get junk back, so add 128 just in case... 495 DataBufferHeap arg_data(arg_data_size + 128, 0); 496 arg_data_size = arg_data.GetByteSize(); 497 if (::sysctl(proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size, NULL, 498 0) == 0) { 499 DataExtractor data(arg_data.GetBytes(), arg_data_size, 500 endian::InlHostByteOrder(), sizeof(void *)); 501 lldb::offset_t offset = 0; 502 uint32_t argc = data.GetU32(&offset); 503 llvm::Triple &triple = process_info.GetArchitecture().GetTriple(); 504 const llvm::Triple::ArchType triple_arch = triple.getArch(); 505 const bool check_for_ios_simulator = 506 (triple_arch == llvm::Triple::x86 || 507 triple_arch == llvm::Triple::x86_64); 508 const char *cstr = data.GetCStr(&offset); 509 if (cstr) { 510 process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native); 511 512 if (match_info_ptr == NULL || 513 NameMatches( 514 process_info.GetExecutableFile().GetFilename().GetCString(), 515 match_info_ptr->GetNameMatchType(), 516 match_info_ptr->GetProcessInfo().GetName())) { 517 // Skip NULLs 518 while (true) { 519 const uint8_t *p = data.PeekData(offset, 1); 520 if ((p == NULL) || (*p != '\0')) 521 break; 522 ++offset; 523 } 524 // Now extract all arguments 525 Args &proc_args = process_info.GetArguments(); 526 for (int i = 0; i < static_cast<int>(argc); ++i) { 527 cstr = data.GetCStr(&offset); 528 if (cstr) 529 proc_args.AppendArgument(llvm::StringRef(cstr)); 530 } 531 532 Environment &proc_env = process_info.GetEnvironment(); 533 while ((cstr = data.GetCStr(&offset))) { 534 if (cstr[0] == '\0') 535 break; 536 537 if (check_for_ios_simulator) { 538 if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == 539 0) 540 process_info.GetArchitecture().GetTriple().setOS( 541 llvm::Triple::IOS); 542 else 543 process_info.GetArchitecture().GetTriple().setOS( 544 llvm::Triple::MacOSX); 545 } 546 547 proc_env.insert(cstr); 548 } 549 return true; 550 } 551 } 552 } 553 } 554 return false; 555} 556 557static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { 558 if (process_info.ProcessIDIsValid()) { 559 int mib[4]; 560 mib[0] = CTL_KERN; 561 mib[1] = KERN_PROC; 562 mib[2] = KERN_PROC_PID; 563 mib[3] = process_info.GetProcessID(); 564 struct kinfo_proc proc_kinfo; 565 size_t proc_kinfo_size = sizeof(struct kinfo_proc); 566 567 if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) { 568 if (proc_kinfo_size > 0) { 569 process_info.SetParentProcessID(proc_kinfo.kp_eproc.e_ppid); 570 process_info.SetUserID(proc_kinfo.kp_eproc.e_pcred.p_ruid); 571 process_info.SetGroupID(proc_kinfo.kp_eproc.e_pcred.p_rgid); 572 process_info.SetEffectiveUserID(proc_kinfo.kp_eproc.e_ucred.cr_uid); 573 if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0) 574 process_info.SetEffectiveGroupID( 575 proc_kinfo.kp_eproc.e_ucred.cr_groups[0]); 576 else 577 process_info.SetEffectiveGroupID(UINT32_MAX); 578 return true; 579 } 580 } 581 } 582 process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID); 583 process_info.SetUserID(UINT32_MAX); 584 process_info.SetGroupID(UINT32_MAX); 585 process_info.SetEffectiveUserID(UINT32_MAX); 586 process_info.SetEffectiveGroupID(UINT32_MAX); 587 return false; 588} 589 590uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, 591 ProcessInstanceInfoList &process_infos) { 592 std::vector<struct kinfo_proc> kinfos; 593 594 int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; 595 596 size_t pid_data_size = 0; 597 if (::sysctl(mib, 3, nullptr, &pid_data_size, nullptr, 0) != 0) 598 return 0; 599 600 // Add a few extra in case a few more show up 601 const size_t estimated_pid_count = 602 (pid_data_size / sizeof(struct kinfo_proc)) + 10; 603 604 kinfos.resize(estimated_pid_count); 605 pid_data_size = kinfos.size() * sizeof(struct kinfo_proc); 606 607 if (::sysctl(mib, 3, &kinfos[0], &pid_data_size, nullptr, 0) != 0) 608 return 0; 609 610 const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc)); 611 612 bool all_users = match_info.GetMatchAllUsers(); 613 const lldb::pid_t our_pid = getpid(); 614 const uid_t our_uid = getuid(); 615 for (size_t i = 0; i < actual_pid_count; i++) { 616 const struct kinfo_proc &kinfo = kinfos[i]; 617 618 bool kinfo_user_matches = false; 619 if (all_users) 620 kinfo_user_matches = true; 621 else 622 kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid; 623 624 // Special case, if lldb is being run as root we can attach to anything. 625 if (our_uid == 0) 626 kinfo_user_matches = true; 627 628 if (!kinfo_user_matches || // Make sure the user is acceptable 629 static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) == 630 our_pid || // Skip this process 631 kinfo.kp_proc.p_pid == 0 || // Skip kernel (kernel pid is zero) 632 kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains... 633 kinfo.kp_proc.p_flag & P_TRACED || // Being debugged? 634 kinfo.kp_proc.p_flag & P_WEXIT) 635 continue; 636 637 ProcessInstanceInfo process_info; 638 process_info.SetProcessID(kinfo.kp_proc.p_pid); 639 process_info.SetParentProcessID(kinfo.kp_eproc.e_ppid); 640 process_info.SetUserID(kinfo.kp_eproc.e_pcred.p_ruid); 641 process_info.SetGroupID(kinfo.kp_eproc.e_pcred.p_rgid); 642 process_info.SetEffectiveUserID(kinfo.kp_eproc.e_ucred.cr_uid); 643 if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0) 644 process_info.SetEffectiveGroupID(kinfo.kp_eproc.e_ucred.cr_groups[0]); 645 else 646 process_info.SetEffectiveGroupID(UINT32_MAX); 647 648 // Make sure our info matches before we go fetch the name and cpu type 649 if (!match_info.UserIDsMatch(process_info) || 650 !match_info.ProcessIDsMatch(process_info)) 651 continue; 652 653 // Get CPU type first so we can know to look for iOS simulator is we have 654 // x86 or x86_64 655 if (GetMacOSXProcessCPUType(process_info)) { 656 if (GetMacOSXProcessArgs(&match_info, process_info)) { 657 if (match_info.Matches(process_info)) 658 process_infos.push_back(process_info); 659 } 660 } 661 } 662 return process_infos.size(); 663} 664 665bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { 666 process_info.SetProcessID(pid); 667 bool success = false; 668 669 // Get CPU type first so we can know to look for iOS simulator is we have x86 670 // or x86_64 671 if (GetMacOSXProcessCPUType(process_info)) 672 success = true; 673 674 if (GetMacOSXProcessArgs(NULL, process_info)) 675 success = true; 676 677 if (GetMacOSXProcessUserAndGroup(process_info)) 678 success = true; 679 680 if (success) 681 return true; 682 683 process_info.Clear(); 684 return false; 685} 686 687#if TARGET_OS_OSX 688static void PackageXPCArguments(xpc_object_t message, const char *prefix, 689 const Args &args) { 690 size_t count = args.GetArgumentCount(); 691 char buf[50]; // long enough for 'argXXX' 692 memset(buf, 0, 50); 693 sprintf(buf, "%sCount", prefix); 694 xpc_dictionary_set_int64(message, buf, count); 695 for (size_t i = 0; i < count; i++) { 696 memset(buf, 0, 50); 697 sprintf(buf, "%s%zi", prefix, i); 698 xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i)); 699 } 700} 701 702static void PackageXPCEnvironment(xpc_object_t message, llvm::StringRef prefix, 703 const Environment &env) { 704 xpc_dictionary_set_int64(message, (prefix + "Count").str().c_str(), 705 env.size()); 706 size_t i = 0; 707 for (const auto &KV : env) { 708 xpc_dictionary_set_string(message, (prefix + llvm::Twine(i)).str().c_str(), 709 Environment::compose(KV).c_str()); 710 } 711} 712 713/* 714 A valid authorizationRef means that 715 - there is the LaunchUsingXPCRightName rights in the /etc/authorization 716 - we have successfully copied the rights to be send over the XPC wire 717 Once obtained, it will be valid for as long as the process lives. 718 */ 719static AuthorizationRef authorizationRef = NULL; 720static Status getXPCAuthorization(ProcessLaunchInfo &launch_info) { 721 Status error; 722 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST | 723 LIBLLDB_LOG_PROCESS)); 724 725 if ((launch_info.GetUserID() == 0) && !authorizationRef) { 726 OSStatus createStatus = 727 AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, 728 kAuthorizationFlagDefaults, &authorizationRef); 729 if (createStatus != errAuthorizationSuccess) { 730 error.SetError(1, eErrorTypeGeneric); 731 error.SetErrorString("Can't create authorizationRef."); 732 LLDB_LOG(log, "error: {0}", error); 733 return error; 734 } 735 736 OSStatus rightsStatus = 737 AuthorizationRightGet(LaunchUsingXPCRightName, NULL); 738 if (rightsStatus != errAuthorizationSuccess) { 739 // No rights in the security database, Create it with the right prompt. 740 CFStringRef prompt = 741 CFSTR("Xcode is trying to take control of a root process."); 742 CFStringRef keys[] = {CFSTR("en")}; 743 CFTypeRef values[] = {prompt}; 744 CFDictionaryRef promptDict = CFDictionaryCreate( 745 kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, 746 &kCFCopyStringDictionaryKeyCallBacks, 747 &kCFTypeDictionaryValueCallBacks); 748 749 CFStringRef keys1[] = {CFSTR("class"), CFSTR("group"), CFSTR("comment"), 750 CFSTR("default-prompt"), CFSTR("shared")}; 751 CFTypeRef values1[] = {CFSTR("user"), CFSTR("admin"), 752 CFSTR(LaunchUsingXPCRightName), promptDict, 753 kCFBooleanFalse}; 754 CFDictionaryRef dict = CFDictionaryCreate( 755 kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5, 756 &kCFCopyStringDictionaryKeyCallBacks, 757 &kCFTypeDictionaryValueCallBacks); 758 rightsStatus = AuthorizationRightSet( 759 authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL); 760 CFRelease(promptDict); 761 CFRelease(dict); 762 } 763 764 OSStatus copyRightStatus = errAuthorizationDenied; 765 if (rightsStatus == errAuthorizationSuccess) { 766 AuthorizationItem item1 = {LaunchUsingXPCRightName, 0, NULL, 0}; 767 AuthorizationItem items[] = {item1}; 768 AuthorizationRights requestedRights = {1, items}; 769 AuthorizationFlags authorizationFlags = 770 kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; 771 copyRightStatus = AuthorizationCopyRights( 772 authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment, 773 authorizationFlags, NULL); 774 } 775 776 if (copyRightStatus != errAuthorizationSuccess) { 777 // Eventually when the commandline supports running as root and the user 778 // is not 779 // logged in in the current audit session, we will need the trick in gdb 780 // where 781 // we ask the user to type in the root passwd in the terminal. 782 error.SetError(2, eErrorTypeGeneric); 783 error.SetErrorStringWithFormat( 784 "Launching as root needs root authorization."); 785 LLDB_LOG(log, "error: {0}", error); 786 787 if (authorizationRef) { 788 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); 789 authorizationRef = NULL; 790 } 791 } 792 } 793 794 return error; 795} 796#endif 797 798static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { 799 short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; 800 801 if (launch_info.GetFlags().Test(eLaunchFlagExec)) 802 flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag 803 804 if (launch_info.GetFlags().Test(eLaunchFlagDebug)) 805 flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag 806 807 if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) 808 flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag 809 810 if (launch_info.GetLaunchInSeparateProcessGroup()) 811 flags |= POSIX_SPAWN_SETPGROUP; 812 813#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT 814#if defined(__x86_64__) || defined(__i386__) 815 static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate; 816 if (g_use_close_on_exec_flag == eLazyBoolCalculate) { 817 g_use_close_on_exec_flag = eLazyBoolNo; 818 819 llvm::VersionTuple version = HostInfo::GetOSVersion(); 820 if (version > llvm::VersionTuple(10, 7)) { 821 // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or 822 // earlier 823 g_use_close_on_exec_flag = eLazyBoolYes; 824 } 825 } 826#else 827 static LazyBool g_use_close_on_exec_flag = eLazyBoolYes; 828#endif // defined(__x86_64__) || defined(__i386__) 829 // Close all files exception those with file actions if this is supported. 830 if (g_use_close_on_exec_flag == eLazyBoolYes) 831 flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; 832#endif // ifdef POSIX_SPAWN_CLOEXEC_DEFAULT 833 return flags; 834} 835 836static Status LaunchProcessXPC(const char *exe_path, 837 ProcessLaunchInfo &launch_info, 838 lldb::pid_t &pid) { 839#if TARGET_OS_OSX 840 Status error = getXPCAuthorization(launch_info); 841 if (error.Fail()) 842 return error; 843 844 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST | 845 LIBLLDB_LOG_PROCESS)); 846 847 uid_t requested_uid = launch_info.GetUserID(); 848 const char *xpc_service = nil; 849 bool send_auth = false; 850 AuthorizationExternalForm extForm; 851 if (requested_uid == 0) { 852 if (AuthorizationMakeExternalForm(authorizationRef, &extForm) == 853 errAuthorizationSuccess) { 854 send_auth = true; 855 } else { 856 error.SetError(3, eErrorTypeGeneric); 857 error.SetErrorStringWithFormat("Launching root via XPC needs to " 858 "externalize authorization reference."); 859 LLDB_LOG(log, "error: {0}", error); 860 return error; 861 } 862 xpc_service = LaunchUsingXPCRightName; 863 } else { 864 error.SetError(4, eErrorTypeGeneric); 865 error.SetErrorStringWithFormat( 866 "Launching via XPC is only currently available for root."); 867 LLDB_LOG(log, "error: {0}", error); 868 return error; 869 } 870 871 xpc_connection_t conn = xpc_connection_create(xpc_service, NULL); 872 873 xpc_connection_set_event_handler(conn, ^(xpc_object_t event) { 874 xpc_type_t type = xpc_get_type(event); 875 876 if (type == XPC_TYPE_ERROR) { 877 if (event == XPC_ERROR_CONNECTION_INTERRUPTED) { 878 // The service has either canceled itself, crashed, or been terminated. 879 // The XPC connection is still valid and sending a message to it will 880 // re-launch the service. 881 // If the service is state-full, this is the time to initialize the new 882 // service. 883 return; 884 } else if (event == XPC_ERROR_CONNECTION_INVALID) { 885 // The service is invalid. Either the service name supplied to 886 // xpc_connection_create() is incorrect 887 // or we (this process) have canceled the service; we can do any cleanup 888 // of application state at this point. 889 // printf("Service disconnected"); 890 return; 891 } else { 892 // printf("Unexpected error from service: %s", 893 // xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); 894 } 895 896 } else { 897 // printf("Received unexpected event in handler"); 898 } 899 }); 900 901 xpc_connection_set_finalizer_f(conn, xpc_finalizer_t(xpc_release)); 902 xpc_connection_resume(conn); 903 xpc_object_t message = xpc_dictionary_create(nil, nil, 0); 904 905 if (send_auth) { 906 xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes, 907 sizeof(AuthorizationExternalForm)); 908 } 909 910 PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey, 911 launch_info.GetArguments()); 912 PackageXPCEnvironment(message, LauncherXPCServiceEnvPrefxKey, 913 launch_info.GetEnvironment()); 914 915 // Posix spawn stuff. 916 xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey, 917 launch_info.GetArchitecture().GetMachOCPUType()); 918 xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey, 919 GetPosixspawnFlags(launch_info)); 920 const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO); 921 if (file_action && !file_action->GetPath().empty()) { 922 xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey, 923 file_action->GetPath().str().c_str()); 924 } 925 file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); 926 if (file_action && !file_action->GetPath().empty()) { 927 xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey, 928 file_action->GetPath().str().c_str()); 929 } 930 file_action = launch_info.GetFileActionForFD(STDERR_FILENO); 931 if (file_action && !file_action->GetPath().empty()) { 932 xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey, 933 file_action->GetPath().str().c_str()); 934 } 935 936 xpc_object_t reply = 937 xpc_connection_send_message_with_reply_sync(conn, message); 938 xpc_type_t returnType = xpc_get_type(reply); 939 if (returnType == XPC_TYPE_DICTIONARY) { 940 pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey); 941 if (pid == 0) { 942 int errorType = 943 xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey); 944 int errorCode = 945 xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey); 946 947 error.SetError(errorCode, eErrorTypeGeneric); 948 error.SetErrorStringWithFormat( 949 "Problems with launching via XPC. Error type : %i, code : %i", 950 errorType, errorCode); 951 LLDB_LOG(log, "error: {0}", error); 952 953 if (authorizationRef) { 954 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); 955 authorizationRef = NULL; 956 } 957 } 958 } else if (returnType == XPC_TYPE_ERROR) { 959 error.SetError(5, eErrorTypeGeneric); 960 error.SetErrorStringWithFormat( 961 "Problems with launching via XPC. XPC error : %s", 962 xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION)); 963 LLDB_LOG(log, "error: {0}", error); 964 } 965 966 return error; 967#else 968 Status error; 969 return error; 970#endif 971} 972 973static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, 974 Log *log, Status &error) { 975 if (info == NULL) 976 return false; 977 978 posix_spawn_file_actions_t *file_actions = 979 static_cast<posix_spawn_file_actions_t *>(_file_actions); 980 981 switch (info->GetAction()) { 982 case FileAction::eFileActionNone: 983 error.Clear(); 984 break; 985 986 case FileAction::eFileActionClose: 987 if (info->GetFD() == -1) 988 error.SetErrorString( 989 "invalid fd for posix_spawn_file_actions_addclose(...)"); 990 else { 991 error.SetError( 992 ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), 993 eErrorTypePOSIX); 994 if (error.Fail()) 995 LLDB_LOG(log, 996 "error: {0}, posix_spawn_file_actions_addclose " 997 "(action={1}, fd={2})", 998 error, file_actions, info->GetFD()); 999 } 1000 break; 1001 1002 case FileAction::eFileActionDuplicate: 1003 if (info->GetFD() == -1) 1004 error.SetErrorString( 1005 "invalid fd for posix_spawn_file_actions_adddup2(...)"); 1006 else if (info->GetActionArgument() == -1) 1007 error.SetErrorString( 1008 "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); 1009 else { 1010 error.SetError( 1011 ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), 1012 info->GetActionArgument()), 1013 eErrorTypePOSIX); 1014 if (error.Fail()) 1015 LLDB_LOG(log, 1016 "error: {0}, posix_spawn_file_actions_adddup2 " 1017 "(action={1}, fd={2}, dup_fd={3})", 1018 error, file_actions, info->GetFD(), info->GetActionArgument()); 1019 } 1020 break; 1021 1022 case FileAction::eFileActionOpen: 1023 if (info->GetFD() == -1) 1024 error.SetErrorString( 1025 "invalid fd in posix_spawn_file_actions_addopen(...)"); 1026 else { 1027 int oflag = info->GetActionArgument(); 1028 1029 mode_t mode = 0; 1030 1031 if (oflag & O_CREAT) 1032 mode = 0640; 1033 1034 error.SetError(::posix_spawn_file_actions_addopen( 1035 file_actions, info->GetFD(), 1036 info->GetPath().str().c_str(), oflag, mode), 1037 eErrorTypePOSIX); 1038 if (error.Fail()) 1039 LLDB_LOG(log, 1040 "error: {0}, posix_spawn_file_actions_addopen (action={1}, " 1041 "fd={2}, path='{3}', oflag={4}, mode={5})", 1042 error, file_actions, info->GetFD(), info->GetPath(), oflag, 1043 mode); 1044 } 1045 break; 1046 } 1047 return error.Success(); 1048} 1049 1050static Status LaunchProcessPosixSpawn(const char *exe_path, 1051 const ProcessLaunchInfo &launch_info, 1052 lldb::pid_t &pid) { 1053 Status error; 1054 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST | 1055 LIBLLDB_LOG_PROCESS)); 1056 1057 posix_spawnattr_t attr; 1058 error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX); 1059 1060 if (error.Fail()) { 1061 LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error); 1062 return error; 1063 } 1064 1065 // Make sure we clean up the posix spawn attributes before exiting this scope. 1066 auto cleanup_attr = 1067 llvm::make_scope_exit([&]() { posix_spawnattr_destroy(&attr); }); 1068 1069 sigset_t no_signals; 1070 sigset_t all_signals; 1071 sigemptyset(&no_signals); 1072 sigfillset(&all_signals); 1073 ::posix_spawnattr_setsigmask(&attr, &no_signals); 1074 ::posix_spawnattr_setsigdefault(&attr, &all_signals); 1075 1076 short flags = GetPosixspawnFlags(launch_info); 1077 1078 error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX); 1079 if (error.Fail()) { 1080 LLDB_LOG(log, 1081 "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )", 1082 error, flags); 1083 return error; 1084 } 1085 1086 const char *tmp_argv[2]; 1087 char *const *argv = const_cast<char *const *>( 1088 launch_info.GetArguments().GetConstArgumentVector()); 1089 Environment::Envp envp = launch_info.GetEnvironment().getEnvp(); 1090 if (argv == NULL) { 1091 // posix_spawn gets very unhappy if it doesn't have at least the program 1092 // name in argv[0]. One of the side affects I have noticed is the 1093 // environment 1094 // variables don't make it into the child process if "argv == NULL"!!! 1095 tmp_argv[0] = exe_path; 1096 tmp_argv[1] = NULL; 1097 argv = const_cast<char *const *>(tmp_argv); 1098 } 1099 1100 FileSpec working_dir{launch_info.GetWorkingDirectory()}; 1101 if (working_dir) { 1102 // Set the working directory on this thread only 1103 if (__pthread_chdir(working_dir.GetCString()) < 0) { 1104 if (errno == ENOENT) { 1105 error.SetErrorStringWithFormat("No such file or directory: %s", 1106 working_dir.GetCString()); 1107 } else if (errno == ENOTDIR) { 1108 error.SetErrorStringWithFormat("Path doesn't name a directory: %s", 1109 working_dir.GetCString()); 1110 } else { 1111 error.SetErrorStringWithFormat("An unknown error occurred when " 1112 "changing directory for process " 1113 "execution."); 1114 } 1115 return error; 1116 } 1117 } 1118 1119 ::pid_t result_pid = LLDB_INVALID_PROCESS_ID; 1120 const size_t num_file_actions = launch_info.GetNumFileActions(); 1121 if (num_file_actions > 0) { 1122 posix_spawn_file_actions_t file_actions; 1123 error.SetError(::posix_spawn_file_actions_init(&file_actions), 1124 eErrorTypePOSIX); 1125 if (error.Fail()) { 1126 LLDB_LOG(log, 1127 "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )", 1128 error); 1129 return error; 1130 } 1131 1132 // Make sure we clean up the posix file actions before exiting this scope. 1133 auto cleanup_fileact = llvm::make_scope_exit( 1134 [&]() { posix_spawn_file_actions_destroy(&file_actions); }); 1135 1136 for (size_t i = 0; i < num_file_actions; ++i) { 1137 const FileAction *launch_file_action = 1138 launch_info.GetFileActionAtIndex(i); 1139 if (launch_file_action) { 1140 if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, 1141 error)) 1142 return error; 1143 } 1144 } 1145 1146 error.SetError( 1147 ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), 1148 eErrorTypePOSIX); 1149 1150 if (error.Fail()) { 1151 LLDB_LOG(log, 1152 "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', " 1153 "file_actions = {3}, " 1154 "attr = {4}, argv = {5}, envp = {6} )", 1155 error, result_pid, exe_path, &file_actions, &attr, argv, 1156 envp.get()); 1157 if (log) { 1158 for (int ii = 0; argv[ii]; ++ii) 1159 LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]); 1160 } 1161 } 1162 1163 } else { 1164 error.SetError( 1165 ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), 1166 eErrorTypePOSIX); 1167 1168 if (error.Fail()) { 1169 LLDB_LOG(log, 1170 "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', " 1171 "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )", 1172 error, result_pid, exe_path, &attr, argv, envp.get()); 1173 if (log) { 1174 for (int ii = 0; argv[ii]; ++ii) 1175 LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]); 1176 } 1177 } 1178 } 1179 pid = result_pid; 1180 1181 if (working_dir) { 1182 // No more thread specific current working directory 1183 __pthread_fchdir(-1); 1184 } 1185 1186 return error; 1187} 1188 1189static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) { 1190 bool result = false; 1191 1192#if TARGET_OS_OSX 1193 bool launchingAsRoot = launch_info.GetUserID() == 0; 1194 bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0; 1195 1196 if (launchingAsRoot && !currentUserIsRoot) { 1197 // If current user is already root, we don't need XPC's help. 1198 result = true; 1199 } 1200#endif 1201 1202 return result; 1203} 1204 1205Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) { 1206 Status error; 1207 1208 FileSystem &fs = FileSystem::Instance(); 1209 FileSpec exe_spec(launch_info.GetExecutableFile()); 1210 1211 if (!fs.Exists(exe_spec)) 1212 FileSystem::Instance().Resolve(exe_spec); 1213 1214 if (!fs.Exists(exe_spec)) 1215 FileSystem::Instance().ResolveExecutableLocation(exe_spec); 1216 1217 if (!fs.Exists(exe_spec)) { 1218 error.SetErrorStringWithFormatv("executable doesn't exist: '{0}'", 1219 exe_spec); 1220 return error; 1221 } 1222 1223 if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) { 1224#if TARGET_OS_OSX 1225 return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(), 1226 launch_info); 1227#else 1228 error.SetErrorString("launching a process in a new terminal is not " 1229 "supported on iOS devices"); 1230 return error; 1231#endif 1232 } 1233 1234 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 1235 1236 // From now on we'll deal with the external (devirtualized) path. 1237 auto exe_path = fs.GetExternalPath(exe_spec); 1238 if (!exe_path) 1239 return Status(exe_path.getError()); 1240 1241 if (ShouldLaunchUsingXPC(launch_info)) 1242 error = LaunchProcessXPC(exe_path->c_str(), launch_info, pid); 1243 else 1244 error = LaunchProcessPosixSpawn(exe_path->c_str(), launch_info, pid); 1245 1246 if (pid != LLDB_INVALID_PROCESS_ID) { 1247 // If all went well, then set the process ID into the launch info 1248 launch_info.SetProcessID(pid); 1249 1250 // Make sure we reap any processes we spawn or we will have zombies. 1251 bool monitoring = launch_info.MonitorProcess(); 1252 UNUSED_IF_ASSERT_DISABLED(monitoring); 1253 assert(monitoring); 1254 } else { 1255 // Invalid process ID, something didn't go well 1256 if (error.Success()) 1257 error.SetErrorString("process launch failed for unknown reasons"); 1258 } 1259 return error; 1260} 1261 1262Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { 1263 Status error; 1264 if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) { 1265 FileSpec expand_tool_spec = HostInfo::GetSupportExeDir(); 1266 if (!expand_tool_spec) { 1267 error.SetErrorString( 1268 "could not get support executable directory for lldb-argdumper tool"); 1269 return error; 1270 } 1271 expand_tool_spec.AppendPathComponent("lldb-argdumper"); 1272 if (!FileSystem::Instance().Exists(expand_tool_spec)) { 1273 error.SetErrorStringWithFormat( 1274 "could not find the lldb-argdumper tool: %s", 1275 expand_tool_spec.GetPath().c_str()); 1276 return error; 1277 } 1278 1279 StreamString expand_tool_spec_stream; 1280 expand_tool_spec_stream.Printf("\"%s\"", 1281 expand_tool_spec.GetPath().c_str()); 1282 1283 Args expand_command(expand_tool_spec_stream.GetData()); 1284 expand_command.AppendArguments(launch_info.GetArguments()); 1285 1286 int status; 1287 std::string output; 1288 FileSpec cwd(launch_info.GetWorkingDirectory()); 1289 if (!FileSystem::Instance().Exists(cwd)) { 1290 char *wd = getcwd(nullptr, 0); 1291 if (wd == nullptr) { 1292 error.SetErrorStringWithFormat( 1293 "cwd does not exist; cannot launch with shell argument expansion"); 1294 return error; 1295 } else { 1296 FileSpec working_dir(wd); 1297 free(wd); 1298 launch_info.SetWorkingDirectory(working_dir); 1299 } 1300 } 1301 bool run_in_default_shell = true; 1302 bool hide_stderr = true; 1303 Status e = RunShellCommand(expand_command, cwd, &status, nullptr, &output, 1304 std::chrono::seconds(10), run_in_default_shell, 1305 hide_stderr); 1306 1307 if (e.Fail()) 1308 return e; 1309 1310 if (status != 0) { 1311 error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", 1312 status); 1313 return error; 1314 } 1315 1316 auto data_sp = StructuredData::ParseJSON(output); 1317 if (!data_sp) { 1318 error.SetErrorString("invalid JSON"); 1319 return error; 1320 } 1321 1322 auto dict_sp = data_sp->GetAsDictionary(); 1323 if (!data_sp) { 1324 error.SetErrorString("invalid JSON"); 1325 return error; 1326 } 1327 1328 auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments"); 1329 if (!args_sp) { 1330 error.SetErrorString("invalid JSON"); 1331 return error; 1332 } 1333 1334 auto args_array_sp = args_sp->GetAsArray(); 1335 if (!args_array_sp) { 1336 error.SetErrorString("invalid JSON"); 1337 return error; 1338 } 1339 1340 launch_info.GetArguments().Clear(); 1341 1342 for (size_t i = 0; i < args_array_sp->GetSize(); i++) { 1343 auto item_sp = args_array_sp->GetItemAtIndex(i); 1344 if (!item_sp) 1345 continue; 1346 auto str_sp = item_sp->GetAsString(); 1347 if (!str_sp) 1348 continue; 1349 1350 launch_info.GetArguments().AppendArgument(str_sp->GetValue()); 1351 } 1352 } 1353 1354 return error; 1355} 1356 1357llvm::Expected<HostThread> Host::StartMonitoringChildProcess( 1358 const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, 1359 bool monitor_signals) { 1360 unsigned long mask = DISPATCH_PROC_EXIT; 1361 if (monitor_signals) 1362 mask |= DISPATCH_PROC_SIGNAL; 1363 1364 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_HOST | 1365 LIBLLDB_LOG_PROCESS)); 1366 1367 dispatch_source_t source = ::dispatch_source_create( 1368 DISPATCH_SOURCE_TYPE_PROC, pid, mask, 1369 ::dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 1370 1371 LLDB_LOGF(log, 1372 "Host::StartMonitoringChildProcess " 1373 "(callback, pid=%i, monitor_signals=%i) " 1374 "source = %p\n", 1375 static_cast<int>(pid), monitor_signals, 1376 static_cast<void *>(source)); 1377 1378 if (source) { 1379 Host::MonitorChildProcessCallback callback_copy = callback; 1380 ::dispatch_source_set_cancel_handler(source, ^{ 1381 dispatch_release(source); 1382 }); 1383 ::dispatch_source_set_event_handler(source, ^{ 1384 1385 int status = 0; 1386 int wait_pid = 0; 1387 bool cancel = false; 1388 bool exited = false; 1389 wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, 0); 1390 if (wait_pid >= 0) { 1391 int signal = 0; 1392 int exit_status = 0; 1393 const char *status_cstr = NULL; 1394 if (WIFSTOPPED(status)) { 1395 signal = WSTOPSIG(status); 1396 status_cstr = "STOPPED"; 1397 } else if (WIFEXITED(status)) { 1398 exit_status = WEXITSTATUS(status); 1399 status_cstr = "EXITED"; 1400 exited = true; 1401 } else if (WIFSIGNALED(status)) { 1402 signal = WTERMSIG(status); 1403 status_cstr = "SIGNALED"; 1404 exited = true; 1405 exit_status = -1; 1406 } else { 1407 status_cstr = "???"; 1408 } 1409 1410 LLDB_LOGF(log, 1411 "::waitpid (pid = %llu, &status, 0) => pid = %i, status " 1412 "= 0x%8.8x (%s), signal = %i, exit_status = %i", 1413 pid, wait_pid, status, status_cstr, signal, exit_status); 1414 1415 if (callback_copy) 1416 cancel = callback_copy(pid, exited, signal, exit_status); 1417 1418 if (exited || cancel) { 1419 ::dispatch_source_cancel(source); 1420 } 1421 } 1422 }); 1423 1424 ::dispatch_resume(source); 1425 } 1426 return HostThread(); 1427} 1428 1429//---------------------------------------------------------------------- 1430// Log to both stderr and to ASL Logging when running on MacOSX. 1431//---------------------------------------------------------------------- 1432void Host::SystemLog(SystemLogType type, const char *format, va_list args) { 1433 if (format && format[0]) { 1434 static aslmsg g_aslmsg = NULL; 1435 if (g_aslmsg == NULL) { 1436 g_aslmsg = ::asl_new(ASL_TYPE_MSG); 1437 char asl_key_sender[PATH_MAX]; 1438 snprintf(asl_key_sender, sizeof(asl_key_sender), 1439 "com.apple.LLDB.framework"); 1440 ::asl_set(g_aslmsg, ASL_KEY_SENDER, asl_key_sender); 1441 } 1442 1443 // Copy the va_list so we can log this message twice 1444 va_list copy_args; 1445 va_copy(copy_args, args); 1446 // Log to stderr 1447 ::vfprintf(stderr, format, copy_args); 1448 va_end(copy_args); 1449 1450 int asl_level; 1451 switch (type) { 1452 case eSystemLogError: 1453 asl_level = ASL_LEVEL_ERR; 1454 break; 1455 1456 case eSystemLogWarning: 1457 asl_level = ASL_LEVEL_WARNING; 1458 break; 1459 } 1460 1461 // Log to ASL 1462 ::asl_vlog(NULL, g_aslmsg, asl_level, format, args); 1463 } 1464} 1465