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