bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH4/4] fully enable rpctrace to trace multitask programs.


From: Da Zheng
Subject: [PATCH4/4] fully enable rpctrace to trace multitask programs.
Date: Mon, 20 Jul 2009 19:44:06 +0800
User-agent: Thunderbird 2.0.0.22 (Macintosh/20090605)

The fourth patch is the main one, which fully enable rpctrace to trace 
multitask programs.

Zheng Da

2009-07-20  Zheng Da  <zhengda1936@gmail.com>

        * rpctrace.c (UNKNOWN_NAME): New variable.
        (task_info): New structure.
        (traced_task): Removed.
        (task_ihash): New variable.
        (unknown_task): Likewise.
        (add_task): New function.
        (remove_task): Likewise.
        (traced_info): Modified.
        (receiver_info): New structure.
        (sender_info): Likewise.
        (send_once_info): Likewise.
        (TRACED_INFO): New macro.
        (SEND_INFO): Likewise.
        (SEND_ONCE_INFO): Likewise.
        (req_info): New structure.
        (req_head): New variable.
        (add_request): New function.
        (remove_request): Likewise.
        (freelist): Different type.
        (notify_pi): New variable.
        (receive_right_list): Likewise.
        (dummy_wrapper): Likewise.
        (traced_names): Different initial value.
        (other_class): New variable.
        (print_request_header): Different parameter.
        (print_reply_header): Likewise.
        (new_receiver_info): New function.
        (destroy_receiver_info): Likewise.
        (new_send_wrapper): Redefined.
        (new_send_once_wrapper): Modified.
        (unlink_sender_info): New function.
        (traced_dropweak): Removed.
        (traced_clean): New function.
        (seen_receive_right): Likewise.
        (discover_receive_right): Likewise.
        (get_send_wrapper): Likewise.
        (rewrite_right): Redefined.
        (print_contents): Don't treat mach_port_insert_right specially.
        (wrap_all_threads): Use new structuress.
        (wrap_new_thread): Likewise.
        (wrap_new_task): New function.
        (trace_and_forward): Redefined.
        (expected_reply_port): Removed.
        (print_request_header): Use new structures.
        (print_reply_header): Likewise.
        (unfinished_line): Removed.
        (traced_spawn): Use new structures.
        (main): Initialize some global variables.

diff --git a/utils/rpctrace.c b/utils/rpctrace.c
index 23e4e00..de7c9a4 100644
--- a/utils/rpctrace.c
+++ b/utils/rpctrace.c
@@ -59,6 +59,8 @@ static const struct argp_option options[] =
   {0}
 };
 
+#define UNKNOWN_NAME MACH_PORT_NULL
+
 static const char args_doc[] = "COMMAND [ARG...]";
 static const char doc[] = "Trace Mach Remote Procedure Calls.";
 
@@ -79,10 +81,43 @@ msgid_ihash_cleanup (void *element, void *arg)
   free (info);
 }
 
+/* This structure stores the information of the traced task. */
+struct task_info
+{
+  task_t task;
+  boolean_t threads_wrapped;   /* All threads of the task has been wrapped? */
+};
+
 static struct hurd_ihash msgid_ihash
   = HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);
 
-task_t traced_task;
+static struct hurd_ihash task_ihash
+  = HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);
+
+task_t unknown_task;
+
+void
+add_task (task_t task)
+{
+  error_t err;
+  struct task_info *info = malloc (sizeof *info);
+
+  if (info == NULL)
+    error (1, 0, "Fail to allocate memory.");
+
+  info->task = task;
+  info->threads_wrapped = FALSE;
+  
+  err = hurd_ihash_add (&task_ihash, task, info);
+  if (err)
+    error (1, err, "hurd_ihash_add");
+}
+
+void
+remove_task (task_t task)
+{
+  hurd_ihash_remove (&task_ihash, task);
+}
 
 /* Parse a file of RPC names and message IDs as output by mig's -list
    option: "subsystem base-id routine n request-id reply-id".  Put each
@@ -188,45 +223,121 @@ msgid_trace_replies (const struct msgid_info *info)
 {
   return 1;
 }
+
 
-/* We keep one of these structures for each port right we are tracing.  */
+/* A common structure between sender_info and send_once_info */
 struct traced_info
 {
   struct port_info pi;
-
-  mach_port_t forward;         /* real port */
   mach_msg_type_name_t type;
+  char *name;                  /* null or a string describing this */
+};
+
+/* Each traced port has one receiver info and multiple send wrappers.
+ * The receiver info records the information of the receive right to
+ * the traced port, while send wrappers are created for each task
+ * who has the send right to the traced port.
+ */
 
+struct receiver_info
+{
   char *name;                  /* null or a string describing this */
+  hurd_ihash_locp_t locp;      /* position in the traced_names hash table */
+  mach_port_t portname;                /* The port name in the owner task. */
+  task_t task;                 /* The task who has the right. */
+  mach_port_t forward;         /* real port. */
+  struct receiver_info *receive_right; /* Link with other receive rights. */
+  struct sender_info *next;    /* The head of the send right list */
+};
+
+struct sender_info
+{
+  struct traced_info pi;
+  task_t task;                 /* The task who has the right. */
 
-  union
-  {
-    struct traced_info *nextfree; /* Link when on free list.  */
-
-    struct                     /* For a send right wrapper.  */
-    {
-      hurd_ihash_locp_t locp;  /* position in the traced_names hash table */
-    } send;
-
-    struct                     /* For a send-once right wrapper.  */
-    {
-      /* We keep track of the send right to which the message containing
-        this send-once right as its reply port was sent, and the msgid of
-        that request.  We don't hold a reference to the send right; it is
-        just a hint to indicate a match with a send right on which we just
-        forwarded a message.  */
-      mach_port_t sent_to;
-      mach_msg_id_t sent_msgid;
-    } send_once;
-  } u;
+  /* It is used to form the list of send rights for different tasks.
+   * The head is the receive right. */
+  struct sender_info *next;
+
+  struct receiver_info *receive_right; /* The corresponding receive right */
 };
+
+struct send_once_info
+{
+  struct traced_info pi;
+  mach_port_t forward;         /* real port. */
+
+  struct send_once_info *nextfree; /* Link when on free list.  */
+};
+
 #define INFO_SEND_ONCE(info) ((info)->type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+#define TRACED_INFO(info) ((struct traced_info *) info)
+#define SEND_INFO(info) ((struct sender_info *) info)
+#define SEND_ONCE_INFO(info) ((struct send_once_info *) info)
 
