summaryrefslogtreecommitdiff
path: root/debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch')
-rw-r--r--debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch373
1 files changed, 373 insertions, 0 deletions
diff --git a/debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch b/debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch
new file mode 100644
index 00000000..5deff761
--- /dev/null
+++ b/debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch
@@ -0,0 +1,373 @@
+From 5a4a5c0807ce9b90b36e21032d5ff268b4a71f6f Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Fri, 23 May 2014 08:42:45 +0200
+Subject: [PATCH hurd 08/11] utils/rpctrace: support attaching to servers
+
+* utils/rpctrace.c (options): Add `--pid' and `--reference-port'.
+(print_contents): Prevent the translation of rights if `req' is NULL.
+We will use this to print messages in `trace_server'.
+(parse_task): New function.
+(trace_server): Mach server function that displays relayed messages.
+(trace_class_rpcs): New function that attaches to a server and starts
+tracing.
+(parse_opt): Handle `--pid' and `--reference-port'.
+(main): Handle new arguments, call trace_class_rpcs if desired.
+---
+ utils/Makefile | 5 +-
+ utils/rpctrace.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 248 insertions(+), 3 deletions(-)
+
+diff --git a/utils/Makefile b/utils/Makefile
+index 955789b..352494a 100644
+--- a/utils/Makefile
++++ b/utils/Makefile
+@@ -34,7 +34,7 @@ SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \
+ nullauth.c match-options.c msgids.c rpcscan.c
+
+ OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
+-HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc
++HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc introspection
+ LDLIBS += -lpthread
+ login-LDLIBS = -lutil -lcrypt
+ addauth-LDLIBS = -lcrypt
+@@ -67,7 +67,8 @@ ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \
+
+ $(filter-out $(special-targets), $(targets)): %: %.o
+
+-rpctrace: ../libports/libports.a
++rpctrace: ../libports/libports.a \
++ ../libintrospection/libintrospection.a hurd_portUser.o
+ rpctrace rpcscan: msgids.o \
+ ../libihash/libihash.a
+ msgids-CPPFLAGS = -DDATADIR=\"${datadir}\"
+diff --git a/utils/rpctrace.c b/utils/rpctrace.c
+index d53b510..64c171a 100644
+--- a/utils/rpctrace.c
++++ b/utils/rpctrace.c
+@@ -23,6 +23,7 @@
+ #include <hurd.h>
+ #include <hurd/ports.h>
+ #include <hurd/ihash.h>
++#include <hurd/introspection.h>
+ #include <mach/message.h>
+ #include <assert.h>
+ #include <fcntl.h>
+@@ -40,14 +41,22 @@
+ #include <envz.h>
+
+ #include "msgids.h"
++#include "hurd_port_U.h"
+
+ const char *argp_program_version = STANDARD_HURD_VERSION (rpctrace);
+
+ static unsigned strsize = 80;
++static int trace_class;
+
+ static const struct argp_option options[] =
+ {
+ {"output", 'o', "FILE", 0, "Send trace output to FILE instead of stderr."},
++ {"pid", 'p', "PID", 0, "Attach to PID and trace all requests to objects "
++ "of the same class as the given reference port. This will only work "
++ "for Hurd servers implementing the introspection protocol."},
++ {"port", 'P', "PORT", 0, "Trace all requests PORT. "
++ "PORT must denote a receive right in PID."},
++ {"class", 'c', NULL, 0, "Trace all requests to the same class as PORT."},
+ {0, 's', "SIZE", 0, "Specify the maximum string size to print (the default is 80)."},
+ {0, 'E', "var[=value]", 0,
+ "Set/change (var=value) or remove (var) an environment variable among the "
+@@ -852,7 +861,7 @@ print_contents (mach_msg_header_t *inp,
+ what task that port name is meaningful in. If it's meaningful in
+ a traced task, then it refers to our intercepting port rather than
+ the original port anyway. */
+- if (MACH_MSG_TYPE_PORT_ANY_RIGHT (name))
++ if (MACH_MSG_TYPE_PORT_ANY_RIGHT (name) && req != NULL)
+ {
+ /* These are port rights. Translate them into wrappers. */
+ mach_port_t *const portnames = data;
+@@ -1669,10 +1678,218 @@ traced_spawn (char **argv, char **envp)
+
+ return pid;
+ }
++
++/* Return the task corresponding to the user argument ARG, exiting with an
++ appriate error message if we can't. */
++static task_t
++parse_task (char *arg)
++{
++ error_t err;
++ task_t task;
++ char *arg_end;
++ pid_t pid = strtoul (arg, &arg_end, 10);
++ static process_t proc = MACH_PORT_NULL;
++
++ if (*arg == '\0' || *arg_end != '\0')
++ error (10, 0, "%s: Invalid process id", arg);
++
++ if (proc == MACH_PORT_NULL)
++ proc = getproc ();
++
++ err = proc_pid2task (proc, pid, &task);
++ if (err)
++ error (11, err, "%s", arg);
++ else if (task == MACH_PORT_NULL)
++ error (11, 0, "%s: Process %d is dead and has no task", arg, (int) pid);
++
++ return task;
++}
++
++static mach_port_t trace_notification_port;
++static mach_port_t reference_port;
++
++boolean_t
++trace_server (mach_msg_header_t *inp,
++ mach_msg_header_t *outp)
++{
++ error_t err;
++ static struct hurd_ihash ongoing_requests =
++ HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);
++ struct msgid_info *info;
++ mach_port_t trace_id;
++ int is_reply;
++
++ if (inp->msgh_local_port == trace_notification_port
++ && inp->msgh_id == MACH_NOTIFY_NO_SENDERS)
++ {
++ error (0, 0, "The tracee vanished.");
++ exit (EXIT_SUCCESS);
++ }
++
++ err = introspection_extract_message (inp, &trace_id);
++ if (err)
++ {
++ error (0, err, "introspection_extract_message");
++ goto out;
++ }
++ info = msgid_info (inp->msgh_id);
++
++ /* XXX This hardcodes an assumption about reply message ids. */
++ is_reply = (inp->msgh_id / 100) % 2 == 1;
++ if (is_reply)
++ {
++ /* This looks like a traced reply or a pseudo-reply. A
++ pseudo-reply is a message containing the result of a simple
++ procedure that is only sent to us. */
++ mig_reply_header_t *reply = (mig_reply_header_t *) inp;
++
++ mach_port_t request_port;
++ request_port = hurd_ihash_find (&ongoing_requests, trace_id);
++ if (! MACH_PORT_VALID (request_port))
++ {
++ fprintf (stderr, "unsolicited reply packet with id: %d\n",
++ trace_id);
++ goto out;
++ }
++ hurd_ihash_remove (&ongoing_requests, trace_id);
++
++ if (! (trace_class || request_port == reference_port))
++ goto out;
++
++ if (last_reply_port != trace_id)
++ {
++ print_ellipsis ();
++ fprintf (ostream, "%u...", (unsigned int) trace_id);
++ }
++ last_reply_port = MACH_PORT_NULL;
++
++ fprintf (ostream, " = ");
++
++ if (reply->RetCode == 0)
++ fprintf (ostream, "0");
++ else
++ {
++ const char *str = strerror (reply->RetCode);
++ if (str == 0)
++ fprintf (ostream, "%#x", reply->RetCode);
++ else
++ fprintf (ostream, "%#x (%s)", reply->RetCode, str);
++ }
++
++ if (inp->msgh_size > sizeof *reply)
++ {
++ fprintf (ostream, " ");
++ print_contents (inp, (void *) inp + sizeof *reply, NULL);
++ }
++ fprintf (ostream, "\n");
++ }
++ else
++ {
++ /* Remember the request port. */
++ hurd_ihash_add (&ongoing_requests, trace_id, inp->msgh_local_port);
++
++ if (! (trace_class || inp->msgh_local_port == reference_port))
++ goto out;
++
++ /* This looks like a traced request. */
++ print_ellipsis ();
++ last_reply_port = trace_id;
++
++ if (info)
++ fprintf (ostream, "% 4d->%s (", inp->msgh_local_port, info->name);
++ else
++ fprintf (ostream, "% 4d->%d (", inp->msgh_local_port, inp->msgh_id);
++
++ print_contents (inp, (void *) inp + sizeof *inp, NULL);
++ fprintf (ostream, ")");
++ }
++
++ out:
++ /* vm_deallocate any out-of-band memory. */
++ mach_msg_destroy (inp);
++
++ /* Prevent mach_msg_server from sending messages. */
++ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
++ return TRUE;
++}
++
++int
++trace_class_rpcs (mach_port_t task,
++ mach_port_t name)
++{
++ error_t err;
++ mach_port_t trace_port;
++ mach_port_t introspection_port;
++ mach_port_t previous;
++ mach_port_t port_set;
++
++ err = introspection_get_port (task, &introspection_port);
++ if (err)
++ error (13, err, "Failed to get introspection port");
++
++ if (! MACH_PORT_VALID (introspection_port))
++ error (13, 0, "The server does not implement the introspection protocol");
++
++ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
++ &trace_port);
++ if (err)
++ error (13, err, "mach_port_allocate");
++
++ err = hurd_port_trace_class_rpcs (introspection_port, name,
++ trace_port, MACH_MSG_TYPE_MAKE_SEND);
++ if (err)
++ {
++ if (err == EINVAL)
++ error (13, 0,
++ "%d does not denote a receive right managed by libports", name);
++ else
++ error (13, err, "hurd_port_trace_class_rpcs");
++ }
++
++ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
++ &trace_notification_port);
++ if (err)
++ error (13, err, "mach_port_allocate");
++
++ err = mach_port_request_notification (mach_task_self (),
++ trace_port,
++ MACH_NOTIFY_NO_SENDERS,
++ 0,
++ trace_notification_port,
++ MACH_MSG_TYPE_MAKE_SEND_ONCE,
++ &previous);
++ if (err)
++ error (13, err, "mach_port_request_notification");
++ assert (! MACH_PORT_VALID (previous));
++
++
++ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
++ &port_set);
++ if (err)
++ error (13, err, "mach_port_allocate");
++
++ err = mach_port_move_member (mach_task_self (), trace_port, port_set);
++ if (err)
++ error (13, err, "mach_port_move_member");
+
++ err = mach_port_move_member (mach_task_self (), trace_notification_port,
++ port_set);
++ if (err)
++ error (13, err, "mach_port_move_member");
++
++ error (0, 0, "entering service loop");
++ while (1)
++ mach_msg_server (trace_server, 0, port_set);
++
++ /* Not reached. */
++ return 0;
++}
++
+ int
+ main (int argc, char **argv, char **envp)
+ {
++ mach_port_t target_task = MACH_PORT_NULL;
++ bool nostdinc = FALSE;
+ const char *outfile = 0;
+ char **cmd_argv = 0;
+ pthread_t thread;
+@@ -1684,12 +1901,27 @@ main (int argc, char **argv, char **envp)
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
++ char *arg_end;
+ switch (key)
+ {
+ case 'o':
+ outfile = arg;
+ break;
+
++ case 'p':
++ target_task = parse_task (arg);
++ break;
++
++ case 'P':
++ reference_port = strtoul (arg, &arg_end, 10);
++ if (*arg == '\0' || *arg_end != '\0')
++ argp_error (state, "Invalid port name: %s", arg);
++ break;
++
++ case 'c':
++ trace_class = 1;
++ break;
++
+ case 's':
+ strsize = atoi (arg);
+ break;
+@@ -1723,10 +1955,16 @@ main (int argc, char **argv, char **envp)
+ break;
+
+ case ARGP_KEY_NO_ARGS:
++ if (MACH_PORT_VALID (target_task))
++ break;
++
+ argp_usage (state);
+ return EINVAL;
+
+ case ARGP_KEY_ARG:
++ if (MACH_PORT_VALID (target_task))
++ argp_error (state, "Superfluous argument: %s", arg);
++
+ cmd_argv = &state->argv[state->next - 1];
+ state->next = state->argc;
+ break;
+@@ -1746,6 +1984,9 @@ main (int argc, char **argv, char **envp)
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
++ if (MACH_PORT_VALID (target_task) != MACH_PORT_VALID (reference_port))
++ error (10, 0, "Please specify either both -p and -P, or neither.");
++
+ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_DEAD_NAME,
+ &unknown_task);
+ assert_perror (err);
+@@ -1760,6 +2001,9 @@ main (int argc, char **argv, char **envp)
+ ostream = stderr;
+ setlinebuf (ostream);
+
++ if (MACH_PORT_VALID (target_task))
++ return trace_class_rpcs (target_task, reference_port);
++
+ traced_bucket = ports_create_bucket ();
+ traced_class = ports_create_class (&traced_clean, NULL);
+ other_class = ports_create_class (0, 0);
+--
+2.1.4
+