bug-hurd
[Top][All Lists]
Advanced

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

Re: [PATCH] fully enable rpctrace to trace multitask programs.


From: Zheng Da
Subject: Re: [PATCH] fully enable rpctrace to trace multitask programs.
Date: Mon, 15 Jun 2009 16:04:43 +0800

Hi,

Below is the updated patch. The most important update is that I
separate the messy traced_info into 3 structures. There are other
modifications according to antrik's comments.
Unfortunately, git in my Hurd doesn't support --patience option, so
the patch might be still messy in some places.
The ChangeLog is missing. I will add it later in case that there will
be another big change in the patch.

Zheng Da

diff --git a/utils/rpctrace.c b/utils/rpctrace.c
index d80f41d..6093c03 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.";
 
@@ -82,6 +84,63 @@ msgid_ihash_cleanup (void *element, void *arg)
 static struct hurd_ihash msgid_ihash
   = HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);

+/* All traced tasks. */
+task_t *traced_tasks;
+size_t nb_traced_tasks;
+
+task_t unknown_task;
+
+void
+add_task (task_t task)
+{
+  static size_t alloc_size = 100;
+
+  if (traced_tasks == NULL)
+    traced_tasks = malloc (sizeof (task_t) * alloc_size);
+  else if (nb_traced_tasks == alloc_size)
+    {
+      alloc_size *= 2;
+      traced_tasks = realloc (traced_tasks, alloc_size);
+    }
+  if (!traced_tasks)
+    error (1, 0, "cannot allocate memory");
+
+  traced_tasks[nb_traced_tasks++] = task;
+}
+
+void
+print_tasks ()
+{
+  int i;
+  for (i = 0; i < nb_traced_tasks; i++)
+    {
+      fprintf (stderr, "%d ", traced_tasks[i]);
+    }
+  fprintf (stderr, "\n");
+}
+
+void
+remove_task (task_t task)
+{
+  int i,j;
+  for (i = 0, j = 0; j < nb_traced_tasks; j++)
+    {
+      traced_tasks[i] = traced_tasks[j];
+      if (traced_tasks[j] != task)
+       i++;
+    }
+  nb_traced_tasks = i;
+}
+
+task_t
+get_task (int idx)
+{
+  if (idx >= nb_traced_tasks)
+    return -1;
+  assert (traced_tasks);
+  return traced_tasks[idx];
+}
+
 /* 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
    request-id value into `msgid_ihash' with the routine name as its value.  */
@@ -186,45 +245,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; /* Other receive rights. */
+  struct sender_info *next;    /* The head of the send right list */
+};

-  union
-  {
-    struct traced_info *nextfree; /* Link when on free list.  */
+struct sender_info
+{
+  struct traced_info pi;
+  task_t task;                 /* The task who has the right. */

-    struct                     /* For a send right wrapper.  */
-    {
-      hurd_ihash_locp_t locp;  /* position in the traced_names hash table */
-    } send;
+  /* It is used to form the list of send rights for different tasks.
+   * The head is the receive right. */
+  struct sender_info *next;

-    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;
+  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;

@@ -234,12 +369,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.  */
@@ -247,42 +383,104 @@ 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;
+  struct receiver_info *info;
+  mach_port_t foo;

-  /* Use a free send-once wrapper port if we have one.  */
-  if (freelist)
+  info = malloc (sizeof (*info));
+  if (!info)
+    error (1, 0, "cannot allocate memory");
+  info->forward = right;
+  info->task = owner;
+  info->portname = UNKNOWN_NAME;
+  info->receive_right = NULL;
+  info->next = NULL;
+  if (owner != unknown_task)
     {
-      info = freelist;
-      freelist = info->u.nextfree;
+      info->receive_right = receive_right_list;
+      receive_right_list = info;
     }
-  else
+  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);
+  assert_perror (err);
+  mach_port_deallocate (mach_task_self (), foo);
+
+  err = hurd_ihash_add (&traced_names, info->forward, info);
+  assert_perror (err);
+  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)
     {
-      /* 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 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;
     }

-  info->forward = right;
-  info->type = MACH_MSG_TYPE_MOVE_SEND;
+  hurd_ihash_locp_remove (&traced_names, info->locp);
+  free (info);
+}

-  /* 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);
+/* 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);
@@ -291,17 +489,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
     {
@@ -309,11 +507,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
@@ -326,87 +525,271 @@ 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;

-/* 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.  */
+  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;
+    }
+}
+
+/* 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 traced_info *const info = pi;
+  struct sender_info *info = pi;

-  assert (info->type == MACH_MSG_TYPE_MOVE_SEND);
-  assert (info->u.send.locp);
+  assert (TRACED_INFO (info)->type == MACH_MSG_TYPE_MOVE_SEND);
+  free (TRACED_INFO (info)->name);

-  /* Remove INFO from the hash table.  */
-  hurd_ihash_locp_remove (&traced_names, info->u.send.locp);
-  ports_port_deref_weak (info);
+  if (info->receive_right)
+    {
+      unlink_sender_info (pi);

-  /* Deallocate the forward port, so the real port also sees no-senders.  */
-  mach_port_deallocate (mach_task_self (), info->forward);
+      /* 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);

-  /* 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);
+      info->receive_right = NULL;
+    }
+}

-  free (info->name);
-  info->name = 0;
+/* 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)
+{
+  int i;
+  error_t err;
+  struct receiver_info *info;
+
+  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;
+
+  for (i = 0; i < nb_traced_tasks; i++)
+    {
+      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;
+      task_t task = traced_tasks[i];
+      err = mach_port_names (task, &portnames, &nportnames,
+                            &porttypes, &nporttypes);
+      assert_perror (err);
+
+      for (j = 0; j < nportnames; j++)
+       {
+         mach_port_t send_right;
+         mach_msg_type_name_t type;
+         if (!(porttypes[j] & MACH_PORT_TYPE_RECEIVE) /* not a receive right */
+             || seen_receive_right (task, portnames[j]))
+           continue;
+
+         err = mach_port_extract_right (task, portnames[j],
+                                        MACH_MSG_TYPE_MAKE_SEND,
+                                        &send_right, &type);
+         assert_perror (err);