-static struct traced_info *freelist;
+/* This structure stores the information of the RPC requests. */
+struct req_info
+{
+  boolean_t is_req;
+  mach_msg_id_t req_id;
+  mach_port_t reply_port;
+  task_t from;
+  task_t to;
+  struct req_info *next;
+};
+
+static struct req_info *req_head = NULL;
+
+static struct req_info *
+add_request (mach_msg_id_t req_id, mach_port_t reply_port,
+            task_t from, task_t to)
+{
+  struct req_info *req = malloc (sizeof (*req));
+  if (!req)
+    error (1, 0, "cannot allocate memory");
+  req->req_id = req_id;
+  req->from = from;
+  req->to = to;
+  req->reply_port = reply_port;
+  req->is_req = TRUE;
+
+  req->next = req_head;
+  req_head = req;
+
+  return req;
+}
+
+static struct req_info *
+remove_request (mach_msg_id_t req_id, mach_port_t reply_port)
+{
+  struct req_info **prev;
+  struct req_info *req;
+
+  prev = &req_head;
+  while (*prev)
+    {
+      if ((*prev)->req_id == req_id && (*prev)->reply_port == reply_port)
+       break;
+      prev = &(*prev)->next;
+    }
+  if (*prev == NULL)
+    return NULL;
+
+  req = *prev;
+  *prev = req->next;
+  return req;
+}
+
+struct port_info *notify_pi;
+/* The list of receiver infos, but only the ones for the traced tasks. */
+struct receiver_info *receive_right_list;
+static struct traced_info dummy_wrapper;
+static struct send_once_info *freelist;
 
 struct hurd_ihash traced_names
-  = HURD_IHASH_INITIALIZER (offsetof (struct traced_info, u.send.locp));
+  = HURD_IHASH_INITIALIZER (offsetof (struct receiver_info, locp));
 struct port_class *traced_class;
+struct port_class *other_class;
 struct port_bucket *traced_bucket;
 FILE *ostream;
 
@@ -236,12 +347,13 @@ FILE *ostream;
 /* Called for a message that does not look like an RPC reply.
    The header has already been swapped into the sender's view
    with interposed ports.  */
