summaryrefslogtreecommitdiffstats
path: root/lldb/source/Host/macosx/launcherXPCService/main.mm
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Host/macosx/launcherXPCService/main.mm')
-rw-r--r--lldb/source/Host/macosx/launcherXPCService/main.mm193
1 files changed, 193 insertions, 0 deletions
diff --git a/lldb/source/Host/macosx/launcherXPCService/main.mm b/lldb/source/Host/macosx/launcherXPCService/main.mm
new file mode 100644
index 00000000000..2766c0ebfd4
--- /dev/null
+++ b/lldb/source/Host/macosx/launcherXPCService/main.mm
@@ -0,0 +1,193 @@
+//
+// main.m
+// Used in both LauncherXPCService and LaunchRootXPCService targets
+//
+// Copyright (c) 2012 Apple Inc. All rights reserved.
+//
+#include <AvailabilityMacros.h>
+
+#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+#define BUILDING_ON_SNOW_LEOPARD 1
+#endif
+
+#if !BUILDING_ON_SNOW_LEOPARD
+#define __XPC_PRIVATE_H__
+#include <xpc/xpc.h>
+#include <spawn.h>
+#include <signal.h>
+#include <assert.h>
+#include "LauncherXPCService.h"
+
+// Declaration. Returns 0 if successful.
+int _validate_authorization(xpc_object_t message);
+
+// Returns 0 if successful.
+int _setup_posixspawn_attributes_file_actions(xpc_object_t message, posix_spawnattr_t *attr, posix_spawn_file_actions_t *file_actions)
+{
+ *attr = 0;
+
+ int errorCode = posix_spawnattr_init(attr);
+ if (errorCode)
+ return errorCode;
+
+ cpu_type_t cpuType = xpc_dictionary_get_int64(message, LauncherXPCServiceCPUTypeKey);
+ if (cpuType == -2) {
+ cpuType= CPU_TYPE_ANY;
+ }
+ size_t realCount;
+ errorCode = posix_spawnattr_setbinpref_np(attr, 1, &cpuType, &realCount);
+ if (errorCode)
+ return errorCode;
+
+ 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);
+
+ short flags = xpc_dictionary_get_int64(message, LauncherXPCServicePosixspawnFlagsKey);
+ errorCode = posix_spawnattr_setflags(attr, flags);
+ if (errorCode)
+ return errorCode;
+
+ // Setup any file actions. Here we are emulating what debugserver would do normally in Host.mm since the XPC service meant only for debugserver.
+ errorCode = posix_spawn_file_actions_init(file_actions);
+ if (errorCode)
+ return errorCode;
+ errorCode = posix_spawn_file_actions_addclose(file_actions, STDIN_FILENO);
+ if (errorCode)
+ return errorCode;
+ errorCode = posix_spawn_file_actions_addclose(file_actions, STDOUT_FILENO);
+ if (errorCode)
+ return errorCode;
+ errorCode = posix_spawn_file_actions_addclose(file_actions, STDERR_FILENO);
+
+ return errorCode;
+}
+
+bool extract_args(xpc_object_t message, const char *prefix, const char ***argsOut)
+{
+ char buf[50]; // long enough for 'argXXX'
+ memset(buf, 0, 50);
+ sprintf(buf, "%sCount", prefix);
+ int argsCount = xpc_dictionary_get_int64(message, buf);
+ if (argsCount == 0) {
+ return true;
+ }
+
+ const char **argsp = NULL;
+ argsp = (const char **)malloc((argsCount+1) * sizeof(argsp[0]));
+ if (argsp == NULL) {
+ return false;
+ }
+
+ for (int i=0; i<argsCount; i++) {
+ memset(buf, 0, 50);
+ sprintf(buf, "%s%i", prefix, i);
+ const char *arg = xpc_dictionary_get_string(message, buf);
+ argsp[i] = arg;
+ }
+ argsp[argsCount] = NULL;
+
+ *argsOut = argsp;
+ return true;
+}
+
+// Returns 0 if successful.
+int get_args(xpc_object_t message, const char **path, const char ***argsOut, const char ***envOut)
+{
+ if (!extract_args(message, LauncherXPCServiceArgPrefxKey, argsOut)) {
+ return 1;
+ }
+ *path = (*argsOut)[0];
+
+ if (!extract_args(message, LauncherXPCServiceEnvPrefxKey, envOut)) {
+ return 2;
+ }
+
+ return 0;
+}
+
+static void launcherXPC_peer_event_handler(xpc_connection_t peer, xpc_object_t event)
+{
+ xpc_type_t type = xpc_get_type(event);
+ if (type == XPC_TYPE_ERROR) {
+ if (event == XPC_ERROR_CONNECTION_INVALID) {
+ // The client process on the other end of the connection has either
+ // crashed or cancelled the connection. After receiving this error,
+ // the connection is in an invalid state, and you do not need to
+ // call xpc_connection_cancel(). Just tear down any associated state
+ // here.
+ } else if (event == XPC_ERROR_TERMINATION_IMMINENT) {
+ // Handle per-connection termination cleanup.
+ }
+ } else {
+ assert(type == XPC_TYPE_DICTIONARY);
+ // Handle the message.
+
+ pid_t childPID = 0;
+ posix_spawn_file_actions_t file_actions;
+ posix_spawnattr_t attributes;
+
+ /*
+ Types of error. Error code will be specific to each type.
+ 100 - authorization failure
+ 101 - posixspawn attributes problem
+ 102 - get args/env problem
+ 103 - posixspawn problem
+ */
+ int errorType = 100;
+ int errorCode = _validate_authorization(event);
+ if (!errorCode) {
+ errorType = 101;
+ errorCode = _setup_posixspawn_attributes_file_actions(event, &attributes, &file_actions);
+ if (!errorCode) {
+ const char *path = NULL;
+ const char **argvp = NULL;
+ const char **envp = NULL;
+ errorType = 102;
+ errorCode = get_args(event, &path, &argvp, &envp);
+ if (!errorCode) {
+ errorType = 103;
+ errorCode = posix_spawn(&childPID, path, &file_actions, &attributes, (char * const *)argvp, (char * const *)envp);
+
+ if (argvp) free(argvp);
+ if (envp) free(envp);
+ }
+ }
+ }
+
+ xpc_object_t reply = xpc_dictionary_create_reply(event);
+
+ xpc_dictionary_set_int64(reply, LauncherXPCServiceChildPIDKey, childPID);
+ if (!childPID) {
+ xpc_dictionary_set_int64(reply, LauncherXPCServiceErrorTypeKey, errorType);
+ xpc_dictionary_set_int64(reply, LauncherXPCServiceCodeTypeKey, errorCode);
+ }
+
+ xpc_connection_send_message(peer, reply);
+ xpc_release(reply);
+ }
+}
+
+static void launcherXPC_event_handler(xpc_connection_t peer)
+{
+ // By defaults, new connections will target the default dispatch
+ // concurrent queue.
+ xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
+ launcherXPC_peer_event_handler(peer, event);
+ });
+
+ // This will tell the connection to begin listening for events. If you
+ // have some other initialization that must be done asynchronously, then
+ // you can defer this call until after that initialization is done.
+ xpc_connection_resume(peer);
+}
+
+int main(int argc, const char *argv[])
+{
+ xpc_main(launcherXPC_event_handler);
+ return 0;
+}
+#endif
OpenPOWER on IntegriCloud