diff options
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.patch | 373 |
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..0a8b0260 --- /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 8/9] 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 + |