darwin-nat: avoid crash while debugging gdb.
authorTristan Gingold <tristan.gingold@adacore.com>
Fri, 21 Mar 2014 15:56:39 +0000 (16:56 +0100)
committerTristan Gingold <tristan.gingold@adacore.com>
Tue, 1 Apr 2014 09:50:36 +0000 (11:50 +0200)
it is possible that gdb gets mach exceptions from an unknown inferior.  This
happens when an inferior creates a child and that child gets a signal.

So instead of reporting messages with unknown origins, simply reply to these
notifications. The kernel will then post the unix signal.

gdb/
* darwin-nat.c (darwin_encode_reply): Add prototype.
(darwin_decode_exception_message): Reply to unknown inferiors.
(darwin_decode_message): Handle message by id.  Ignore message
to unknown inferior.
(darwin_wait): Discard unknown messages, add debug trace.

gdb/ChangeLog
gdb/darwin-nat.c

index 5ff3b59..c8d4ab5 100644 (file)
@@ -1,3 +1,11 @@
+2014-04-01  Tristan Gingold  <gingold@adacore.com>
+
+       * darwin-nat.c (darwin_encode_reply): Add prototype.
+       (darwin_decode_exception_message): Reply to unknown inferiors.
+       (darwin_decode_message): Handle message by id.  Ignore message
+       to unknown inferior.
+       (darwin_wait): Discard unknown messages, add debug trace.
+
 2014-03-31  Doug Evans  <dje@google.com>
 
        * dwarf2read.c (read_cutu_die_from_dwo): Delete unused local
index 3ea9696..7d2508e 100644 (file)
@@ -113,6 +113,9 @@ static char *darwin_pid_to_str (struct target_ops *ops, ptid_t tpid);
 
 static int darwin_thread_alive (struct target_ops *ops, ptid_t tpid);
 
+static void darwin_encode_reply (mig_reply_error_t *reply,
+                                mach_msg_header_t *hdr, integer_t code);
+
 /* Target operations for Darwin.  */
 static struct target_ops *darwin_ops;
 
@@ -557,8 +560,8 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
   kern_return_t kret;
   int i;
 
-  /* Check message identifier.  2401 == 0x961 is exc.  */
-  if (hdr->msgh_id != 2401)
+  /* Check message destination.  */
+  if (hdr->msgh_local_port != darwin_ex_port)
     return -1;
 
   /* Check message header.  */
@@ -588,25 +591,42 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
   /* Ok, the hard work.  */
   data = (integer_t *)(ndr + 1);
 
-  /* Find process by port.  */
   task_port = desc[1].name;
   thread_port = desc[0].name;
+
+  /* We got new rights to the task and the thread.  Get rid of them.  */
+  kret = mach_port_deallocate (mach_task_self (), task_port);
+  MACH_CHECK_ERROR (kret);
+  kret = mach_port_deallocate (mach_task_self (), thread_port);
+  MACH_CHECK_ERROR (kret);
+
+  /* Find process by port.  */
   inf = darwin_find_inferior_by_task (task_port);
-  if (inf == NULL)
-    return -1;
   *pinf = inf;
+  if (inf == NULL)
+    {
+      /* Not a known inferior.  This could happen if the child fork, as
+        the created process will inherit its exception port.
+        FIXME: should the exception port be restored ?  */
+      kern_return_t kret;
+      mig_reply_error_t reply;
+
+      darwin_encode_reply (&reply, hdr, KERN_SUCCESS);
+
+      kret = mach_msg (&reply.Head, MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+                      reply.Head.msgh_size, 0,
+                      MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+                      MACH_PORT_NULL);
+      MACH_CHECK_ERROR (kret);
+
+      return 0;
+    }
 
   /* Find thread by port.  */
   /* Check for new threads.  Do it early so that the port in the exception
      message can be deallocated.  */
   darwin_check_new_threads (inf);
 
-  /* We got new rights to the task and the thread.  Get rid of them.  */
-  kret = mach_port_deallocate (mach_task_self (), task_port);
-  MACH_CHECK_ERROR (kret);
-  kret = mach_port_deallocate (mach_task_self (), thread_port);
-  MACH_CHECK_ERROR (kret);
-
   thread = darwin_find_thread (inf, thread_port);
   if (thread == NULL)
     return -1;
