summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--utils/Makefile17
-rw-r--r--utils/rpctrace.c271
2 files changed, 281 insertions, 7 deletions
diff --git a/utils/Makefile b/utils/Makefile
index a2a1a3b1..3f443050 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation
+# Copyright (C) 1994,95,96,97,98,99 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -20,14 +20,15 @@ makemode := utilities
targets = shd ps settrans showtrans syncfs su mount fsysopts \
storeinfo login w uptime ids loginpr sush vmstat portinfo \
- devprobe vminfo addauth rmauth unsu setauth ftpcp ftpdir storecat \
- storeread ping msgport
+ devprobe vminfo addauth freeauth rmauth unsu setauth ftpcp ftpdir storecat \
+ storeread ping msgport rpctrace
special-targets = mount loginpr sush uptime
SRCS = shd.c ps.c su.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \
mount.sh fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \
uptime.sh psout.c ids.c vmstat.c portinfo.c devprobe.c vminfo.c \
parse.c frobauth.c frobauth-mod.c setauth.c pids.c nonsugid.c \
- unsu.c ftpcp.c ftpdir.c storeread.c storecat.c ping.c msgport.c
+ unsu.c ftpcp.c ftpdir.c storeread.c storecat.c ping.c msgport.c \
+ rpctrace.c
LCLHDRS = psout.h parse.h pids.h frobauth.h
OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
@@ -49,9 +50,9 @@ INSTALL-ping-ops = -o root -m 4755
include ../Makeconf
-ps addauth rmauth setauth su unsu msgport: parse.o pids.o
+freeauth ps addauth rmauth setauth su unsu msgport: parse.o pids.o
login addauth setauth su: nonsugid.o
-addauth rmauth setauth su unsu: frobauth.o
+freeauth addauth rmauth setauth su unsu: frobauth.o
rmauth setauth su unsu: frobauth-mod.o
ps w: psout.o ../libps/libps.a ../libihash/libihash.a
@@ -64,8 +65,10 @@ ping: ../libthreads/libthreads.a
# work: all libraries that *any* routine in libfshelp uses must be defined.
settrans: ../libfshelp/libfshelp.a ../libports/libports.a ../libthreads/libthreads.a
ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \
- devprobe vminfo addauth rmauth setauth su unsu ftpcp ftpdir storeread \
+ devprobe vminfo addauth freeauth rmauth setauth su unsu ftpcp ftpdir storeread \
storecat msgport: \
../libshouldbeinlibc/libshouldbeinlibc.a
$(filter-out $(special-targets), $(targets)): %: %.o
+
+rpctrace: ../libports/libports.a ../libihash/libihash.a ../libthreads/libthreads.a
diff --git a/utils/rpctrace.c b/utils/rpctrace.c
new file mode 100644
index 00000000..bf6e71d5
--- /dev/null
+++ b/utils/rpctrace.c
@@ -0,0 +1,271 @@
+/* Trace RPCs sent to selected ports
+
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Jose M. Moya <josem@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA. */
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/ihash.h>
+#include <mach/message.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (rpctrace);
+
+static const struct argp_option options[] = {
+ {"output", 'o', "FILE", 0, "Send trace output to FILE instead of stderr."},
+ {0}
+};
+
+static const char *args_doc = "COMMAND [ARG...]";
+static const char *doc =
+"Trace Mach Remote Procedure Calls."
+"\v.";
+
+
+struct traced_info
+{
+ struct port_info pi;
+ mach_port_t forward;
+};
+
+task_t traced_task;
+ihash_t traced_names;
+struct port_class *traced_class;
+struct port_bucket *traced_bucket;
+FILE *ostream;
+cthread_t traced_thread;
+char *cmd;
+char **cmd_argv;
+char **cmd_envp;
+
+int print_message (FILE *stream, mach_msg_header_t *msg);
+
+#if 1
+int
+print_message (FILE *stream, mach_msg_header_t *msg)
+{
+ fprintf (stream, "[%d] %d -> %d\n", msg->msgh_id,
+ msg->msgh_local_port, msg->msgh_remote_port);
+ return 0;
+}
+#endif
+
+mach_port_t
+trace_wrapper (mach_port_t orig)
+{
+ struct traced_info *info;
+ mach_port_t port = MACH_PORT_NULL;
+
+ /* Never wrap the null port. */
+ if (orig == MACH_PORT_NULL)
+ return orig;
+
+ info = ihash_find (traced_names, orig);
+ if (! info)
+ {
+ error_t err;
+ mach_port_type_t type;
+ mach_msg_type_name_t typename;
+
+ ports_create_port (traced_class, traced_bucket,
+ sizeof (struct traced_info), &info);
+ port = ports_get_right (info);
+ info->forward = MACH_PORT_NULL;
+
+ mach_port_type (traced_task, orig, &type);
+ /* FIXME: type == 0x11bdf68: how do I get the type of right? */
+
+ if (type & MACH_PORT_TYPE_SEND)
+ {
+ err = mach_port_extract_right (traced_task, orig,
+ MACH_MSG_TYPE_MOVE_SEND,
+ &info->forward, &typename);
+ assert_perror (err);
+ err = mach_port_insert_right (traced_task, orig, port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
+ }
+ if (type & MACH_PORT_TYPE_SEND_ONCE)
+ {
+ err = mach_port_extract_right (traced_task, orig,
+ MACH_MSG_TYPE_MOVE_SEND_ONCE,
+ &info->forward, &typename);
+ assert_perror (err);
+ err = mach_port_insert_right (traced_task, orig, port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ assert_perror (err);
+ }
+ if (info->forward == MACH_PORT_NULL)
+ {
+ err = mach_port_extract_right (traced_task, orig,
+ MACH_MSG_TYPE_MAKE_SEND,
+ &info->forward, &typename);
+ assert_perror (err);
+ }
+
+ ihash_add (traced_names, orig, info, NULL);
+
+ }
+ else
+ port = ports_get_right (info);
+ mach_port_insert_right (mach_task_self (), port, port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ return port;
+}
+
+int
+trace_and_forward (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ struct traced_info *info;
+ void *msg_buf_ptr = (void *) inp + sizeof (*inp);
+
+ /* Print the message trace. */
+ print_message (ostream, inp); fflush (ostream);
+
+ /* Wrap ports. */
+ while (msg_buf_ptr < (void *) inp + inp->msgh_size)
+ {
+ mach_msg_type_t type = *(mach_msg_type_t *) msg_buf_ptr;
+ msg_buf_ptr += sizeof (mach_msg_type_t);
+ if (type.msgt_name == MACH_MSG_TYPE_PORT_NAME)
+ {
+ mach_port_t *port = msg_buf_ptr;
+ *port = trace_wrapper (*port);
+ }
+ msg_buf_ptr += type.msgt_size / 8;
+ }
+
+ info = ports_lookup_port (traced_bucket, inp->msgh_local_port,
+ traced_class);
+ if (! info)
+ return 0;
+
+ /* Swap the header data like a crossover cable. */
+ inp->msgh_bits
+ = MACH_MSGH_BITS (MACH_MSGH_BITS_LOCAL (inp->msgh_bits),
+ MACH_MSGH_BITS_REMOTE (inp->msgh_bits));
+ inp->msgh_local_port = trace_wrapper (inp->msgh_remote_port);
+ inp->msgh_remote_port = info->forward;
+
+ /* Resend the message to the tracee. */
+ mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+ return 1;
+}
+
+static any_t
+trace_thread_function (struct port_bucket *bucket)
+{
+ ports_manage_port_operations_one_thread (bucket, trace_and_forward, 0);
+ return 0;
+}
+
+static any_t
+traced_thread_function (struct port_bucket *bucket)
+{
+ mach_port_t wrapper;
+ struct traced_info *info;
+ file_t file = file_name_path_lookup (cmd, getenv ("PATH"), O_EXEC, 0, 0);
+
+ if (file == MACH_PORT_NULL)
+ error (1, errno, "cannot lookup `%s' in PATH", cmd);
+ task_create (mach_task_self (), 0, &traced_task);
+
+ /* Create a trace wrapper for the task port. */
+ ports_create_port (traced_class, traced_bucket, sizeof (*info), &info);
+ info->forward = traced_task;
+ ihash_add (traced_names, wrapper, info, NULL);
+
+ /* Make sure the traced task uses this wrapper. */
+ wrapper = ports_get_right (info);
+ mach_port_insert_right (mach_task_self (), wrapper,
+ wrapper, MACH_MSG_TYPE_MAKE_SEND);
+ task_set_special_port (traced_task, TASK_KERNEL_PORT, wrapper);
+
+ /* Now actually run the command they told us to trace. */
+ proc_child (getproc (), traced_task);
+ _hurd_exec (traced_task, file, cmd_argv, cmd_envp);
+
+ /* FIXME: falls through immediately if we don't spin */
+ for (;;) ;
+ return 0;
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'o':
+ ostream = fopen (arg, "w");
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ return EINVAL;
+
+ case ARGP_KEY_ARG:
+ cmd = arg;
+ cmd_argv = &state->argv[state->next-1];
+ cmd_envp = envp;
+ state->next = state->argc;
+ traced_thread = cthread_fork ((cthread_fn_t)
+ traced_thread_function, 0);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ const struct argp argp = { options, parse_opt, args_doc, doc };
+
+ traced_class = ports_create_class (0, 0);
+ traced_bucket = ports_create_bucket();
+
+ ihash_create (&traced_names);
+ ostream = stderr;
+
+ cthread_detach (cthread_fork ((cthread_fn_t)trace_thread_function,
+ traced_bucket));
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ cthread_join (traced_thread);
+
+ fprintf (stderr, "***************hola***************\n");
+ exit (0);
+}
+
+/*
+ Local Variables:
+ compile-command: "gcc -Wall -g -D_GNU_SOURCE=1 -o rpctrace rpctrace.c -lthreads -lports -lihash"
+ End:
+*/