diff options
Diffstat (limited to 'lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp | 1185 |
1 files changed, 546 insertions, 639 deletions
diff --git a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp index 91abe4f26e2..408f0abe72d 100644 --- a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp +++ b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp @@ -15,7 +15,7 @@ #include <sys/sysctl.h> #ifndef _POSIX_SPAWN_DISABLE_ASLR -#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 #endif // LLDB includes @@ -35,703 +35,610 @@ using namespace lldb_private; using namespace lldb_private::process_darwin; using namespace lldb_private::darwin_process_launcher; -namespace -{ - static LaunchFlavor g_launch_flavor = LaunchFlavor::Default; +namespace { +static LaunchFlavor g_launch_flavor = LaunchFlavor::Default; } -namespace lldb_private -{ -namespace darwin_process_launcher -{ - -static uint32_t -GetCPUTypeForLocalProcess(::pid_t pid) -{ - int mib[CTL_MAXNAME]={0,}; - size_t len = CTL_MAXNAME; - if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) - return 0; - - mib[len] = pid; - len++; - - cpu_type_t cpu; - size_t cpu_len = sizeof(cpu); - if (::sysctl (mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) - cpu = 0; - return cpu; +namespace lldb_private { +namespace darwin_process_launcher { + +static uint32_t GetCPUTypeForLocalProcess(::pid_t pid) { + int mib[CTL_MAXNAME] = { + 0, + }; + size_t len = CTL_MAXNAME; + if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) + return 0; + + mib[len] = pid; + len++; + + cpu_type_t cpu; + size_t cpu_len = sizeof(cpu); + if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) + cpu = 0; + return cpu; } -static bool -ResolveExecutablePath(const char *path, char *resolved_path, - size_t resolved_path_size) -{ - if (path == NULL || path[0] == '\0') - return false; - - char max_path[PATH_MAX]; - std::string result; - CFString::GlobPath(path, result); - - if (result.empty()) - result = path; - - struct stat path_stat; - if (::stat(path, &path_stat) == 0) - { - if ((path_stat.st_mode & S_IFMT) == S_IFDIR) - { - CFBundle bundle(path); - CFReleaser<CFURLRef> url(bundle.CopyExecutableURL ()); - if (url.get()) - { - if (::CFURLGetFileSystemRepresentation(url.get(), true, - (UInt8*)resolved_path, - resolved_path_size)) - return true; - } - } - } +static bool ResolveExecutablePath(const char *path, char *resolved_path, + size_t resolved_path_size) { + if (path == NULL || path[0] == '\0') + return false; - if (realpath(path, max_path)) - { - // Found the path relatively... - ::strncpy(resolved_path, max_path, resolved_path_size); - return strlen(resolved_path) + 1 < resolved_path_size; + char max_path[PATH_MAX]; + std::string result; + CFString::GlobPath(path, result); + + if (result.empty()) + result = path; + + struct stat path_stat; + if (::stat(path, &path_stat) == 0) { + if ((path_stat.st_mode & S_IFMT) == S_IFDIR) { + CFBundle bundle(path); + CFReleaser<CFURLRef> url(bundle.CopyExecutableURL()); + if (url.get()) { + if (::CFURLGetFileSystemRepresentation( + url.get(), true, (UInt8 *)resolved_path, resolved_path_size)) + return true; + } } - else - { - // Not a relative path, check the PATH environment variable if the - const char *PATH = getenv("PATH"); - if (PATH) - { - const char *curr_path_start = PATH; - const char *curr_path_end; - while (curr_path_start && *curr_path_start) - { - curr_path_end = strchr(curr_path_start, ':'); - if (curr_path_end == NULL) - { - result.assign(curr_path_start); - curr_path_start = NULL; - } - else if (curr_path_end > curr_path_start) - { - size_t len = curr_path_end - curr_path_start; - result.assign(curr_path_start, len); - curr_path_start += len + 1; - } - else - break; - - result += '/'; - result += path; - struct stat s; - if (stat(result.c_str(), &s) == 0) - { - ::strncpy(resolved_path, result.c_str(), - resolved_path_size); - return result.size() + 1 < resolved_path_size; - } - } + } + + if (realpath(path, max_path)) { + // Found the path relatively... + ::strncpy(resolved_path, max_path, resolved_path_size); + return strlen(resolved_path) + 1 < resolved_path_size; + } else { + // Not a relative path, check the PATH environment variable if the + const char *PATH = getenv("PATH"); + if (PATH) { + const char *curr_path_start = PATH; + const char *curr_path_end; + while (curr_path_start && *curr_path_start) { + curr_path_end = strchr(curr_path_start, ':'); + if (curr_path_end == NULL) { + result.assign(curr_path_start); + curr_path_start = NULL; + } else if (curr_path_end > curr_path_start) { + size_t len = curr_path_end - curr_path_start; + result.assign(curr_path_start, len); + curr_path_start += len + 1; + } else + break; + + result += '/'; + result += path; + struct stat s; + if (stat(result.c_str(), &s) == 0) { + ::strncpy(resolved_path, result.c_str(), resolved_path_size); + return result.size() + 1 < resolved_path_size; } + } } - return false; + } + return false; } // TODO check if we have a general purpose fork and exec. We may be // able to get rid of this entirely. -static Error -ForkChildForPTraceDebugging(const char *path, - char const *argv[], - char const *envp[], - ::pid_t *pid, - int *pty_fd) -{ - Error error; - if (!path || !argv || !envp || !pid || !pty_fd) - { - error.SetErrorString("invalid arguments"); - return error; - } - - // Use a fork that ties the child process's stdin/out/err to a pseudo - // terminal so we can read it in our MachProcess::STDIOThread - // as unbuffered io. - lldb_utility::PseudoTerminal pty; - char fork_error[256]; - memset(fork_error, 0, sizeof(fork_error)); - *pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error))); - if (*pid < 0) - { - //-------------------------------------------------------------- - // Error during fork. - //-------------------------------------------------------------- - *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID); - error.SetErrorStringWithFormat("%s(): fork failed: %s", - __FUNCTION__, fork_error); - return error; - } - else if (pid == 0) - { - //-------------------------------------------------------------- - // Child process - //-------------------------------------------------------------- - - // Debug this process. - ::ptrace(PT_TRACE_ME, 0, 0, 0); - - // Get BSD signals as mach exceptions. - ::ptrace(PT_SIGEXC, 0, 0, 0); - - // If our parent is setgid, lets make sure we don't inherit those - // extra powers due to nepotism. - if (::setgid(getgid()) == 0) - { - // Let the child have its own process group. We need to execute - // this call in both the child and parent to avoid a race - // condition between the two processes. - - // Set the child process group to match its pid. - ::setpgid(0, 0); - - // Sleep a bit to before the exec call. - ::sleep(1); - - // Turn this process into the given executable. - ::execv(path, (char * const *)argv); - } - // Exit with error code. Child process should have taken - // over in above exec call and if the exec fails it will - // exit the child process below. - ::exit(127); - } - else - { - //-------------------------------------------------------------- - // Parent process - //-------------------------------------------------------------- - // Let the child have its own process group. We need to execute - // this call in both the child and parent to avoid a race condition - // between the two processes. - - // Set the child process group to match its pid - ::setpgid(*pid, *pid); - if (pty_fd) - { - // Release our master pty file descriptor so the pty class doesn't - // close it and so we can continue to use it in our STDIO thread - *pty_fd = pty.ReleaseMasterFileDescriptor(); - } - } +static Error ForkChildForPTraceDebugging(const char *path, char const *argv[], + char const *envp[], ::pid_t *pid, + int *pty_fd) { + Error error; + if (!path || !argv || !envp || !pid || !pty_fd) { + error.SetErrorString("invalid arguments"); return error; -} + } + + // Use a fork that ties the child process's stdin/out/err to a pseudo + // terminal so we can read it in our MachProcess::STDIOThread + // as unbuffered io. + lldb_utility::PseudoTerminal pty; + char fork_error[256]; + memset(fork_error, 0, sizeof(fork_error)); + *pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error))); + if (*pid < 0) { + //-------------------------------------------------------------- + // Error during fork. + //-------------------------------------------------------------- + *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID); + error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__, + fork_error); + return error; + } else if (pid == 0) { + //-------------------------------------------------------------- + // Child process + //-------------------------------------------------------------- -static Error -CreatePosixSpawnFileAction(const FileAction &action, - posix_spawn_file_actions_t *file_actions) -{ - Error error; + // Debug this process. + ::ptrace(PT_TRACE_ME, 0, 0, 0); - // Log it. - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - { - StreamString stream; - stream.PutCString("converting file action for posix_spawn(): "); - action.Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } + // Get BSD signals as mach exceptions. + ::ptrace(PT_SIGEXC, 0, 0, 0); - // Validate args. - if (!file_actions) - { - error.SetErrorString("mandatory file_actions arg is null"); - return error; - } + // If our parent is setgid, lets make sure we don't inherit those + // extra powers due to nepotism. + if (::setgid(getgid()) == 0) { + // Let the child have its own process group. We need to execute + // this call in both the child and parent to avoid a race + // condition between the two processes. - // Build the posix file action. - switch (action.GetAction()) - { - case FileAction::eFileActionOpen: - { - const int error_code = - ::posix_spawn_file_actions_addopen(file_actions, - action.GetFD(), - action.GetPath(), - action.GetActionArgument(), - 0); - if (error_code != 0) - { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } + // Set the child process group to match its pid. + ::setpgid(0, 0); - case FileAction::eFileActionClose: - { - const int error_code = - ::posix_spawn_file_actions_addclose(file_actions, - action.GetFD()); - if (error_code != 0) - { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } - - case FileAction::eFileActionDuplicate: - { - const int error_code = - ::posix_spawn_file_actions_adddup2(file_actions, - action.GetFD(), - action.GetActionArgument()); - if (error_code != 0) - { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } + // Sleep a bit to before the exec call. + ::sleep(1); - case FileAction::eFileActionNone: - default: - if (log) - log->Printf("%s(): unsupported file action %u", - __FUNCTION__, action.GetAction()); - break; + // Turn this process into the given executable. + ::execv(path, (char *const *)argv); } - - return error; + // Exit with error code. Child process should have taken + // over in above exec call and if the exec fails it will + // exit the child process below. + ::exit(127); + } else { + //-------------------------------------------------------------- + // Parent process + //-------------------------------------------------------------- + // Let the child have its own process group. We need to execute + // this call in both the child and parent to avoid a race condition + // between the two processes. + + // Set the child process group to match its pid + ::setpgid(*pid, *pid); + if (pty_fd) { + // Release our master pty file descriptor so the pty class doesn't + // close it and so we can continue to use it in our STDIO thread + *pty_fd = pty.ReleaseMasterFileDescriptor(); + } + } + return error; } static Error -PosixSpawnChildForPTraceDebugging(const char *path, - ProcessLaunchInfo &launch_info, - ::pid_t *pid, - cpu_type_t *actual_cpu_type) -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!pid) - { - error.SetErrorStringWithFormat("%s(): pid arg cannot be null", - __FUNCTION__); - return error; +CreatePosixSpawnFileAction(const FileAction &action, + posix_spawn_file_actions_t *file_actions) { + Error error; + + // Log it. + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + StreamString stream; + stream.PutCString("converting file action for posix_spawn(): "); + action.Dump(stream); + stream.Flush(); + log->PutCString(stream.GetString().c_str()); + } + + // Validate args. + if (!file_actions) { + error.SetErrorString("mandatory file_actions arg is null"); + return error; + } + + // Build the posix file action. + switch (action.GetAction()) { + case FileAction::eFileActionOpen: { + const int error_code = ::posix_spawn_file_actions_addopen( + file_actions, action.GetFD(), action.GetPath(), + action.GetActionArgument(), 0); + if (error_code != 0) { + error.SetError(error_code, eErrorTypePOSIX); + return error; } - - posix_spawnattr_t attr; - short flags; - if (log) - { - StreamString stream; - stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path); - launch_info.Dump(stream, nullptr); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); + break; + } + + case FileAction::eFileActionClose: { + const int error_code = + ::posix_spawn_file_actions_addclose(file_actions, action.GetFD()); + if (error_code != 0) { + error.SetError(error_code, eErrorTypePOSIX); + return error; } - - int error_code; - if ((error_code = ::posix_spawnattr_init(&attr)) != 0) - { - if (log) - log->Printf("::posix_spawnattr_init(&attr) failed"); - error.SetError(error_code, eErrorTypePOSIX); - return error; + break; + } + + case FileAction::eFileActionDuplicate: { + const int error_code = ::posix_spawn_file_actions_adddup2( + file_actions, action.GetFD(), action.GetActionArgument()); + if (error_code != 0) { + error.SetError(error_code, eErrorTypePOSIX); + return error; } + break; + } - // Ensure we clean up the spawnattr structure however we exit this - // function. - std::unique_ptr<posix_spawnattr_t, int(*)(posix_spawnattr_t*)> - spawnattr_up(&attr, ::posix_spawnattr_destroy); - - - flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF | - POSIX_SPAWN_SETSIGMASK; - if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) - flags |= _POSIX_SPAWN_DISABLE_ASLR; - - sigset_t no_signals; - sigset_t all_signals; - sigemptyset (&no_signals); - sigfillset (&all_signals); - ::posix_spawnattr_setsigmask(&attr, &no_signals); - ::posix_spawnattr_setsigdefault(&attr, &all_signals); - - if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) - { - if (log) - log->Printf("::posix_spawnattr_setflags(&attr, " - "POSIX_SPAWN_START_SUSPENDED%s) failed: %s", - flags & _POSIX_SPAWN_DISABLE_ASLR ? - " | _POSIX_SPAWN_DISABLE_ASLR" : "", - strerror(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } + case FileAction::eFileActionNone: + default: + if (log) + log->Printf("%s(): unsupported file action %u", __FUNCTION__, + action.GetAction()); + break; + } -#if !defined(__arm__) + return error; +} - // We don't need to do this for ARM, and we really shouldn't now that we - // have multiple CPU subtypes and no posix_spawnattr call that allows us - // to set which CPU subtype to launch... - cpu_type_t desired_cpu_type = - launch_info.GetArchitecture().GetMachOCPUType(); - if (desired_cpu_type != LLDB_INVALID_CPUTYPE) - { - size_t ocount = 0; - error_code = ::posix_spawnattr_setbinpref_np(&attr, 1, - &desired_cpu_type, - &ocount); - if (error_code != 0) - { - if (log) - log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, " - "cpu_type = 0x%8.8x, count => %llu): %s", - desired_cpu_type, (uint64_t)ocount, - strerror(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - if (ocount != 1) - { - error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np " - "did not set the expected number " - "of cpu_type entries: expected 1 " - "but was %zu", ocount); - return error; - } - } -#endif +static Error PosixSpawnChildForPTraceDebugging(const char *path, + ProcessLaunchInfo &launch_info, + ::pid_t *pid, + cpu_type_t *actual_cpu_type) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - posix_spawn_file_actions_t file_actions; - if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) - { - if (log) - log->Printf("::posix_spawn_file_actions_init(&file_actions) " - "failed: %s", - strerror(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } + if (!pid) { + error.SetErrorStringWithFormat("%s(): pid arg cannot be null", + __FUNCTION__); + return error; + } + + posix_spawnattr_t attr; + short flags; + if (log) { + StreamString stream; + stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path); + launch_info.Dump(stream, nullptr); + stream.Flush(); + log->PutCString(stream.GetString().c_str()); + } + + int error_code; + if ((error_code = ::posix_spawnattr_init(&attr)) != 0) { + if (log) + log->Printf("::posix_spawnattr_init(&attr) failed"); + error.SetError(error_code, eErrorTypePOSIX); + return error; + } + + // Ensure we clean up the spawnattr structure however we exit this + // function. + std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up( + &attr, ::posix_spawnattr_destroy); + + flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETSIGMASK; + if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) + flags |= _POSIX_SPAWN_DISABLE_ASLR; + + sigset_t no_signals; + sigset_t all_signals; + sigemptyset(&no_signals); + sigfillset(&all_signals); + ::posix_spawnattr_setsigmask(&attr, &no_signals); + ::posix_spawnattr_setsigdefault(&attr, &all_signals); + + if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) { + if (log) + log->Printf("::posix_spawnattr_setflags(&attr, " + "POSIX_SPAWN_START_SUSPENDED%s) failed: %s", + flags & _POSIX_SPAWN_DISABLE_ASLR + ? " | _POSIX_SPAWN_DISABLE_ASLR" + : "", + strerror(error_code)); + error.SetError(error_code, eErrorTypePOSIX); + return error; + } - // Ensure we clean up file actions however we exit this. When the - // file_actions_up below goes out of scope, we'll get our file action - // cleanup. - std::unique_ptr<posix_spawn_file_actions_t, - int(*)(posix_spawn_file_actions_t*)> - file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy); - - // We assume the caller has setup the file actions appropriately. We - // are not in the business of figuring out what we really need here. - // lldb-server will have already called FinalizeFileActions() as well - // to button these up properly. - const size_t num_actions = launch_info.GetNumFileActions(); - for (size_t action_index = 0; action_index < num_actions; ++action_index) - { - const FileAction *const action = - launch_info.GetFileActionAtIndex(action_index); - if (!action) - continue; - - error = CreatePosixSpawnFileAction(*action, &file_actions); - if (!error.Success()) - { - if (log) - log->Printf("%s(): error converting FileAction to posix_spawn " - "file action: %s", __FUNCTION__, error.AsCString()); - return error; - } - } +#if !defined(__arm__) - // TODO: Verify if we can set the working directory back immediately - // after the posix_spawnp call without creating a race condition??? - const char *const working_directory = - launch_info.GetWorkingDirectory().GetCString(); - if (working_directory && working_directory[0]) - ::chdir(working_directory); - - auto argv = launch_info.GetArguments().GetArgumentVector(); - auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector(); - error_code = ::posix_spawnp(pid, path, &file_actions, &attr, - (char * const*)argv, (char * const*)envp); - if (error_code != 0) - { - if (log) - log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions " - "= %p, attr = %p, argv = %p, envp = %p) failed: %s", - pid, path, &file_actions, &attr, argv, envp, - strerror(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; + // We don't need to do this for ARM, and we really shouldn't now that we + // have multiple CPU subtypes and no posix_spawnattr call that allows us + // to set which CPU subtype to launch... + cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType(); + if (desired_cpu_type != LLDB_INVALID_CPUTYPE) { + size_t ocount = 0; + error_code = + ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount); + if (error_code != 0) { + if (log) + log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, " + "cpu_type = 0x%8.8x, count => %llu): %s", + desired_cpu_type, (uint64_t)ocount, strerror(error_code)); + error.SetError(error_code, eErrorTypePOSIX); + return error; } - - // Validate we got a pid. - if (pid == LLDB_INVALID_PROCESS_ID) - { - error.SetErrorString("posix_spawn() did not indicate a failure but it " - "failed to return a pid, aborting."); - return error; + if (ocount != 1) { + error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np " + "did not set the expected number " + "of cpu_type entries: expected 1 " + "but was %zu", + ocount); + return error; } + } +#endif - if (actual_cpu_type) - { - *actual_cpu_type = GetCPUTypeForLocalProcess(*pid); - if (log) - log->Printf("%s(): cpu type for launched process pid=%i: " - "cpu_type=0x%8.8x", __FUNCTION__, *pid, - *actual_cpu_type); + posix_spawn_file_actions_t file_actions; + if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) { + if (log) + log->Printf("::posix_spawn_file_actions_init(&file_actions) " + "failed: %s", + strerror(error_code)); + error.SetError(error_code, eErrorTypePOSIX); + return error; + } + + // Ensure we clean up file actions however we exit this. When the + // file_actions_up below goes out of scope, we'll get our file action + // cleanup. + std::unique_ptr<posix_spawn_file_actions_t, + int (*)(posix_spawn_file_actions_t *)> + file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy); + + // We assume the caller has setup the file actions appropriately. We + // are not in the business of figuring out what we really need here. + // lldb-server will have already called FinalizeFileActions() as well + // to button these up properly. + const size_t num_actions = launch_info.GetNumFileActions(); + for (size_t action_index = 0; action_index < num_actions; ++action_index) { + const FileAction *const action = + launch_info.GetFileActionAtIndex(action_index); + if (!action) + continue; + + error = CreatePosixSpawnFileAction(*action, &file_actions); + if (!error.Success()) { + if (log) + log->Printf("%s(): error converting FileAction to posix_spawn " + "file action: %s", + __FUNCTION__, error.AsCString()); + return error; } - + } + + // TODO: Verify if we can set the working directory back immediately + // after the posix_spawnp call without creating a race condition??? + const char *const working_directory = + launch_info.GetWorkingDirectory().GetCString(); + if (working_directory && working_directory[0]) + ::chdir(working_directory); + + auto argv = launch_info.GetArguments().GetArgumentVector(); + auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector(); + error_code = ::posix_spawnp(pid, path, &file_actions, &attr, + (char *const *)argv, (char *const *)envp); + if (error_code != 0) { + if (log) + log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions " + "= %p, attr = %p, argv = %p, envp = %p) failed: %s", + pid, path, &file_actions, &attr, argv, envp, + strerror(error_code)); + error.SetError(error_code, eErrorTypePOSIX); return error; -} + } -Error -LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, - LaunchFlavor *launch_flavor) -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!launch_flavor) - { - error.SetErrorString("mandatory launch_flavor field was null"); - return error; - } + // Validate we got a pid. + if (pid == LLDB_INVALID_PROCESS_ID) { + error.SetErrorString("posix_spawn() did not indicate a failure but it " + "failed to return a pid, aborting."); + return error; + } + if (actual_cpu_type) { + *actual_cpu_type = GetCPUTypeForLocalProcess(*pid); if (log) - { - StreamString stream; - stream.Printf("NativeProcessDarwin::%s(): launching with the " - "following launch info:", __FUNCTION__); - launch_info.Dump(stream, nullptr); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } + log->Printf("%s(): cpu type for launched process pid=%i: " + "cpu_type=0x%8.8x", + __FUNCTION__, *pid, *actual_cpu_type); + } + + return error; +} - // Retrieve the binary name given to us. - char given_path[PATH_MAX]; - given_path[0] = '\0'; - launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path)); - - // Determine the manner in which we'll launch. - *launch_flavor = g_launch_flavor; - if (*launch_flavor == LaunchFlavor::Default) - { - // Our default launch method is posix spawn - *launch_flavor = LaunchFlavor::PosixSpawn; +Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, + LaunchFlavor *launch_flavor) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!launch_flavor) { + error.SetErrorString("mandatory launch_flavor field was null"); + return error; + } + + if (log) { + StreamString stream; + stream.Printf("NativeProcessDarwin::%s(): launching with the " + "following launch info:", + __FUNCTION__); + launch_info.Dump(stream, nullptr); + stream.Flush(); + log->PutCString(stream.GetString().c_str()); + } + + // Retrieve the binary name given to us. + char given_path[PATH_MAX]; + given_path[0] = '\0'; + launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path)); + + // Determine the manner in which we'll launch. + *launch_flavor = g_launch_flavor; + if (*launch_flavor == LaunchFlavor::Default) { + // Our default launch method is posix spawn + *launch_flavor = LaunchFlavor::PosixSpawn; #if defined WITH_FBS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(given_path, ".app")) - { - *launch_flavor = eLaunchFlavorFBS; - } + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(given_path, ".app")) { + *launch_flavor = eLaunchFlavorFBS; + } #elif defined WITH_BKS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(given_path, ".app")) - { - *launch_flavor = eLaunchFlavorBKS; - } + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(given_path, ".app")) { + *launch_flavor = eLaunchFlavorBKS; + } #elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (strstr(given_path, ".app")) - { - *launch_flavor = eLaunchFlavorSpringBoard; - } -#endif + // Check if we have an app bundle, if so launch using SpringBoard. + if (strstr(given_path, ".app")) { + *launch_flavor = eLaunchFlavorSpringBoard; } +#endif + } + + // Attempt to resolve the binary name to an absolute path. + char resolved_path[PATH_MAX]; + resolved_path[0] = '\0'; - // Attempt to resolve the binary name to an absolute path. - char resolved_path[PATH_MAX]; - resolved_path[0] = '\0'; + if (log) + log->Printf("%s(): attempting to resolve given binary path: \"%s\"", + __FUNCTION__, given_path); + // If we fail to resolve the path to our executable, then just use what we + // were given and hope for the best + if (!ResolveExecutablePath(given_path, resolved_path, + sizeof(resolved_path))) { if (log) - log->Printf("%s(): attempting to resolve given binary path: \"%s\"", - __FUNCTION__, given_path); - - // If we fail to resolve the path to our executable, then just use what we - // were given and hope for the best - if (!ResolveExecutablePath(given_path, resolved_path, - sizeof(resolved_path)) ) - { - if (log) - log->Printf("%s(): failed to resolve binary path, using " - "what was given verbatim and hoping for the best", - __FUNCTION__); - ::strncpy(resolved_path, given_path, - sizeof(resolved_path)); - } - else - { - if (log) - log->Printf("%s(): resolved given binary path to: \"%s\"", - __FUNCTION__, resolved_path); - } + log->Printf("%s(): failed to resolve binary path, using " + "what was given verbatim and hoping for the best", + __FUNCTION__); + ::strncpy(resolved_path, given_path, sizeof(resolved_path)); + } else { + if (log) + log->Printf("%s(): resolved given binary path to: \"%s\"", __FUNCTION__, + resolved_path); + } + + char launch_err_str[PATH_MAX]; + launch_err_str[0] = '\0'; - char launch_err_str[PATH_MAX]; - launch_err_str[0] = '\0'; - - // TODO figure out how to handle QSetProcessEvent - // const char *process_event = ctx.GetProcessEvent(); - - // Ensure the binary is there. - struct stat path_stat; - if (::stat(resolved_path, &path_stat) == -1) - { - error.SetErrorToErrno(); - return error; + // TODO figure out how to handle QSetProcessEvent + // const char *process_event = ctx.GetProcessEvent(); + + // Ensure the binary is there. + struct stat path_stat; + if (::stat(resolved_path, &path_stat) == -1) { + error.SetErrorToErrno(); + return error; + } + + // Fork a child process for debugging + // state_callback(eStateLaunching); + + const auto argv = launch_info.GetArguments().GetConstArgumentVector(); + const auto envp = + launch_info.GetEnvironmentEntries().GetConstArgumentVector(); + + switch (*launch_flavor) { + case LaunchFlavor::ForkExec: { + ::pid_t pid = LLDB_INVALID_PROCESS_ID; + error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid, + pty_master_fd); + if (error.Success()) { + launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); + } else { + // Reset any variables that might have been set during a failed + // launch attempt. + if (pty_master_fd) + *pty_master_fd = -1; + + // We're done. + return error; } - - // Fork a child process for debugging - // state_callback(eStateLaunching); - - const auto argv = launch_info.GetArguments().GetConstArgumentVector(); - const auto envp = - launch_info.GetEnvironmentEntries().GetConstArgumentVector(); - - switch (*launch_flavor) - { - case LaunchFlavor::ForkExec: - { - ::pid_t pid = LLDB_INVALID_PROCESS_ID; - error = ForkChildForPTraceDebugging(resolved_path, argv, envp, - &pid, pty_master_fd); - if (error.Success()) - { - launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); - } - else - { - // Reset any variables that might have been set during a failed - // launch attempt. - if (pty_master_fd) - *pty_master_fd = -1; - - // We're done. - return error; - } - } - break; + } break; #ifdef WITH_FBS - case LaunchFlavor::FBS: - { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) - { - std::string app_bundle_path(path, app_ext + strlen(".app")); - m_flags |= eMachProcessFlagsUsingFBS; - if (BoardServiceLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, event_data, launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid. - else - break; // We tried a FBS launch, but didn't succeed lets get out - } - } - break; + case LaunchFlavor::FBS: { + const char *app_ext = strstr(path, ".app"); + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + m_flags |= eMachProcessFlagsUsingFBS; + if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, + no_stdio, disable_aslr, event_data, + launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a FBS launch, but didn't succeed lets get out + } + } break; #endif - + #ifdef WITH_BKS - case LaunchFlavor::BKS: - { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) - { - std::string app_bundle_path(path, app_ext + strlen(".app")); - m_flags |= eMachProcessFlagsUsingBKS; - if (BoardServiceLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, event_data, launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid. - else - break; // We tried a BKS launch, but didn't succeed lets get out - } - } - break; + case LaunchFlavor::BKS: { + const char *app_ext = strstr(path, ".app"); + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + m_flags |= eMachProcessFlagsUsingBKS; + if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, + no_stdio, disable_aslr, event_data, + launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a BKS launch, but didn't succeed lets get out + } + } break; #endif - + #ifdef WITH_SPRINGBOARD - case LaunchFlavor::SpringBoard: - { - // .../whatever.app/whatever ? - // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in "com.apple.whatever" here - const char *app_ext = strstr (path, ".app/"); - if (app_ext == NULL) - { - // .../whatever.app ? - int len = strlen (path); - if (len > 5) - { - if (strcmp (path + len - 4, ".app") == 0) - { - app_ext = path + len - 4; - } - } - } - if (app_ext) - { - std::string app_bundle_path(path, app_ext + strlen(".app")); - if (SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid. - else - break; // We tried a springboard launch, but didn't succeed lets get out - } - } - break; -#endif - - case LaunchFlavor::PosixSpawn: - { - ::pid_t pid = LLDB_INVALID_PROCESS_ID; - - // Retrieve paths for stdin/stdout/stderr. - cpu_type_t actual_cpu_type = 0; - error = PosixSpawnChildForPTraceDebugging(resolved_path, - launch_info, - &pid, - &actual_cpu_type); - if (error.Success()) - { - launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); - if (pty_master_fd) - *pty_master_fd = launch_info.GetPTY(). - ReleaseMasterFileDescriptor(); - } - else - { - // Reset any variables that might have been set during a failed - // launch attempt. - if (pty_master_fd) - *pty_master_fd = -1; - - // We're done. - return error; - } - break; + case LaunchFlavor::SpringBoard: { + // .../whatever.app/whatever ? + // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in + // "com.apple.whatever" here + const char *app_ext = strstr(path, ".app/"); + if (app_ext == NULL) { + // .../whatever.app ? + int len = strlen(path); + if (len > 5) { + if (strcmp(path + len - 4, ".app") == 0) { + app_ext = path + len - 4; } - - default: - // Invalid launch flavor. - error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown " - "launch flavor %d", __FUNCTION__, - (int)*launch_flavor); - return error; + } } - - if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) - { - // If we don't have a valid process ID and no one has set the error, - // then return a generic error. - if (error.Success()) - error.SetErrorStringWithFormat("%s(): failed to launch, no reason " - "specified", __FUNCTION__); + if (app_ext) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, + disable_aslr, launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a springboard launch, but didn't succeed lets get out } + } break; +#endif - // We're done with the launch side of the operation. + case LaunchFlavor::PosixSpawn: { + ::pid_t pid = LLDB_INVALID_PROCESS_ID; + + // Retrieve paths for stdin/stdout/stderr. + cpu_type_t actual_cpu_type = 0; + error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid, + &actual_cpu_type); + if (error.Success()) { + launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); + if (pty_master_fd) + *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); + } else { + // Reset any variables that might have been set during a failed + // launch attempt. + if (pty_master_fd) + *pty_master_fd = -1; + + // We're done. + return error; + } + break; + } + + default: + // Invalid launch flavor. + error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown " + "launch flavor %d", + __FUNCTION__, (int)*launch_flavor); return error; + } + + if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) { + // If we don't have a valid process ID and no one has set the error, + // then return a generic error. + if (error.Success()) + error.SetErrorStringWithFormat("%s(): failed to launch, no reason " + "specified", + __FUNCTION__); + } + + // We're done with the launch side of the operation. + return error; } - -}} // namespaces - +} +} // namespaces |