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