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