@@ -863,8 +883,8 @@ darwin_decode_message (mach_msg_header_t *hdr,
   darwin_thread_t *thread;
   struct inferior *inf;
 
-  /* Exception message.  */
-  if (hdr->msgh_local_port == darwin_ex_port)
+  /* Exception message.  2401 == 0x961 is exc.  */
+  if (hdr->msgh_id == 2401)
     {
       int res;
 
@@ -877,7 +897,12 @@ darwin_decode_message (mach_msg_header_t *hdr,
          printf_unfiltered
            (_("darwin_wait: ill-formatted message (id=0x%x)\n"), hdr->msgh_id);
          /* FIXME: send a failure reply?  */
-         status->kind = TARGET_WAITKIND_SPURIOUS;
+         status->kind = TARGET_WAITKIND_IGNORE;
+         return minus_one_ptid;
+       }
+      if (inf == NULL)
+       {
+         status->kind = TARGET_WAITKIND_IGNORE;
          return minus_one_ptid;
        }
       *pinf = inf;
@@ -940,56 +965,60 @@ darwin_decode_message (mach_msg_header_t *hdr,
 
       return ptid_build (inf->pid, 0, thread->gdb_port);
     }
-
-  *pinf = NULL;
-  *pthread = NULL;
-
-  inf = darwin_find_inferior_by_notify (hdr->msgh_local_port);
-  if (inf != NULL)
+  else if (hdr->msgh_id == 0x48)
     {
-      if (!inf->private->no_ptrace)
-       {
-         pid_t res;
-         int wstatus;
+      /* MACH_NOTIFY_DEAD_NAME: notification for exit.  */
+      *pinf = NULL;
+      *pthread = NULL;
 
-         res = wait4 (inf->pid, &wstatus, 0, NULL);
-         if (res < 0 || res != inf->pid)
-           {
-             printf_unfiltered (_("wait4: res=%d: %s\n"),
-                                res, safe_strerror (errno));
-             status->kind = TARGET_WAITKIND_SPURIOUS;
-             return minus_one_ptid;
-           }
-         if (WIFEXITED (wstatus))
+      inf = darwin_find_inferior_by_notify (hdr->msgh_local_port);
+      if (inf != NULL)
+       {
+         if (!inf->private->no_ptrace)
            {
-             status->kind = TARGET_WAITKIND_EXITED;
-             status->value.integer = WEXITSTATUS (wstatus);
+             pid_t res;
+             int wstatus;
+
+             res = wait4 (inf->pid, &wstatus, 0, NULL);
+             if (res < 0 || res != inf->pid)
+               {
+                 printf_unfiltered (_("wait4: res=%d: %s\n"),
+                                    res, safe_strerror (errno));
+                 status->kind = TARGET_WAITKIND_IGNORE;
+                 return minus_one_ptid;
+               }
+             if (WIFEXITED (wstatus))
+               {
+                 status->kind = TARGET_WAITKIND_EXITED;
+                 status->value.integer = WEXITSTATUS (wstatus);
+               }
+             else
+               {
+                 status->kind = TARGET_WAITKIND_SIGNALLED;
+                 status->value.sig = WTERMSIG (wstatus);
+               }
+
+             inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"),
+                             res, wstatus);
+
+             /* Looks necessary on Leopard and harmless...  */
+             wait4 (inf->pid, &wstatus, 0, NULL);
+
+             return ptid_build (inf->pid, 0, 0);
            }
          else
            {
-             status->kind = TARGET_WAITKIND_SIGNALLED;
-             status->value.sig = WTERMSIG (wstatus);
+             inferior_debug (4, _("darwin_wait: pid=%d\n"), inf->pid);
+             status->kind = TARGET_WAITKIND_EXITED;
+             status->value.integer = 0; /* Don't know.  */
+             return ptid_build (inf->pid, 0, 0);
            }
-
-         inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"),
-                         res, wstatus);
-
-         /* Looks necessary on Leopard and harmless...  */
-         wait4 (inf->pid, &wstatus, 0, NULL);
-
-         return ptid_build (inf->pid, 0, 0);
-       }
-      else
-       {
-         inferior_debug (4, _("darwin_wait: pid=%d\n"), inf->pid);
-         status->kind = TARGET_WAITKIND_EXITED;
-         status->value.integer = 0; /* Don't know.  */
-         return ptid_build (inf->pid, 0, 0);
        }
     }
 
-  printf_unfiltered (_("Bad local-port: 0x%x\n"), hdr->msgh_local_port);
-  status->kind = TARGET_WAITKIND_SPURIOUS;
+  /* Unknown message.  */
+  warning (_("darwin: got unknown message, id: 0x%x\n"), hdr->msgh_id);
+  status->kind = TARGET_WAITKIND_IGNORE;
   return minus_one_ptid;
 }
 
@@ -1082,7 +1111,10 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status)
        darwin_dump_message (hdr, darwin_debug_flag > 11);
 
       res = darwin_decode_message (hdr, &thread, &inf, status);
+      if (ptid_equal (res, minus_one_ptid))
+       continue;
 
+      /* Early return in case an inferior has exited.  */
       if (inf == NULL)
        return res;
     }
@@ -1110,6 +1142,10 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status)
          break;
        }
 
+      /* Debug: display message.  */
+      if (darwin_debug_flag > 10)
+       darwin_dump_message (hdr, darwin_debug_flag > 11);
+
       ptid2 = darwin_decode_message (hdr, &thread, &inf, &status2);
 
       if (inf != NULL && thread != NULL