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