-  info->u.nextfree = freelist;
-  freelist = info;
+         receiver_info = hurd_ihash_find (&traced_names, send_right);
+         /* We have seen this send right before. */
+         if (receiver_info)
+           mach_port_deallocate (mach_task_self (), send_right);
+         else
+           /* We haven't seen the receive right.
+            * Now we have the send right to the port,
+            * use it to create the receiver info. */
+           receiver_info = new_receiver_info (send_right, task);
+
+         receiver_info->portname = portnames[j];
+
+         /* We have found the wrapper for the receive right. */
+         if (send_right == send)
+           break;
+         receiver_info = NULL;
+       }
+      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;

-  switch (*type)
+  if (req)
     {
-    case MACH_MSG_TYPE_PORT_SEND:
-      /* See if we are already tracing this port.  */
-      info = hurd_ihash_find (&traced_names, *right);
-      if (info)
+      if (req->is_req)    /* It's a RPC request. */
        {
-         /* 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;
+         source = req->from;
+         dest = req->to;
        }
+      else
+       {
+         source = req->to;
+         dest = req->from;
+       }
+    }
+
+  switch (*type)
+    {
+    case MACH_MSG_TYPE_PORT_SEND:
+      /* 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);
+             assert_perror (err);
+             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);
+      receiver_info = discover_receive_right (*right);
+      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
@@ -416,62 +799,95 @@ 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);
+           assert_perror (err);
+
+           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);
+           assert_perror (err);
+           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);
+           assert_perror (err);
+           *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);
+           assert_perror (err);
+           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:
@@ -482,7 +898,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;

@@ -541,7 +957,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));
@@ -549,19 +964,11 @@ print_contents (mach_msg_header_t *inp,
          poly = 0;
          for (i = 0; i < nelt; ++i)
            {
-             newtypes[i] = name;
+             char *str;

-             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;
-               }
+             newtypes[i] = name;

-             ti = rewrite_right (&portnames[i], &newtypes[i]);
+             str = rewrite_right (&portnames[i], &newtypes[i], req);

              putc ((i == 0 && nelt > 1) ? '{' : ' ', ostream);

@@ -571,9 +978,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]);
                }
@@ -642,9 +1048,135 @@ print_contents (mach_msg_header_t *inp,
     }
 }

+/* Wrap all thread port in the task */
+static void
+wrap_all_threads (task_t task)
+{
+  struct sender_info *thread_send_wrapper;
+  struct receiver_info *thread_receiver_info;
+  thread_t *threads = NULL;
+  size_t nthreads = 0;
+  error_t err;
+
+  err = task_threads (task, &threads, &nthreads);
+  assert_perror (err);
+
+  for (int i = 0; i < nthreads; i++)
+    {
+      thread_receiver_info = hurd_ihash_find (&traced_names, threads[i]);
+      /* We haven't seen the port. */
+      if (thread_receiver_info == NULL)
+       {
+         mach_port_t new_thread_port;
+         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,
+                                       MACH_MSG_TYPE_MAKE_SEND);
+         assert_perror (err);
+
+         err = thread_set_kernel_port (threads[i], new_thread_port);
+         assert_perror (err);
+
+         mach_port_deallocate (mach_task_self (), new_thread_port);
+       }
+    }
+  munmap (threads, nthreads * sizeof (thread_t));
+}
+
+/* Wrap the new thread port that is in the message. */
+static void
+wrap_new_thread (mach_msg_header_t *inp, struct req_info *req)
+{
+  error_t err;
+  mach_port_t thread_port;
+  struct
+    {
+      mach_msg_header_t head;
+      mach_msg_type_t retcode_type;
+      kern_return_t retcode;
+      mach_msg_type_t child_thread_type;
+      mach_port_t child_thread;
+    } *reply = (void *) inp;
+  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);
+  assert_perror (err);
+  thread_port = send_wrapper->receive_right->forward;
+  err = thread_set_kernel_port (thread_port, reply->child_thread);
+  assert_perror (err);
+  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);
+  assert_perror (err);
+  err = task_set_kernel_port (task_port, pseudo_task_port);
+  assert_perror (err);
+  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 = */
@@ -671,19 +1203,27 @@ 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 receive wrapper has been destroyed. */
+         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
@@ -698,8 +1238,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;
@@ -710,31 +1259,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.
@@ -744,8 +1305,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;
@@ -761,26 +1323,77 @@ 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, req);
+         else if (inp->msgh_id == 2107) /* for task_create */
+           wrap_new_task (inp, req);
+
+         free (req);
        }
       else
        {
+         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);
+         fflush (ostream);
+         /* 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 (SEND_INFO (info)->task);
+
        }
     }

@@ -843,19 +1456,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);
@@ -864,57 +1474,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");
@@ -926,8 +1496,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;
 }


@@ -1014,8 +1582,6 @@ print_data (mach_msg_type_name_t type,
 
 /*** Main program and child startup ***/

-task_t traced_task;
-

 /* Run a child and have it do more or else `execvpe (argv, envp);'.  */
 pid_t
@@ -1024,7 +1590,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);

@@ -1038,6 +1606,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)
@@ -1046,9 +1615,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
@@ -1124,6 +1696,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)
@@ -1168,6 +1741,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)
@@ -1196,7 +1773,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);

@@ -1222,6 +1803,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]