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