-static void print_request_header (struct traced_info *info,
+static void print_request_header (struct sender_info *info,
                                  mach_msg_header_t *header);
 
 /* Called for a message that looks like an RPC reply.  */
-static void print_reply_header (struct traced_info *info,
-                               mig_reply_header_t *header);
+static void print_reply_header (struct send_once_info *info,
+                               mig_reply_header_t *header,
+                               struct req_info *req);
 
 /* Called for each data item (which might be an array).
    Always called after one of the above two.  */
@@ -249,42 +361,106 @@ static void print_data (mach_msg_type_name_t type,
                        const void *data,
                        mach_msg_type_number_t nelt,
                        mach_msg_type_number_t eltsize);
+
 
 /*** Mechanics of tracing messages and interposing on ports ***/
 
-
-/* Create a new wrapper port and do `ports_get_right' on it.  */
-static struct traced_info *
-new_send_wrapper (mach_port_t right, mach_port_t *wrapper_right)
+/* Create a new info for the receive right.
+ * It lives until the traced receive right dies. */
+static struct receiver_info *
+new_receiver_info (mach_port_t right, mach_port_t owner)
 {
   error_t err;
-  struct traced_info *info;
-
-  /* Use a free send-once wrapper port if we have one.  */
-  if (freelist)
-    {
-      info = freelist;
-      freelist = info->u.nextfree;
-    }
-  else
-    {
-      /* Create a new wrapper port that forwards to *RIGHT.  */
-      err = ports_create_port (traced_class, traced_bucket,
-                              sizeof *info, &info);
-      assert_perror (err);
-      info->name = 0;
-    }
+  struct receiver_info *info;
+  mach_port_t foo;
 
+  info = malloc (sizeof (*info));
+  if (!info)
+    error (1, 0, "cannot allocate memory");
   info->forward = right;
-  info->type = MACH_MSG_TYPE_MOVE_SEND;
+  info->task = owner;
+  info->portname = UNKNOWN_NAME;
+  info->receive_right = NULL;
+  info->next = NULL;
+  if (owner != unknown_task)
+    {
+      info->receive_right = receive_right_list;
+      receive_right_list = info;
+    }
+  info->name = 0;
+
+  /* Request the dead-name notification, so if the receive right is destroyed,
+   * we can destroy the wrapper. */
+  err = mach_port_request_notification (mach_task_self (), right,
+                                       MACH_NOTIFY_DEAD_NAME, 1,
+                                       notify_pi->port_right,
+                                       MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+  if (err)
+    error (2, err, "mach_port_request_notification");
+  mach_port_deallocate (mach_task_self (), foo);
 
-  /* Store it in the reverse-lookup hash table, so we can
-     look up this same right again to find the wrapper port.
-     The entry in the hash table holds a weak ref on INFO.  */
   err = hurd_ihash_add (&traced_names, info->forward, info);
+  if (err)
+    error (2, err, "hurd_ihash_add");
+  return info;
+}
+
+static void
+destroy_receiver_info (struct receiver_info *info)
+{
+  struct sender_info *send_wrapper;
+  struct receiver_info **prev;
+
+  mach_port_deallocate (mach_task_self (), info->forward);
+  /* Remove it from the receive right list. */
+  prev = &receive_right_list;
+  while (*prev != info && *prev)
+    prev = &((*prev)->receive_right);
+  /* If we find the receiver info in the list. */
+  if (*prev)
+    *prev = info->receive_right;
+  
+  send_wrapper = info->next;
+  while (send_wrapper)
+    {
+      struct sender_info *next = send_wrapper->next;
+      assert (TRACED_INFO (send_wrapper)->pi.refcnt == 1);
+      /* Reset the receive_right of the send wrapper in advance to avoid
+       * destroy_receiver_info is called when the port info is destroyed. */
+      send_wrapper->receive_right = NULL;
+      ports_destroy_right (send_wrapper);
+      send_wrapper = next;
+    }
+
+  hurd_ihash_locp_remove (&traced_names, info->locp);
+  free (info);
+}
+
+/* Create a new wrapper port and do `ports_get_right' on it.
+ *
+ * The wrapper lives until there is no send right to it,
+ * or the corresponding receiver info is destroyed.
+ */
+static struct sender_info *
+new_send_wrapper (struct receiver_info *receive, task_t task,
+                 mach_port_t *wrapper_right)
+{
+  error_t err;
+  struct sender_info *info;
+
+  /* Create a new wrapper port that forwards to *RIGHT.  */
+  err = ports_create_port (traced_class, traced_bucket,
+                          sizeof *info, &info);
   assert_perror (err);
-  ports_port_ref_weak (info);
-  assert (info->u.send.locp != 0);
+
+  TRACED_INFO (info)->name = 0;
+  asprintf (&TRACED_INFO (info)->name, "  %d<--%d(pid%d)", 
+           receive->forward, TRACED_INFO (info)->pi.port_right, task2pid 
(task));
+  TRACED_INFO (info)->type = MACH_MSG_TYPE_MOVE_SEND;
+  info->task = task;
+  info->receive_right = receive;
+  info->next = receive->next;
+  receive->next = info;
 
   *wrapper_right = ports_get_right (info);
   ports_port_deref (info);
@@ -293,17 +469,17 @@ new_send_wrapper (mach_port_t right, mach_port_t 
*wrapper_right)
 }
 
 /* Create a new wrapper port and do `ports_get_right' on it.  */
-static struct traced_info *
+static struct send_once_info *
 new_send_once_wrapper (mach_port_t right, mach_port_t *wrapper_right)
 {
   error_t err;
-  struct traced_info *info;
+  struct send_once_info *info;
 
   /* Use a free send-once wrapper port if we have one.  */
   if (freelist)
     {
       info = freelist;
-      freelist = info->u.nextfree;
+      freelist = info->nextfree;
     }
   else
     {
@@ -311,11 +487,12 @@ new_send_once_wrapper (mach_port_t right, mach_port_t 
*wrapper_right)
       err = ports_create_port (traced_class, traced_bucket,
                               sizeof *info, &info);
       assert_perror (err);
-      info->name = 0;
+      TRACED_INFO (info)->name = 0;
     }
 
   info->forward = right;
-  info->type = MACH_MSG_TYPE_MOVE_SEND_ONCE;
+  TRACED_INFO (info)->type = MACH_MSG_TYPE_MOVE_SEND_ONCE;
+  info->nextfree = NULL;
 
   /* Send-once rights never compare equal to any other right (even
      another send-once right), so there is no point in putting them
@@ -328,87 +505,286 @@ new_send_once_wrapper (mach_port_t right, mach_port_t 
*wrapper_right)
      receive a message on it.  The kernel automatically sends a
      MACH_NOTIFY_SEND_ONCE message if the send-once right dies.  */
 
-  *wrapper_right = info->pi.port_right;
-  memset (&info->u.send_once, 0, sizeof info->u.send_once);
+  *wrapper_right = TRACED_INFO (info)->pi.port_right;
 
   return info;
 }
 
+/* Unlink the send wrapper from the list. */
+static void
+unlink_sender_info (void *pi)
+{
+  struct sender_info *info = pi;
+  struct sender_info **prev;
+
+  if (info->receive_right)
+    {
+      /* Remove it from the send right list. */
+      prev = &info->receive_right->next;
+      while (*prev != info && *prev)
+       prev = &((*prev)->next);
+      assert (*prev);
+      *prev = info->next;
+
+      info->next = NULL;
+    }
+}
 
-/* This gets called when a wrapper port has no hard refs (send rights),
-   only weak refs.  The only weak ref is the one held in the reverse-lookup
-   hash table.  */
+/* The function is called when the port_info is going to be destroyed.
+ * If it's the last send wrapper for the traced port, the receiver info
+ * will also be destroyed. */
 static void
-traced_dropweak (void *pi)
+traced_clean (void *pi)
+{
+  struct sender_info *info = pi;
+
+  assert (TRACED_INFO (info)->type == MACH_MSG_TYPE_MOVE_SEND);
+  free (TRACED_INFO (info)->name);
+
+  if (info->receive_right)
+    {
+      unlink_sender_info (pi);
+
+      /* If this is the last send wrapper, it means that our traced port won't
+       * have any more send rights. We notify the owner of the receive right
+       * of that by deallocating the forward port. */
+      if (info->receive_right->next == NULL)
+       destroy_receiver_info (info->receive_right);
+
+      info->receive_right = NULL;
+    }
+}
+
+/* Check if the receive right has been seen. */
+boolean_t
+seen_receive_right (task_t task, mach_port_t name)
+{
+  struct receiver_info *info = receive_right_list;
+  while (info)
+    {
+      if (info->task == task && info->portname == name)
+       return TRUE;
+      info = info->receive_right;
+    }
+  return FALSE;
+}
+
+/* This function is to find the receive right for the send right 'send'
+ * among traced tasks. I assume that all receive rights are moved
+ * under the control of rpctrace.
+ *
+ * Note: 'send' shouldn't be the send right to the wrapper.
+ *
+ * Note: the receiver_info returned from the function
+ * might not be the receive right in the traced tasks.
+ * */
+struct receiver_info *
+discover_receive_right (mach_port_t send, task_t task)
 {
-  struct traced_info *const info = pi;
+  error_t err;
+  struct receiver_info *info = NULL;
 
-  assert (info->type == MACH_MSG_TYPE_MOVE_SEND);
-  assert (info->u.send.locp);
+  info = hurd_ihash_find (&traced_names, send);
+  /* If we have seen the send right or send once right. */
+  if (info
+      /* If the receive right is in one of traced tasks,
+       * but we don't know its name 
+       * (probably because the receive right has been moved),
+       * we need to find it out. */
+      && !(info->task != unknown_task
+         && info->portname == UNKNOWN_NAME))
+    return info;
+  
+    {
+      int j;
+      mach_port_t *portnames = NULL;
+      mach_msg_type_number_t nportnames = 0;
+      mach_port_type_t *porttypes = NULL;
+      mach_msg_type_number_t nporttypes = 0;
+      struct receiver_info *receiver_info = NULL;
 
-  /* Remove INFO from the hash table.  */
-  hurd_ihash_locp_remove (&traced_names, info->u.send.locp);
-  ports_port_deref_weak (info);
+      err = mach_port_names (task, &portnames, &nportnames,
+                            &porttypes, &nporttypes);
+      if (err == MACH_SEND_INVALID_DEST)
+       {
+         remove_task (task);
+         return 0;
+       }
+      if (err)
+       error (2, err, "mach_port_names");
 
-  /* Deallocate the forward port, so the real port also sees no-senders.  */
-  mach_port_deallocate (mach_task_self (), info->forward);
+      for (j = 0; j < nportnames; j++)
+       {
+         mach_port_status_t port_status;
+         mach_port_t send_right;
+         mach_msg_type_name_t type;
 
-  /* There are no rights to this port, so we can reuse it.
-     Add a hard ref and put INFO on the free list.  */
-  ports_port_ref (info);
+         if (!(porttypes[j] & MACH_PORT_TYPE_RECEIVE) /* not a receive right */
+             || seen_receive_right (task, portnames[j]))
+           continue;
 
-  free (info->name);
-  info->name = 0;
+         err = mach_port_get_receive_status (task, portnames[j],
+                                             &port_status);
+         if (err)
+           error (2, err, "mach_port_get_receive_status");
+         /* If the port doesn't have the send right, skip it. */
+         if (!port_status.mps_srights)
+           continue;
 
-  info->u.nextfree = freelist;
-  freelist = info;
+         err = mach_port_extract_right (task, portnames[j],
+                                        MACH_MSG_TYPE_MAKE_SEND,
+                                        &send_right, &type);
+         if (err)
+           error (2, err, "mach_port_extract_right");
+
+         if (/* We have seen this send right before. */
+             hurd_ihash_find (&traced_names, send_right)
+             || send_right != send     /* It's not the port we want. */)
+           {
+             mach_port_deallocate (mach_task_self (), send_right);
+             continue;
+           }
+
+         /* We have found the receive right we want. */
+         receiver_info = new_receiver_info (send_right, task);
+         receiver_info->portname = portnames[j];
+         break;
+       }
+      if (portnames)
+       vm_deallocate (mach_task_self (), (vm_address_t) portnames,
+                      nportnames * sizeof (*portnames));
+      if (porttypes)
+       vm_deallocate (mach_task_self (), (vm_address_t) porttypes,
+                      nporttypes * sizeof (*porttypes));
+
+      if (receiver_info)
+       return receiver_info;
+    }
+  return NULL;
 }
 
+/* get_send_wrapper searches for the send wrapper for the target task.
+   If it doesn't exist, create a new one. */
+struct sender_info *
+get_send_wrapper (struct receiver_info *receiver_info,
+                 mach_port_t task, mach_port_t *right)
+{
+  struct sender_info *info = receiver_info->next;
+  
+  while (info)
+    {
+      if (info->task == task)
+       {
+         *right = ports_get_right (info);
+         return info;
+       }
+      info = info->next;
+    }
+  /* No send wrapper is found. */
+  return new_send_wrapper (receiver_info, task, right);
+}
 
 /* Rewrite a port right in a message with an appropriate wrapper port.  */
-static struct traced_info *
-rewrite_right (mach_port_t *right, mach_msg_type_name_t *type)
+static char *
+rewrite_right (mach_port_t *right, mach_msg_type_name_t *type,
+              struct req_info *req)
 {
   error_t err;
-  struct traced_info *info;
+  struct receiver_info *receiver_info;
+  struct sender_info *send_wrapper;
+  task_t dest = unknown_task;
+  task_t source = unknown_task;
 
   /* We can never do anything special with a null or dead port right.  */
   if (!MACH_PORT_VALID (*right))
     return 0;
 
+  if (req)
+    {
+      if (req->is_req)    /* It's a RPC request. */
+       {
+         source = req->from;
+         dest = req->to;
+       }
+      else
+       {
+         source = req->to;
+         dest = req->from;
+       }
+    }
+
   switch (*type)
     {
     case MACH_MSG_TYPE_PORT_SEND:
-      /* See if we are already tracing this port.  */
-      info = hurd_ihash_find (&traced_names, *right);
-      if (info)
-       {
-         /* We are already tracing this port.  We will pass on a right
-            to our existing wrapper port.  */
-         *right = ports_get_right (info);
-         *type = MACH_MSG_TYPE_MAKE_SEND;
-         return info;
-       }
+      /* The strategy for moving the send right is: if the destination task
+       * has the receive right, we move the send right of the traced port to
+       * the destination; otherwise, we move the one of the send wrapper.
+       */
+      assert (req);
 
       /* See if this is already one of our own wrapper ports.  */
-      info = ports_lookup_port (traced_bucket, *right, 0);
-      if (info)
+      send_wrapper = ports_lookup_port (traced_bucket, *right, 0);
+      if (send_wrapper)
        {
-         /* This is a send right to one of our own wrapper ports.
-            Instead, send along the original send right.  */
+         /* This is a send right to one of our own wrapper ports. */
          mach_port_deallocate (mach_task_self (), *right); /* eat msg ref */
-         *right = info->forward;
-         err = mach_port_mod_refs (mach_task_self (), *right,
-                                   MACH_PORT_RIGHT_SEND, +1);
-         assert_perror (err);
-         ports_port_deref (info);
-         return info;
+
+         /* If the send right is moved to the task with the receive right,
+          * copy the send right in 'forward' of receiver info to the 
destination.
+          * Otherwise, copy the send right to the send wrapper. */
+         assert (send_wrapper->receive_right);
+         if (dest == send_wrapper->receive_right->task)
+           {
+             *right = send_wrapper->receive_right->forward;
+             err = mach_port_mod_refs (mach_task_self (), *right,
+                                       MACH_PORT_RIGHT_SEND, +1);
+             if (err)
+               error (2, err, "mach_port_mod_refs");
+             ports_port_deref (send_wrapper);
+           }
+         else
+           {
+             struct sender_info *send_wrapper2
+               = get_send_wrapper (send_wrapper->receive_right, dest, right);
+             ports_port_deref (send_wrapper);
+             *type = MACH_MSG_TYPE_MAKE_SEND;
+             send_wrapper = send_wrapper2;
+           }
+         return TRACED_INFO (send_wrapper)->name;
        }
 
-      /* We have never seen this port before.  Create a new wrapper port
-        and replace the right in the message with a right to it.  */
-      *type = MACH_MSG_TYPE_MAKE_SEND;
-      return new_send_wrapper (*right, right);
+      if (req->req_id == 3216)     /* mach_port_extract_right */
+       receiver_info = discover_receive_right (*right, dest);
+      else
+       receiver_info = discover_receive_right (*right, source);
+      if (receiver_info == NULL)
+       {
+         /* It's unusual to see an unknown send right from a traced task.
+          * We ignore it. */
+         if (source != unknown_task)
+           {
+             error (0, 0, "get an unknown send right from process %d",
+                    task2pid (source));
+             return dummy_wrapper.name;
+           }
+         /* The receive right is owned by an unknown task. */
+         receiver_info = new_receiver_info (*right, unknown_task);
+         mach_port_mod_refs (mach_task_self (), *right,
+                             MACH_PORT_RIGHT_SEND, 1);
+       }
+      /* If the send right is moved to the task with the receive right,
+       * don't do anything. 
+       * Otherwise, we translate it into the one to the send wrapper. */
+      if (dest == receiver_info->task)
+       return receiver_info->name;
+      else
+       {
+         assert (*right == receiver_info->forward);
+         mach_port_deallocate (mach_task_self (), *right);
+         send_wrapper = get_send_wrapper (receiver_info, dest, right);
+         *type = MACH_MSG_TYPE_MAKE_SEND;
+         return TRACED_INFO (send_wrapper)->name;
+       }
 
     case MACH_MSG_TYPE_PORT_SEND_ONCE:
       /* There is no way to know if this send-once right is to the same
@@ -418,62 +794,99 @@ rewrite_right (mach_port_t *right, mach_msg_type_name_t 
*type)
         make a new send-once wrapper object, that will trace the one
         message it receives, and then die.  */
       *type = MACH_MSG_TYPE_MAKE_SEND_ONCE;
-      return new_send_once_wrapper (*right, right);
+      return TRACED_INFO (new_send_once_wrapper (*right, right))->name;
 
     case MACH_MSG_TYPE_PORT_RECEIVE:
-      /* We have got a receive right, call it A.  We will pass along a
-        different receive right of our own, call it B.  We ourselves will
-        receive messages on A, trace them, and forward them on to B.
-
-        If A is the receive right to a send right that we have wrapped,
-        then B must be that wrapper receive right, moved from us to the
-        intended receiver of A--that way it matches previous send rights
-        to A that were sent through and replaced with our wrapper (B).
-        If not, we create a new receive right.  */
+      /* We have got a receive right, call it A and the send wrapper for
+       * the destination task is denoted as B (if the destination task
+       * doesn't have the send wrapper, we create it before moving receive
+       * right).
+       * We wrap the receive right A in the send wrapper and move the receive
+       * right B to the destination task.  */
       {
-       mach_port_t rr;         /* B */
-       char *name;
-
-       info = hurd_ihash_find (&traced_names, *right);
-       if (info)
+       assert (req);
+       receiver_info = hurd_ihash_find (&traced_names, *right);
+       if (receiver_info)
          {
-           /* This is a receive right that we have been tracing sends to.  */
-           name = info->name;
-           rr = ports_claim_right (info);
-           /* That released the refs on INFO, so it's been freed now.  */
+           struct sender_info *send_wrapper2;
+           char *name;
+           mach_port_t rr;
+
+           /* The port A has at least one send right - the one in
+            * receiver_info->forward. If the source task doesn't have
+            * the send right, the port A will be destroyed after we
+            * deallocate the only send right. */
+
+           /* We have to deallocate the send right in
+            * receiver_info->forward before we import the port to port_info.
+            * So the reference count in the imported port info will be 1,
+            * if it doesn't have any other send rights. */
+           mach_port_deallocate (mach_task_self (), receiver_info->forward);
+           err = ports_import_port (traced_class, traced_bucket,
+                                    *right, sizeof *send_wrapper,
+                                    &send_wrapper);
+           if (err)
+             error (2, err, "ports_import_port");
+
+           TRACED_INFO (send_wrapper)->type = MACH_MSG_TYPE_MOVE_SEND;
+           send_wrapper->task = source;
+           TRACED_INFO (send_wrapper)->name = receiver_info->name;
+           /* Initialize them in case that the source task doesn't
+            * have the send right to the port, and the port will
+            * be destroyed immediately. */
+           send_wrapper->receive_right = NULL;
+           send_wrapper->next = NULL;
+           ports_port_deref (send_wrapper);
+
+           hurd_ihash_locp_remove (&traced_names, receiver_info->locp);
+
+           send_wrapper2 = get_send_wrapper (receiver_info, dest, &rr);
+           assert (TRACED_INFO (send_wrapper2)->pi.refcnt == 1);
+           name = TRACED_INFO (send_wrapper2)->name;
+           TRACED_INFO (send_wrapper2)->name = NULL;
+           /* send_wrapper2 isn't destroyed normally, so we need to unlink
+            * it from the send wrapper list before calling ports_claim_right */
+           unlink_sender_info (send_wrapper2);
+           send_wrapper2->receive_right = NULL;
+           rr = ports_claim_right (send_wrapper2);
+           /* Get us a send right that we will forward on.  */
+           err = mach_port_insert_right (mach_task_self (), rr, rr,
+                                         MACH_MSG_TYPE_MAKE_SEND);
+           if (err)
+             error (2, err, "mach_port_insert_right");
+           receiver_info->forward = rr;
+           receiver_info->task = dest;
+           if (dest != unknown_task)
+             {
+               receiver_info->receive_right = receive_right_list;
+               receive_right_list = receiver_info;
+             }
+           /* The port name will be discovered
+            * when we search for this receive right. */
+           receiver_info->portname = UNKNOWN_NAME;
+           receiver_info->name = name;
+
+           send_wrapper->receive_right = receiver_info;
+           send_wrapper->next = receiver_info->next;
+           receiver_info->next = send_wrapper;
+
+           err = hurd_ihash_add (&traced_names, receiver_info->forward,
+                                 receiver_info);
+           if (err)
+             error (2, err, "hurd_ihash_add");
+           *right = rr;
          }
        else
          {
-           /* This is a port we know nothing about.  */
-           rr = mach_reply_port ();
-           name = 0;
+           /* Weird? no send right for the port. */
+           err = mach_port_insert_right (mach_task_self (), *right, *right,
+                                         MACH_MSG_TYPE_MAKE_SEND);
+           if (err)
+             error (2, err, "mach_port_insert_right");
+           receiver_info = new_receiver_info (*right, dest);
          }
 
-       /* Create a new wrapper object that receives on this port.  */
-       err = ports_import_port (traced_class, traced_bucket,
-                                *right, sizeof *info, &info);
-       assert_perror (err);
-       info->name = name;
-       info->type = MACH_MSG_TYPE_MOVE_SEND; /* XXX ? */
-
-       /* Get us a send right that we will forward on.  */
-       err = mach_port_insert_right (mach_task_self (), rr, rr,
-                                     MACH_MSG_TYPE_MAKE_SEND);
-       assert_perror (err);
-       info->forward = rr;
-
-       err = hurd_ihash_add (&traced_names, info->forward, info);
-       assert_perror (err);
-       ports_port_ref_weak (info);
-
-       /* If there are no extant send rights to this port, then INFO will
-          die right here and release its send right to RR.
-          XXX what to do?
-       */
-       ports_port_deref (info);
-
-       *right = rr;
-       return info;
+       return receiver_info->name;
       }
 
     default:
@@ -484,7 +897,7 @@ rewrite_right (mach_port_t *right, mach_msg_type_name_t 
*type)
 
 static void
 print_contents (mach_msg_header_t *inp,
-               void *msg_buf_ptr)
+               void *msg_buf_ptr, struct req_info *req)
 {
   error_t err;
 
@@ -543,7 +956,6 @@ print_contents (mach_msg_header_t *inp,
          mach_msg_type_number_t i;
          mach_msg_type_name_t newtypes[nelt];
          int poly;
-         struct traced_info *ti;
 
          assert (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX);
          assert (eltsize == sizeof (mach_port_t));
@@ -551,19 +963,11 @@ print_contents (mach_msg_header_t *inp,
          poly = 0;
          for (i = 0; i < nelt; ++i)
            {
+             char *str;
+
              newtypes[i] = name;
 
-             if (inp->msgh_id == 3215) /* mach_port_insert_right */
-               {
-                 /* XXX
-                  */
-                 fprintf (ostream,
-                          "\t\t[%d] = pass through port %d, type %d\n",
-                          i, portnames[i], name);
-                 continue;
-               }
-
-             ti = rewrite_right (&portnames[i], &newtypes[i]);
+             str = rewrite_right (&portnames[i], &newtypes[i], req);
 
              putc ((i == 0 && nelt > 1) ? '{' : ' ', ostream);
 
@@ -573,9 +977,8 @@ print_contents (mach_msg_header_t *inp,
                fprintf (ostream, "(dead)");
              else
                {
-                 assert (ti);
-                 if (ti->name != 0)
-                   fprintf (ostream, "%s", ti->name);
+                 if (str != 0)
+                   fprintf (ostream, "%s", str);
                  else
                    fprintf (ostream, "%3u", (unsigned int) portnames[i]);
                }
@@ -646,11 +1049,12 @@ print_contents (mach_msg_header_t *inp,
     }
 }
 
-/* Wrap all thread port in the task */
+/* Wrap all thread ports in the task */
 static void
 wrap_all_threads (task_t task)
 {
-  struct traced_info *thread_send_wrapper;
+  struct sender_info *thread_send_wrapper;
+  struct receiver_info *thread_receiver_info;
   thread_t *threads = NULL;
   size_t nthreads = 0;
   error_t err;
@@ -661,14 +1065,18 @@ wrap_all_threads (task_t task)
 
   for (int i = 0; i < nthreads; i++)
     {
-      thread_send_wrapper = hurd_ihash_find (&traced_names, threads[i]);
+      thread_receiver_info = hurd_ihash_find (&traced_names, threads[i]);
       /* We haven't seen the port. */
-      if (thread_send_wrapper == NULL)
+      if (thread_receiver_info == NULL)
        {
          mach_port_t new_thread_port;
-         thread_send_wrapper = new_send_wrapper (threads[i], &new_thread_port);
-         free (thread_send_wrapper->name);
-         asprintf (&thread_send_wrapper->name, "thread%d", threads[i]);
+
+         thread_receiver_info = new_receiver_info (threads[i], unknown_task);
+         thread_send_wrapper = new_send_wrapper (thread_receiver_info,
+                                                 task, &new_thread_port);
+         free (TRACED_INFO (thread_send_wrapper)->name);
+         asprintf (&TRACED_INFO (thread_send_wrapper)->name,
+                   "thread%d(pid%d)", threads[i], task2pid (task));
 
          err = mach_port_insert_right (mach_task_self (),
                                        new_thread_port, new_thread_port,
@@ -688,7 +1096,7 @@ wrap_all_threads (task_t task)
 
 /* Wrap the new thread port that is in the message. */
 static void
-wrap_new_thread (mach_msg_header_t *inp)
+wrap_new_thread (mach_msg_header_t *inp, struct req_info *req)
 {
   error_t err;
   mach_port_t thread_port;
@@ -702,27 +1110,81 @@ wrap_new_thread (mach_msg_header_t *inp)
     } *reply = (void *) inp;
   /* This function is called after rewrite_right,
    * so the wrapper for the thread port has been created. */
-  struct traced_info *send_wrapper = ports_lookup_port (traced_bucket,
+  struct sender_info *send_wrapper = ports_lookup_port (traced_bucket,
                                                        reply->child_thread, 0);
 
   assert (send_wrapper);
+  assert (send_wrapper->receive_right);
   err = mach_port_insert_right (mach_task_self (), reply->child_thread,
                                reply->child_thread, MACH_MSG_TYPE_MAKE_SEND);
   if (err)
     error (2, err, "mach_port_insert_right");
-  thread_port = send_wrapper->forward;
+  thread_port = send_wrapper->receive_right->forward;
   err = thread_set_kernel_port (thread_port, reply->child_thread);
   if (err)
     error (2, err, "thread_set_kernel_port");
-  free (send_wrapper->name);
-  asprintf (&send_wrapper->name, "thread%d", thread_port);
+  free (TRACED_INFO (send_wrapper)->name);
+  asprintf (&TRACED_INFO (send_wrapper)->name, "thread%d(pid%d)",
+           thread_port, task2pid (req->from));
   mach_port_deallocate (mach_task_self (), reply->child_thread);
   ports_port_deref (send_wrapper);
 }
 
+/* Wrap the new task port that is in the message. */
+static void
+wrap_new_task (mach_msg_header_t *inp, struct req_info *req)
+{
+  error_t err;
+  pid_t pid;
+  task_t pseudo_task_port;
+  task_t task_port;
+  struct
+    {
+      mach_msg_header_t head;
+      mach_msg_type_t retcode_type;
+      kern_return_t retcode;
+      mach_msg_type_t child_task_type;
+      mach_port_t child_task;
+    } *reply = (void *) inp;
+  /* The send wrapper of the new task for the father task */
+  struct sender_info *task_wrapper1 = ports_lookup_port (traced_bucket,
+                                                      reply->child_task, 0);
+  /* The send wrapper for the new task itself. */
+  struct sender_info *task_wrapper2;
+
+  assert (task_wrapper1);
+  assert (task_wrapper1->receive_right);
+
+  task_port = task_wrapper1->receive_right->forward;
+  add_task (task_port);
+
+  task_wrapper2 = new_send_wrapper (task_wrapper1->receive_right,
+                                   task_port, &pseudo_task_port);
+  err = mach_port_insert_right (mach_task_self (),
+                               pseudo_task_port, pseudo_task_port,
+                               MACH_MSG_TYPE_MAKE_SEND);
+  if (err)
+    error (2, err, "mach_port_insert_right");
+  err = task_set_kernel_port (task_port, pseudo_task_port);
+  if (err)
+    error (2, err, "task_set_kernel_port");
+  mach_port_deallocate (mach_task_self (), pseudo_task_port);
+
+  pid = task2pid (task_port);
+  free (TRACED_INFO (task_wrapper1)->name);
+  asprintf (&TRACED_INFO (task_wrapper1)->name, "task%d(pid%d)",
+           task_port, task2pid (req->from));
+  free (TRACED_INFO (task_wrapper2)->name);
+  asprintf (&TRACED_INFO (task_wrapper2)->name, "task%d(pid%d)",
+           task_port, pid);
+  ports_port_deref (task_wrapper1);
+}
+
 int
 trace_and_forward (mach_msg_header_t *inp, mach_msg_header_t *outp)
 {
+  mach_port_t reply_port;
+
   const mach_msg_type_t RetCodeType =
   {
     MACH_MSG_TYPE_INTEGER_32,  /* msgt_name = */
@@ -749,19 +1211,28 @@ trace_and_forward (mach_msg_header_t *inp, 
mach_msg_header_t *outp)
      with a send-once right, even if there have never really been any.  */
   if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE)
     {
-      if (inp->msgh_id == MACH_NOTIFY_DEAD_NAME)
+      if (inp->msgh_id == MACH_NOTIFY_DEAD_NAME && info == (void *) notify_pi)
        {
-         /* If INFO is a send-once wrapper, this could be a forged
-            notification; oh well.  XXX */
-
+         struct receiver_info *receiver_info;
          const mach_dead_name_notification_t *const n = (void *) inp;
 
-         assert (n->not_port == info->forward);
          /* Deallocate extra ref allocated by the notification.  */
          mach_port_deallocate (mach_task_self (), n->not_port);
-         ports_destroy_right (info);
-         ports_port_deref (info);
+         receiver_info = hurd_ihash_find (&traced_names, n->not_port);
+         /* The receiver info might have been destroyed.
+          * If not, we destroy it here. */
+         if (receiver_info)
+           {
+             assert (n->not_port == receiver_info->forward);
+             destroy_receiver_info (receiver_info);
+           }
+
          ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+         ports_port_deref (info);
+         
+         /* It might be a task port. Remove the dead task from the list. */
+         remove_task (n->not_port);
+
          return 1;
        }
       else if (inp->msgh_id == MACH_NOTIFY_NO_SENDERS
@@ -776,8 +1247,17 @@ trace_and_forward (mach_msg_header_t *inp, 
mach_msg_header_t *outp)
          ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
          return 1;
        }
+      /* Get some unexpected notification for rpctrace itself,
+       * TODO ignore them for now. */
+      else if (info == (void *) notify_pi)
+       {
+         ports_port_deref (info);
+         ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+         return 1;
+       }
     }
 
+  assert (info != (void *) notify_pi);
   assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == info->type);
 
   complex = inp->msgh_bits & MACH_MSGH_BITS_COMPLEX;
@@ -788,31 +1268,43 @@ trace_and_forward (mach_msg_header_t *inp, 
mach_msg_header_t *outp)
   {
     mach_msg_type_name_t this_type = MACH_MSGH_BITS_LOCAL (inp->msgh_bits);
     mach_msg_type_name_t reply_type = MACH_MSGH_BITS_REMOTE (inp->msgh_bits);
+    
+    /* Save the original reply port in the RPC request. */
+    reply_port = inp->msgh_remote_port;
 
     inp->msgh_local_port = inp->msgh_remote_port;
-    if (reply_type && msgid_trace_replies (msgid))
+    if (reply_type && msgid_trace_replies (msgid)
+       /* The reply port might be dead, e.g., the traced task has died. */
+       && MACH_PORT_VALID (inp->msgh_local_port))
       {
-       struct traced_info *info;
-       info = rewrite_right (&inp->msgh_local_port, &reply_type);
-       assert (info);
-       if (info->name == 0)
+       struct send_once_info *info;
+       // TODO is the reply port always a send once right?
+       assert (reply_type == MACH_MSG_TYPE_PORT_SEND_ONCE);
+       info = new_send_once_wrapper (inp->msgh_local_port,
+                                     &inp->msgh_local_port);
+       reply_type = MACH_MSG_TYPE_MAKE_SEND_ONCE;
+       assert (inp->msgh_local_port);
+
+       if (TRACED_INFO (info)->name == 0)
          {
            if (msgid == 0)
-             asprintf (&info->name, "reply(%u:%u)",
-                       (unsigned int) info->pi.port_right,
+             asprintf (&TRACED_INFO (info)->name, "reply(%u:%u)",
+                       (unsigned int) TRACED_INFO (info)->pi.port_right,
                        (unsigned int) inp->msgh_id);
            else
-             asprintf (&info->name, "reply(%u:%s)",
-                       (unsigned int) info->pi.port_right, msgid->name);
-         }
-       if (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
-         {
-           info->u.send_once.sent_to = info->pi.port_right;
-           info->u.send_once.sent_msgid = inp->msgh_id;
+             asprintf (&TRACED_INFO (info)->name, "reply(%u:%s)",
+                       (unsigned int) TRACED_INFO (info)->pi.port_right,
+                       msgid->name);
          }
       }
 
-    inp->msgh_remote_port = info->forward;
+    if (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+      inp->msgh_remote_port = SEND_ONCE_INFO (info)->forward;
+    else
+      {
+       assert (SEND_INFO (info)->receive_right);
+       inp->msgh_remote_port = SEND_INFO (info)->receive_right->forward;
+      }
     if (this_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
       {
        /* We have a message to forward for a send-once wrapper object.
@@ -822,8 +1314,9 @@ trace_and_forward (mach_msg_header_t *inp, 
mach_msg_header_t *outp)
           we are consuming its `forward' right in the message we send.  */
        free (info->name);
        info->name = 0;
-       info->u.nextfree = freelist;
-       freelist = info;
+       SEND_ONCE_INFO (info)->forward = 0;
+       SEND_ONCE_INFO (info)->nextfree = freelist;
+       freelist = SEND_ONCE_INFO (info);
       }
     else
       this_type = MACH_MSG_TYPE_COPY_SEND;
@@ -839,34 +1332,81 @@ trace_and_forward (mach_msg_header_t *inp, 
mach_msg_header_t *outp)
       if (inp->msgh_local_port == MACH_PORT_NULL
          && info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE
          && inp->msgh_size >= sizeof (mig_reply_header_t)
+         /* The notification message is considered as a request. */
+         && (inp->msgh_id > 72 || inp->msgh_id < 64)
          && (*(int *) &((mig_reply_header_t *) inp)->RetCodeType
              == *(int *)&RetCodeType))
        {
+         struct req_info *req = remove_request (inp->msgh_id - 100,
+                                                inp->msgh_remote_port);
+         assert (req);
+         req->is_req = FALSE;
          /* This sure looks like an RPC reply message.  */
          mig_reply_header_t *rh = (void *) inp;
-         print_reply_header (info, rh);
+         print_reply_header ((struct send_once_info *) info, rh, req);
          putc (' ', ostream);
-         print_contents (&rh->Head, rh + 1);
+         fflush (ostream);
+         print_contents (&rh->Head, rh + 1, req);
          putc ('\n', ostream);
 
          if (inp->msgh_id == 2161)/* the reply message for thread_create */
-           wrap_new_thread (inp);
+           wrap_new_thread (inp, req);
+         else if (inp->msgh_id == 2107) /* for task_create */
+           wrap_new_task (inp, req);
+
+         free (req);
        }
       else
        {
+         struct task_info *task_info;
+         task_t to = 0;
+         struct req_info *req = NULL;
+
          /* Print something about the message header.  */
-         print_request_header (info, inp);
-         print_contents (inp, inp + 1);
+         print_request_header ((struct sender_info *) info, inp);
+         /* It's a nofication message. */
+         if (inp->msgh_id <= 72 && inp->msgh_id >= 64)
+           {
+             assert (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE);
+             /* mach_notify_port_destroyed message has a port,
+              * TODO how do I handle it? */
+             assert (inp->msgh_id != 69);
+           }
+
+         /* If it's mach_port RPC,
+          * the port rights in the message will be moved to the target task. */
+         else if (inp->msgh_id >= 3200 && inp->msgh_id <= 3218)
+           to = SEND_INFO (info)->receive_right->forward;
+         else
+           to = SEND_INFO (info)->receive_right->task;
+         if (info->type == MACH_MSG_TYPE_MOVE_SEND)
+           req = add_request (inp->msgh_id, reply_port,
+                              SEND_INFO (info)->task, to);
+
+         /* If it's the notification message, req is NULL.
+          * TODO again, it's difficult to handle mach_notify_port_destroyed */
+         print_contents (inp, inp + 1, req);
          if (inp->msgh_local_port == MACH_PORT_NULL) /* simpleroutine */
-           fprintf (ostream, ");\n");
+           {
+             /* If it's a simpleroutine,
+              * we don't need the request information any more. */
+             req = remove_request (inp->msgh_id, reply_port);
+             free (req);
+             fprintf (ostream, ");\n");
+           }
          else
            /* Leave a partial line that will be finished later.  */
            fprintf (ostream, ")");
+         fflush (ostream);
 
-         /* If it's the request of exec_startup_get_info,
-          * it means that the traced process starts to run */
-         if (inp->msgh_id == 30500)
-           wrap_all_threads (traced_task);
+         /* If it's the first request from the traced task,
+          * wrap the all threads in the task. */
+         task_info = hurd_ihash_find (&task_ihash, SEND_INFO (info)->task);
+         if (task_info && !task_info->threads_wrapped)
+           {
+             wrap_all_threads (SEND_INFO (info)->task);
+             task_info->threads_wrapped = TRUE;
+           }
        }
     }
 
@@ -929,19 +1469,16 @@ static const char *const msg_types[] =
 };
 #endif
 
-static mach_port_t expected_reply_port;
-
 static void
-print_request_header (struct traced_info *receiver, mach_msg_header_t *msg)
+print_request_header (struct sender_info *receiver, mach_msg_header_t *msg)
 {
   const char *msgname = msgid_name (msg->msgh_id);
 
-  expected_reply_port = msg->msgh_local_port;
-
-  if (receiver->name != 0)
-    fprintf (ostream, "%4s->", receiver->name);
+  if (TRACED_INFO (receiver)->name != 0)
+    fprintf (ostream, "%4s->", TRACED_INFO (receiver)->name);
   else
-    fprintf (ostream, "%4u->", (unsigned int) receiver->pi.port_right);
+    fprintf (ostream, "%4u->",
+            (unsigned int) TRACED_INFO (receiver)->pi.port_right);
 
   if (msgname != 0)
     fprintf (ostream, "%5s (", msgname);
@@ -950,57 +1487,17 @@ print_request_header (struct traced_info *receiver, 
mach_msg_header_t *msg)
 }
 
 static void
-unfinished_line (void)
+print_reply_header (struct send_once_info *info, mig_reply_header_t *reply,
+                   struct req_info *req)
 {
-  /* A partial line was printed by print_request_header, but
-     cannot be finished before we print something else.
-     Finish this line with the name of the reply port that
-     will appear in the disconnected reply later on.  */
-  fprintf (ostream, " > %4u ...\n", expected_reply_port);
-}
-
-static void
-print_reply_header (struct traced_info *info, mig_reply_header_t *reply)
-{
-  if (info->pi.port_right == expected_reply_port)
-    {
-      /* We have printed a partial line for the request message,
-        and now we have the corresponding reply.  */
-      if (reply->Head.msgh_id == info->u.send_once.sent_msgid + 100)
-       fprintf (ostream, " = "); /* normal case */
-      else
-       /* This is not the proper reply message ID.  */
-       fprintf (ostream, " =(%u != %u) ",
-                reply->Head.msgh_id,
-                info->u.send_once.sent_msgid + 100);
-    }
+  /* We have printed a partial line for the request message,
+     and now we have the corresponding reply.  */
+  if (reply->Head.msgh_id == req->req_id + 100)
+    fprintf (ostream, " = "); /* normal case */
   else
-    {
-      /* This does not match up with the last thing printed.  */
-      if (expected_reply_port != MACH_PORT_NULL)
-       /* We don't print anything if the last call was a simpleroutine.  */
-       unfinished_line ();
-      if (info->name == 0)
-       /* This was not a reply port in previous message sent
-          through our wrappers.  */
-       fprintf (ostream, "reply?%4u",
-                (unsigned int) info->pi.port_right);
-      else
-       fprintf (ostream, "%s%4u",
-                info->name, (unsigned int) info->pi.port_right);
-      if (reply->Head.msgh_id == info->u.send_once.sent_msgid + 100)
-       /* This is a normal reply to a previous request.  */
-       fprintf (ostream, " > ");
-      else
-       {
-         /* Weirdo.  */
-         const char *msgname = msgid_name (reply->Head.msgh_id);
-         if (msgname == 0)
-           fprintf (ostream, " >(%u) ", reply->Head.msgh_id);
-         else
-           fprintf (ostream, " >(%s) ", msgname);
-       }
-    }
+    /* This is not the proper reply message ID.  */
+    fprintf (ostream, " =(%u != %u) ",
+            reply->Head.msgh_id, req->req_id + 100);
 
   if (reply->RetCode == 0)
     fprintf (ostream, "0");
@@ -1012,8 +1509,6 @@ print_reply_header (struct traced_info *info, 
mig_reply_header_t *reply)
       else
        fprintf (ostream, "%#x (%s)", reply->RetCode, str);
     }
-
-  expected_reply_port = MACH_PORT_NULL;
 }
 
 
@@ -1108,7 +1603,9 @@ traced_spawn (char **argv, char **envp)
   error_t err;
   pid_t pid;
   mach_port_t task_wrapper;
-  struct traced_info *ti;
+  task_t traced_task;
+  struct sender_info *ti;
+  struct receiver_info *receive_ti;
   file_t file = file_name_path_lookup (argv[0], getenv ("PATH"),
                                       O_EXEC, 0, 0);
 
@@ -1122,6 +1619,7 @@ traced_spawn (char **argv, char **envp)
                     0, &traced_task);
   assert_perror (err);
 
+  add_task (traced_task);
   /* Declare the new task to be our child.  This is what a fork does.  */
   err = proc_child (getproc (), traced_task);
   if (err)
@@ -1130,9 +1628,12 @@ traced_spawn (char **argv, char **envp)
   if (pid < 0)
     error (2, errno, "task2pid");
 
+  receive_ti = new_receiver_info (traced_task, unknown_task);
   /* Create a trace wrapper for the task port.  */
-  ti = new_send_wrapper (traced_task, &task_wrapper);/* consumes ref */
-  asprintf (&ti->name, "task%d", (int) pid);
+  ti = new_send_wrapper (receive_ti, traced_task, &task_wrapper);
+  ti->task = traced_task;
+  free (TRACED_INFO (ti)->name);
+  asprintf (&TRACED_INFO (ti)->name, "task%d(pid%d)", traced_task, pid);
 
   /* Replace the task's kernel port with the wrapper.  When this task calls
      `mach_task_self ()', it will get our wrapper send right instead of its
@@ -1208,6 +1709,7 @@ main (int argc, char **argv, char **envp)
   bool nostdinc = FALSE;
   const char *outfile = 0;
   char **cmd_argv = 0;
+  error_t err;
 
   /* Parse our options...  */
   error_t parse_opt (int key, char *arg, struct argp_state *state)
@@ -1252,6 +1754,10 @@ main (int argc, char **argv, char **envp)
   /* Parse our arguments.  */
   argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
 
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_DEAD_NAME,
+                           &unknown_task);
+  assert_perror (err);
+
   /* Insert the files from STD_MSGIDS_DIR at the beginning of the list, so that
      their content can be overridden by subsequently parsed files.  */
   if (nostdinc == FALSE)
@@ -1280,7 +1786,11 @@ main (int argc, char **argv, char **envp)
   setlinebuf (ostream);
 
   traced_bucket = ports_create_bucket ();
-  traced_class = ports_create_class (0, &traced_dropweak);
+  traced_class = ports_create_class (&traced_clean, NULL);
+  other_class = ports_create_class (0, 0);
+  err = ports_create_port (other_class, traced_bucket,
+                          sizeof (*notify_pi), &notify_pi);
+  assert_perror (err);
 
   hurd_ihash_set_cleanup (&msgid_ihash, msgid_ihash_cleanup, 0);
 
@@ -1306,6 +1816,8 @@ main (int argc, char **argv, char **envp)
     else
       fprintf (ostream, "Child %d %s\n", pid, strsignal (WTERMSIG (status)));
   }
+  
+  ports_destroy_right (notify_pi);
 
   return 0;
 }





reply via email to

[Prev in Thread] Current Thread [Next in Thread]