summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp')
-rw-r--r--lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp1185
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
OpenPOWER on IntegriCloud