gdb on macOS 10.12 "Sierra"

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

gdb on macOS 10.12 "Sierra"

Jonas Maebe
Hi,

Has anyone succeeded yet in getting gdb to work on macOS 10.12?  
Reportedly, it works when you disable SIP (which is understandable,  
given  
https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/RuntimeProtections/RuntimeProtections.html ), but plain code signing no longer seems to cut  
it.

With gdb 7.11.1, I occasionally get this when I try to start an inferior:
        During startup program terminated with signal SIG113, Real-time event 113.

and usually (with darwin_debug_flag set to 100 -- didn't manage to get  
the SIG113 anymore after I recompiled gdb with that variable set to  
100):

***
Starting program: textthr
[632 inferior]: inferior task: 0x300b, pid: 701
[632 inferior]:  new_ix:0/1, old_ix:0/0, new_id:0x3203 old_id:0x0
[632 inferior]: darwin_wait: waiting for a message pid=701 thread=0
[701 inferior]: ptrace (PT_TRACE_ME, 0, 0x0, 0): 0 (no error)
[701 inferior]: ptrace (PT_SIGEXC, 0, 0x0, 0): 0 (no error)
message header:
  bits: 0x1200
  size: 0x24
  remote-port: 0x0
  local-port: 0xf87
  reserved: 0x0
  id: 0x48
   data: 00000000 00000001 0000300b
[632 inferior]: darwin_wait: pid=701 exit, status=0x5
[632 inferior]: task=0x300b, prev=0x0, notify_port=0xf87
During startup program terminated with signal SIGTRAP, Trace/breakpoint trap.
***

gdb is code signed, the code signing certificate is the System  
keychain and set to "Trust always".

Thanks,


Jonas
Reply | Threaded
Open this post in threaded view
|

Re: gdb on macOS 10.12 "Sierra"

Tristan Gingold-2

> On 01 Oct 2016, at 14:08, Jonas Maebe <[hidden email]> wrote:
>
> Hi,
>
> Has anyone succeeded yet in getting gdb to work on macOS 10.12? Reportedly, it works when you disable SIP (which is understandable, given https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/RuntimeProtections/RuntimeProtections.html ), but plain code signing no longer seems to cut it.

No, I haven't tried yet.  Did you investigate if lldb has updated its build instructions ?

Tristan.

Reply | Threaded
Open this post in threaded view
|

RE: gdb on macOS 10.12 "Sierra"

Tedeschi, Walfred
Hello All,

It looks like Apple has increased security. We have got it to work with a workaround.
In case the signature is not from Apple the System Integrity protection has to be changed.
In this case reboot the machine enter in the recovery mode, start a terminal and issue the command:

$ csrutil enable --without debug

Reboot the system and the debug session will be able to proceed.

Cheers,
/Fred

-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of Tristan Gingold
Sent: Tuesday, October 4, 2016 12:43 PM
To: Jonas Maebe <[hidden email]>
Cc: [hidden email]
Subject: Re: gdb on macOS 10.12 "Sierra"


> On 01 Oct 2016, at 14:08, Jonas Maebe <[hidden email]> wrote:
>
> Hi,
>
> Has anyone succeeded yet in getting gdb to work on macOS 10.12? Reportedly, it works when you disable SIP (which is understandable, given https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/RuntimeProtections/RuntimeProtections.html ), but plain code signing no longer seems to cut it.

No, I haven't tried yet.  Did you investigate if lldb has updated its build instructions ?

Tristan.

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Christian Lamprechter
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

Reply | Threaded
Open this post in threaded view
|

Re: gdb on macOS 10.12 "Sierra"

Jonas Maebe
In reply to this post by Tristan Gingold-2
Tristan Gingold wrote:
>> On 01 Oct 2016, at 14:08, Jonas Maebe <[hidden email]> wrote:
>>
>> Has anyone succeeded yet in getting gdb to work on macOS 10.12? Reportedly, it works when you disable SIP (which is understandable, given https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/RuntimeProtections/RuntimeProtections.html ), but plain code signing no longer seems to cut it.
>
> No, I haven't tried yet.  Did you investigate if lldb has updated its build instructions ?

I finally got time to look into this. lldb's codesigning instructions
are at
https://llvm.org/svn/llvm-project/lldb/trunk/docs/code-signing.txt .
They have not been updated recently, but they do differ from gdb's.
However, the result is exactly the same: SIG113.

I've also asked on the darwin-dev@apple list, but did not get any
replies there.

...

I've now tried building lldb, and regardless of whether I use the GDB or
LLDB-style codesigning certificate to sign debugserver (lldb itself does
not need codesigning), it works. So it seems like the problem is not
necessarily related to codesigning per se.


Jonas
Reply | Threaded
Open this post in threaded view
|

Re: gdb on macOS 10.12 "Sierra"

Jack Howarth-2
On Mon, Oct 31, 2016 at 7:54 AM, Jonas Maebe <[hidden email]> wrote:

> Tristan Gingold wrote:
>>> On 01 Oct 2016, at 14:08, Jonas Maebe <[hidden email]> wrote:
>>>
>>> Has anyone succeeded yet in getting gdb to work on macOS 10.12? Reportedly, it works when you disable SIP (which is understandable, given https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/RuntimeProtections/RuntimeProtections.html ), but plain code signing no longer seems to cut it.
>>
>> No, I haven't tried yet.  Did you investigate if lldb has updated its build instructions ?
>
> I finally got time to look into this. lldb's codesigning instructions
> are at
> https://llvm.org/svn/llvm-project/lldb/trunk/docs/code-signing.txt .
> They have not been updated recently, but they do differ from gdb's.
> However, the result is exactly the same: SIG113.
>
> I've also asked on the darwin-dev@apple list, but did not get any
> replies there.
>

It has been reported that the hardened security in Sierra requires the
additional step of executing


   csrutil enable --without debug


from within the Terminal application when booted under the Recovery Partition.
I don't have access to a machine that can run Sierra to verify it though.


> ...
>
> I've now tried building lldb, and regardless of whether I use the GDB or
> LLDB-style codesigning certificate to sign debugserver (lldb itself does
> not need codesigning), it works. So it seems like the problem is not
> necessarily related to codesigning per se.
>
>
> Jonas
Reply | Threaded
Open this post in threaded view
|

Re: gdb on macOS 10.12 "Sierra"

Jonas Maebe
Jack Howarth wrote:

> It has been reported that the hardened security in Sierra requires the
> additional step of executing
>
>    csrutil enable --without debug
>
> from within the Terminal application when booted under the Recovery Partition.
> I don't have access to a machine that can run Sierra to verify it though.

Yes, someone else on the gdb list also answered that when I asked my
original question. However, that does not explain why that is not
necessary for a self-built and custom-codesigned lldb/debugserver, as I
wrote below:

>> I've now tried building lldb, and regardless of whether I use the GDB or
>> LLDB-style codesigning certificate to sign debugserver (lldb itself does
>> not need codesigning), it works. So it seems like the problem is not
>> necessarily related to codesigning per se.


Jonas
Reply | Threaded
Open this post in threaded view
|

Re: gdb on macOS 10.12 "Sierra"

C Western
In reply to this post by Jonas Maebe
An additional note on this - I have been having similar problems with
running gdb under Sierra, and it seems the problem is more subtle than a
simple permissions problem. I am able to attach to a running process,
but not start a new process with gdb. This is even after using:

        set startup-with-shell off

which I have seen suggested elsewhere.

Colin
Reply | Threaded
Open this post in threaded view
|

Re: gdb on macOS 10.12 "Sierra"

Jason Molenda
In reply to this post by Jonas Maebe
Hi Jonas, there was a change in macOS 10.12.1 that may be impacting gdb.  After an exec, you need to refresh the task port that gdb uses in its mach calls.  You can see the lldb change here:

http://llvm.org/viewvc/llvm-project?view=revision&revision=282632

or




I skimmed this email thread and someone said that disabling launch-with-shell worked around the issue.  That would be in line with this OS change.


Jason

> On Oct 31, 2016, at 4:54 AM, Jonas Maebe <[hidden email]> wrote:
>
> Tristan Gingold wrote:
>>> On 01 Oct 2016, at 14:08, Jonas Maebe <[hidden email]> wrote:
>>>
>>> Has anyone succeeded yet in getting gdb to work on macOS 10.12? Reportedly, it works when you disable SIP (which is understandable, given https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/RuntimeProtections/RuntimeProtections.html ), but plain code signing no longer seems to cut it.
>>
>> No, I haven't tried yet.  Did you investigate if lldb has updated its build instructions ?
>
> I finally got time to look into this. lldb's codesigning instructions
> are at
> https://llvm.org/svn/llvm-project/lldb/trunk/docs/code-signing.txt .
> They have not been updated recently, but they do differ from gdb's.
> However, the result is exactly the same: SIG113.
>
> I've also asked on the darwin-dev@apple list, but did not get any
> replies there.
>
> ...
>
> I've now tried building lldb, and regardless of whether I use the GDB or
> LLDB-style codesigning certificate to sign debugserver (lldb itself does
> not need codesigning), it works. So it seems like the problem is not
> necessarily related to codesigning per se.
>
>
> Jonas


patch.txt (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: gdb on macOS 10.12 "Sierra"

Tristan Gingold-2

> On 01 Nov 2016, at 00:23, Jason Molenda <[hidden email]> wrote:
>
> Hi Jonas, there was a change in macOS 10.12.1 that may be impacting gdb.  After an exec, you need to refresh the task port that gdb uses in its mach calls.  You can see the lldb change here:
>
> http://llvm.org/viewvc/llvm-project?view=revision&revision=282632
>
> or
>
> <patch.txt>
>
> I skimmed this email thread and someone said that disabling launch-with-shell worked around the issue.  That would be in line with this OS change.

Thank you Jason, that's very useful.

Tristan.

Reply | Threaded
Open this post in threaded view
|

Re: gdb on macOS 10.12 "Sierra"

David Jenkins
In reply to this post by Jonas Maebe
I can confirm that refreshing the task port after exec does allow gdb to
work.  Here is a patch that I made against 7.12 that allows gdb to run
on Sierra.  I cannot speak to the complete quality of the patch as this
is my first dive into gdb code.  We just starting using the patched gdb
and it does allows us to break, step, and view variables in the Lazarus IDE.

Patch is inlined below

David Jenkins

Scooter Software


--- gdb-7.12/gdb/darwin-nat.c    2016-10-07 12:09:21.000000000 -0500
+++ gdb-7.12-dfj/gdb/darwin-nat.c    2016-11-03 15:56:49.000000000 -0500
@@ -171,6 +171,9 @@
    "</dict>\n"
    "</plist>\n";

+static kern_return_t darwin_save_exception_ports (darwin_inferior *inf);
+static kern_return_t darwin_restore_exception_ports (darwin_inferior *inf);
+
  static void inferior_debug (int level, const char *fmt, ...)
    ATTRIBUTE_PRINTF (2, 3);

@@ -401,6 +404,12 @@
  }

  static int
+find_inferior_pid_it (struct inferior *inf, void *pid_ptr)
+{
+  return inf->pid == *(int *)pid_ptr;
+}
+
+static int
  find_inferior_task_it (struct inferior *inf, void *port_ptr)
  {
    return inf->priv->task == *(task_t*)port_ptr;
@@ -412,6 +421,13 @@
    return inf->priv->notify_port == *(task_t*)port_ptr;
  }

+/* Return an inferior by pid.  */
+static struct inferior *
+darwin_find_inferior_by_pid (int pid)
+{
+  return iterate_over_inferiors (&find_inferior_pid_it, &pid);
+}
+
  /* Return an inferior by task port.  */
  static struct inferior *
  darwin_find_inferior_by_task (task_t port)
@@ -572,6 +588,7 @@
    thread_t thread_port;
    kern_return_t kret;
    int i;
+  int task_pid;

    /* Check message destination.  */
    if (hdr->msgh_local_port != darwin_ex_port)
@@ -606,6 +623,7 @@

    task_port = desc[1].name;
    thread_port = desc[0].name;
+  pid_for_task(task_port, &task_pid);

    /* We got new rights to the task, get rid of it.  Do not get rid of
thread
       right, as we will need it to find the thread.  */
@@ -617,25 +635,61 @@
    *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;
+      if MACH_PORT_VALID(task_port)
+    {
+      //int task_pid;
+      mach_port_name_t new_task;
+      mach_port_t prev_not;
+      exception_mask_t mask;
+
+      inf = darwin_find_inferior_by_pid(task_pid);
+      if (inf == NULL)
+        return 0;

-      /* Free thread port (we don't know it).  */
-      kret = mach_port_deallocate (mach_task_self (), thread_port);
-      MACH_CHECK_ERROR (kret);
+      kret = mach_port_deallocate (mach_task_self (), inf->priv->task);
+      MACH_CHECK_ERROR (kret);

-      darwin_encode_reply (&reply, hdr, KERN_SUCCESS);
+      task_for_pid(gdb_task, task_pid, &new_task);

-      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);
+      inf->priv->task = new_task;
+      *pinf = inf;
+
+      mach_port_request_notification (gdb_task, inf->priv->task,
+                      MACH_NOTIFY_DEAD_NAME, 0,
+                      inf->priv->notify_port,
+                      MACH_MSG_TYPE_MAKE_SEND_ONCE,
+                      &prev_not);
+
+      darwin_restore_exception_ports(inf->priv);
+      if (enable_mach_exceptions)
+        mask = EXC_MASK_ALL;
+      else
+        mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
+      task_set_exception_ports (inf->priv->task, mask, darwin_ex_port,
+                    EXCEPTION_DEFAULT, THREAD_STATE_NONE);
+    }
+      else
+    {
+      /* 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;
+
+      /* Free thread port (we don't know it).  */
+      kret = mach_port_deallocate (mach_task_self (), thread_port);
+      MACH_CHECK_ERROR (kret);

-      return 0;
+      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.  */
@@ -900,6 +954,7 @@
  {
    darwin_thread_t *thread;
    struct inferior *inf;
+

    /* Exception message.  2401 == 0x961 is exc.  */
    if (hdr->msgh_id == 2401)
@@ -992,6 +1047,14 @@
        inf = darwin_find_inferior_by_notify (hdr->msgh_local_port);
        if (inf != NULL)
      {
+     mach_dead_name_notification_t *notif;
+     mach_port_t dead_port;
+
+    notif = (mach_dead_name_notification_t *)(hdr);
+    dead_port = notif->not_port;
+      if (dead_port != inf->priv->task)
+        return ptid_build (inf->pid, 0, 0);
+
        if (!inf->priv->no_ptrace)
          {
            pid_t res;


Reply | Threaded
Open this post in threaded view
|

[Patch] Fix gdb on macOS 10.12 "Sierra"

Tristan Gingold-2
Hello,

I have just committed the patch below to support Sierra (Darwin 16) in gdb.
Thanks to Jason Molenda for explaining the change in macOS 10.12.1, and thanks to David Jenkins for an initial patch.

Currently, you still need to 'set startup-with-shell off' on Sierra. I suppose this should be done automatically to be more user friendly, but I have to investigate to do that correctly.

Tristan.

commit 82b19a4d2f9c9e8d56fdffdd702f7db4af486386
Author: Tristan Gingold <[hidden email]>
Date:   Wed Nov 9 10:25:00 2016 +0100

    darwin-nat.c: handle Darwin 16 (aka Sierra).
   
    Support message from new task and dead name notification on task of an
    existing process.
    With Sierra, exec(2) terminate the current task and creates a new one.
    'set startup-with-shell off' must still be used on Darwin 16.
   
    2016-11-09  Tristan Gingold  <[hidden email]>
   
    * darwin-nat.c (find_inferior_task_it): Fix indentation.
    (find_inferior_notify_it): Remove.
    (find_inferior_pid_it): New function.
    (darwin_find_inferior_by_notify): Remove.
    (darwin_find_inferior_by_pid): New function.
    (darwin_find_new_inferior): New function.
    (darwin_check_message_ndr): New function from
    darwin_decode_exception_message.
    (darwin_decode_exception_message): Call darwin_check_message_ndr.
    Handle SIGTRAP addressed to an unknown task (when a task spawned).
    (darwin_decode_notify_message): New function.
    (darwin_decode_message): Handle unknown task.
    (darwin_deallocate_threads): New function from darwin_mourn_inferior.
    (darwin_mourn_inferior): Use darwin_deallocate_threads and
    darwin_deallocate_exception_ports.
    (darwin_deallocate_exception_ports): New function from
    darwin_mourn_inferior.
    (darwin_setup_exceptions): New function from darwin_attach_pid.
    (darwin_setup_request_notification): Likewise.
    (darwin_attach_pid): Call darwin_setup_request_notification and
    darwin_setup_request_notification.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index c808ca5..3b3fea1 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,27 @@
+2016-11-09  Tristan Gingold  <[hidden email]>
+
+ * darwin-nat.c (find_inferior_task_it): Fix indentation.
+ (find_inferior_notify_it): Remove.
+ (find_inferior_pid_it): New function.
+ (darwin_find_inferior_by_notify): Remove.
+ (darwin_find_inferior_by_pid): New function.
+ (darwin_find_new_inferior): New function.
+ (darwin_check_message_ndr): New function from
+ darwin_decode_exception_message.
+ (darwin_decode_exception_message): Call darwin_check_message_ndr.
+ Handle SIGTRAP addressed to an unknown task (when a task spawned).
+ (darwin_decode_notify_message): New function.
+ (darwin_decode_message): Handle unknown task.
+ (darwin_deallocate_threads): New function from darwin_mourn_inferior.
+ (darwin_mourn_inferior): Use darwin_deallocate_threads and
+ darwin_deallocate_exception_ports.
+ (darwin_deallocate_exception_ports): New function from
+ darwin_mourn_inferior.
+ (darwin_setup_exceptions): New function from darwin_attach_pid.
+ (darwin_setup_request_notification): Likewise.
+ (darwin_attach_pid): Call darwin_setup_request_notification and
+ darwin_setup_request_notification.
+
 2016-11-08  Tom Tromey  <[hidden email]>
 
  * python/py-framefilter.c (py_print_frame): Use
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 3f54a76..6ca659f4 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -114,6 +114,11 @@ 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);
 
+static void darwin_setup_request_notification (struct inferior *inf);
+static void darwin_deallocate_exception_ports (darwin_inferior *inf);
+static void darwin_setup_exceptions (struct inferior *inf);
+static void darwin_deallocate_threads (struct inferior *inf);
+
 /* Target operations for Darwin.  */
 static struct target_ops *darwin_ops;
 
@@ -320,6 +325,7 @@ darwin_check_new_threads (struct inferior *inf)
  }
     }
 
+  /* Full handling: detect new threads, remove dead threads.  */
   thread_vec = VEC_alloc (darwin_thread_t, new_nbr);
 
   for (new_ix = 0, old_ix = 0; new_ix < new_nbr || old_ix < old_nbr;)
@@ -365,15 +371,22 @@ darwin_check_new_threads (struct inferior *inf)
   pti->gdb_port = new_id;
   pti->msg_state = DARWIN_RUNNING;
 
-  /* Add a new thread unless this is the first one ever met.  */
-  if (!(old_nbr == 0 && new_ix == 0))
-    tp = add_thread_with_info (ptid_build (inf->pid, 0, new_id), pti);
-  else
+  if (old_nbr == 0 && new_ix == 0)
     {
+      /* A ptid is create when the inferior is started (see
+ fork-child.c) with lwp=tid=0.  This ptid will be renamed
+ later by darwin_init_thread_list ().  */
       tp = find_thread_ptid (ptid_build (inf->pid, 0, 0));
       gdb_assert (tp);
+      gdb_assert (tp->priv == NULL);
       tp->priv = pti;
     }
+  else
+    {
+      /* Add the new thread.  */
+      tp = add_thread_with_info
+ (ptid_build (inf->pid, 0, new_id), pti);
+    }
   VEC_safe_push (darwin_thread_t, thread_vec, pti);
   new_ix++;
   continue;
@@ -403,13 +416,13 @@ darwin_check_new_threads (struct inferior *inf)
 static int
 find_inferior_task_it (struct inferior *inf, void *port_ptr)
 {
-  return inf->priv->task == *(task_t*)port_ptr;
+  return inf->priv->task == *(task_t *)port_ptr;
 }
 
 static int
-find_inferior_notify_it (struct inferior *inf, void *port_ptr)
+find_inferior_pid_it (struct inferior *inf, void *pid_ptr)
 {
-  return inf->priv->notify_port == *(task_t*)port_ptr;
+  return inf->pid == *(int *)pid_ptr;
 }
 
 /* Return an inferior by task port.  */
@@ -419,11 +432,11 @@ darwin_find_inferior_by_task (task_t port)
   return iterate_over_inferiors (&find_inferior_task_it, &port);
 }
 
-/* Return an inferior by notification port.  */
+/* Return an inferior by pid port.  */
 static struct inferior *
-darwin_find_inferior_by_notify (mach_port_t port)
+darwin_find_inferior_by_pid (int pid)
 {
-  return iterate_over_inferiors (&find_inferior_notify_it, &port);
+  return iterate_over_inferiors (&find_inferior_pid_it, &pid);
 }
 
 /* Return a thread by port.  */
@@ -557,6 +570,69 @@ darwin_dump_message (mach_msg_header_t *hdr, int disp_body)
     }
 }
 
+/* Adjust inferior data when a new task was created.  */
+
+static struct inferior *
+darwin_find_new_inferior (task_t task_port, thread_t thread_port)
+{
+  int task_pid;
+  struct inferior *inf;
+  kern_return_t kret;
+  mach_port_t prev;
+
+  /* Find the corresponding pid.  */
+  kret = pid_for_task (task_port, &task_pid);
+  if (kret != KERN_SUCCESS)
+    {
+      MACH_CHECK_ERROR (kret);
+      return NULL;
+    }
+
+  /* Find the inferior for this pid.  */
+  inf = darwin_find_inferior_by_pid (task_pid);
+  if (inf == NULL)
+    return NULL;
+
+  /* Deallocate saved exception ports.  */
+  darwin_deallocate_exception_ports (inf->priv);
+
+  /* No need to remove dead_name notification, but still...  */
+  kret = mach_port_request_notification (gdb_task, inf->priv->task,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &prev);
+  if (kret != KERN_INVALID_ARGUMENT)
+    MACH_CHECK_ERROR (kret);
+
+  /* Replace old task port.  */
+  kret = mach_port_deallocate (gdb_task, inf->priv->task);
+  MACH_CHECK_ERROR (kret);
+  inf->priv->task = task_port;
+
+  darwin_setup_request_notification (inf);
+  darwin_setup_exceptions (inf);
+
+  return inf;
+}
+
+/* Check data representation.  */
+
+static int
+darwin_check_message_ndr (NDR_record_t *ndr)
+{
+  if (ndr->mig_vers != NDR_PROTOCOL_2_0
+      || ndr->if_vers != NDR_PROTOCOL_2_0
+      || ndr->mig_encoding != NDR_record.mig_encoding
+      || ndr->int_rep != NDR_record.int_rep
+      || ndr->char_rep != NDR_record.char_rep
+      || ndr->float_rep != NDR_record.float_rep)
+    return -1;
+  return 0;
+}
+
+/* Decode an exception message.  */
+
 static int
 darwin_decode_exception_message (mach_msg_header_t *hdr,
  struct inferior **pinf,
@@ -593,12 +669,7 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
 
   /* Check data representation.  */
   ndr = (NDR_record_t *)(desc + 2);
-  if (ndr->mig_vers != NDR_PROTOCOL_2_0
-      || ndr->if_vers != NDR_PROTOCOL_2_0
-      || ndr->mig_encoding != NDR_record.mig_encoding
-      || ndr->int_rep != NDR_record.int_rep
-      || ndr->char_rep != NDR_record.char_rep
-      || ndr->float_rep != NDR_record.float_rep)
+  if (darwin_check_message_ndr (ndr) != 0)
     return -1;
 
   /* Ok, the hard work.  */
@@ -607,14 +678,33 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
   task_port = desc[1].name;
   thread_port = desc[0].name;
 
-  /* We got new rights to the task, get rid of it.  Do not get rid of thread
-     right, as we will need it to find the thread.  */
-  kret = mach_port_deallocate (mach_task_self (), task_port);
-  MACH_CHECK_ERROR (kret);
-
   /* Find process by port.  */
   inf = darwin_find_inferior_by_task (task_port);
   *pinf = inf;
+
+  if (inf == NULL && data[0] == EXC_SOFTWARE && data[1] == 2
+      && data[2] == EXC_SOFT_SIGNAL && data[3] == SIGTRAP)
+    {
+      /* Not a known inferior, but a sigtrap.  This happens on darwin 16.1.0,
+ as a new Mach task is created when a process exec.  */
+      inf = darwin_find_new_inferior (task_port, thread_port);
+      *pinf = inf;
+
+      if (inf == NULL)
+ {
+  /* Deallocate task_port, unless it was saved.  */
+  kret = mach_port_deallocate (mach_task_self (), task_port);
+  MACH_CHECK_ERROR (kret);
+ }
+    }
+  else
+    {
+      /* We got new rights to the task, get rid of it.  Do not get rid of
+ thread right, as we will need it to find the thread.  */
+      kret = mach_port_deallocate (mach_task_self (), task_port);
+      MACH_CHECK_ERROR (kret);
+    }
+
   if (inf == NULL)
     {
       /* Not a known inferior.  This could happen if the child fork, as
@@ -623,6 +713,10 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
       kern_return_t kret;
       mig_reply_error_t reply;
 
+      inferior_debug
+ (4, _("darwin_decode_exception_message: unknown task 0x%x\n"),
+ task_port);
+
       /* Free thread port (we don't know it).  */
       kret = mach_port_deallocate (mach_task_self (), thread_port);
       MACH_CHECK_ERROR (kret);
@@ -676,6 +770,45 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
   return 0;
 }
 
+/* Decode dead_name notify message.  */
+
+static int
+darwin_decode_notify_message (mach_msg_header_t *hdr, struct inferior **pinf)
+{
+  NDR_record_t *ndr = (NDR_record_t *)(hdr + 1);
+  integer_t *data = (integer_t *)(ndr + 1);
+  struct inferior *inf;
+  darwin_thread_t *thread;
+  task_t task_port;
+  thread_t thread_port;
+  kern_return_t kret;
+  int i;
+
+  /* Check message header.  */
+  if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+    return -1;
+
+  /* Check descriptors.  */
+  if (hdr->msgh_size < (sizeof (*hdr) + sizeof (*ndr) + sizeof (integer_t)))
+    return -2;
+
+  /* Check data representation.  */
+  if (darwin_check_message_ndr (ndr) != 0)
+    return -3;
+
+  task_port = data[0];
+
+  /* Find process by port.  */
+  inf = darwin_find_inferior_by_task (task_port);
+  *pinf = inf;
+
+  /* Check message destination.  */
+  if (inf != NULL && hdr->msgh_local_port != inf->priv->notify_port)
+    return -4;
+
+  return 0;
+}
+
 static void
 darwin_encode_reply (mig_reply_error_t *reply, mach_msg_header_t *hdr,
      integer_t code)
@@ -986,10 +1119,27 @@ darwin_decode_message (mach_msg_header_t *hdr,
   else if (hdr->msgh_id == 0x48)
     {
       /* MACH_NOTIFY_DEAD_NAME: notification for exit.  */
+      int res;
+
+      res = darwin_decode_notify_message (hdr, &inf);
+
+      if (res < 0)
+ {
+  /* Should not happen...  */
+  printf_unfiltered
+    (_("darwin_wait: ill-formatted message (id=0x%x, res=%d)\n"),
+     hdr->msgh_id, res);
+ }
+
       *pinf = NULL;
       *pthread = NULL;
 
-      inf = darwin_find_inferior_by_notify (hdr->msgh_local_port);
+      if (res < 0 || inf == NULL)
+ {
+  status->kind = TARGET_WAITKIND_IGNORE;
+  return minus_one_ptid;
+ }
+
       if (inf != NULL)
  {
   if (!inf->priv->no_ptrace)
@@ -1022,7 +1172,8 @@ darwin_decode_message (mach_msg_header_t *hdr,
       /* Looks necessary on Leopard and harmless...  */
       wait4 (inf->pid, &wstatus, 0, NULL);
 
-      return ptid_build (inf->pid, 0, 0);
+      inferior_ptid = ptid_build (inf->pid, 0, 0);
+      return inferior_ptid;
     }
   else
     {
@@ -1204,17 +1355,14 @@ darwin_interrupt (struct target_ops *self, ptid_t t)
   kill (inf->pid, SIGINT);
 }
 
+/* Deallocate threads port and vector.  */
+
 static void
-darwin_mourn_inferior (struct target_ops *ops)
+darwin_deallocate_threads (struct inferior *inf)
 {
-  struct inferior *inf = current_inferior ();
-  kern_return_t kret;
-  mach_port_t prev;
-  int i;
-
-  /* Deallocate threads.  */
   if (inf->priv->threads)
     {
+      kern_return_t kret;
       int k;
       darwin_thread_t *t;
       for (k = 0;
@@ -1227,11 +1375,25 @@ darwin_mourn_inferior (struct target_ops *ops)
       VEC_free (darwin_thread_t, inf->priv->threads);
       inf->priv->threads = NULL;
     }
+}
 
+static void
+darwin_mourn_inferior (struct target_ops *ops)
+{
+  struct inferior *inf = current_inferior ();
+  kern_return_t kret;
+  mach_port_t prev;
+  int i;
+
+  /* Deallocate threads.  */
+  darwin_deallocate_threads (inf);
+
+  /* Remove notify_port from darwin_port_set.  */
   kret = mach_port_move_member (gdb_task,
  inf->priv->notify_port, MACH_PORT_NULL);
   MACH_CHECK_ERROR (kret);
 
+  /* Remove task port dead_name notification.  */
   kret = mach_port_request_notification (gdb_task, inf->priv->task,
  MACH_NOTIFY_DEAD_NAME, 0,
  MACH_PORT_NULL,
@@ -1247,19 +1409,14 @@ darwin_mourn_inferior (struct target_ops *ops)
       MACH_CHECK_ERROR (kret);
     }
 
+  /* Destroy notify_port.  */
   kret = mach_port_destroy (gdb_task, inf->priv->notify_port);
   MACH_CHECK_ERROR (kret);
 
-
   /* Deallocate saved exception ports.  */
-  for (i = 0; i < inf->priv->exception_info.count; i++)
-    {
-      kret = mach_port_deallocate
- (gdb_task, inf->priv->exception_info.ports[i]);
-      MACH_CHECK_ERROR (kret);
-    }
-  inf->priv->exception_info.count = 0;
+  darwin_deallocate_exception_ports (inf->priv);
 
+  /* Deallocate task port.  */
   kret = mach_port_deallocate (gdb_task, inf->priv->task);
   MACH_CHECK_ERROR (kret);
 
@@ -1349,6 +1506,48 @@ darwin_restore_exception_ports (darwin_inferior *inf)
   return KERN_SUCCESS;
 }
 
+/* Deallocate saved exception ports.  */
+
+static void
+darwin_deallocate_exception_ports (darwin_inferior *inf)
+{
+  int i;
+  kern_return_t kret;
+
+  for (i = 0; i < inf->exception_info.count; i++)
+    {
+      kret = mach_port_deallocate (gdb_task, inf->exception_info.ports[i]);
+      MACH_CHECK_ERROR (kret);
+    }
+  inf->exception_info.count = 0;
+}
+
+static void
+darwin_setup_exceptions (struct inferior *inf)
+{
+  kern_return_t kret;
+  int traps_expected;
+  exception_mask_t mask;
+
+  kret = darwin_save_exception_ports (inf->priv);
+  if (kret != KERN_SUCCESS)
+    error (_("Unable to save exception ports, task_get_exception_ports"
+     "returned: %d"),
+   kret);
+
+  /* Set exception port.  */
+  if (enable_mach_exceptions)
+    mask = EXC_MASK_ALL;
+  else
+    mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
+  kret = task_set_exception_ports (inf->priv->task, mask, darwin_ex_port,
+   EXCEPTION_DEFAULT, THREAD_STATE_NONE);
+  if (kret != KERN_SUCCESS)
+    error (_("Unable to set exception ports, task_set_exception_ports"
+     "returned: %d"),
+   kret);
+}
+
 static void
 darwin_kill_inferior (struct target_ops *ops)
 {
@@ -1385,6 +1584,34 @@ darwin_kill_inferior (struct target_ops *ops)
 }
 
 static void
+darwin_setup_request_notification (struct inferior *inf)
+{
+  kern_return_t kret;
+  mach_port_t prev_not;
+
+  kret = mach_port_request_notification (gdb_task, inf->priv->task,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ inf->priv->notify_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &prev_not);
+  if (kret != KERN_SUCCESS)
+    error (_("Termination notification request failed, "
+     "mach_port_request_notification\n"
+     "returned: %d"),
+   kret);
+  if (prev_not != MACH_PORT_NULL)
+    {
+      /* This is unexpected, as there should not be any previously
+ registered notification request.  But this is not a fatal
+ issue, so just emit a warning.  */
+      warning (_("\
+A task termination request was registered before the debugger registered\n\
+its own.  This is unexpected, but should otherwise not have any actual\n\
+impact on the debugging session."));
+    }
+}
+
+static void
 darwin_attach_pid (struct inferior *inf)
 {
   kern_return_t kret;
@@ -1463,44 +1690,9 @@ darwin_attach_pid (struct inferior *inf)
      "returned: %d"),
    kret);
 
-  kret = mach_port_request_notification (gdb_task, inf->priv->task,
- MACH_NOTIFY_DEAD_NAME, 0,
- inf->priv->notify_port,
- MACH_MSG_TYPE_MAKE_SEND_ONCE,
- &prev_not);
-  if (kret != KERN_SUCCESS)
-    error (_("Termination notification request failed, "
-     "mach_port_request_notification\n"
-     "returned: %d"),
-   kret);
-  if (prev_not != MACH_PORT_NULL)
-    {
-      /* This is unexpected, as there should not be any previously
- registered notification request.  But this is not a fatal
- issue, so just emit a warning.  */
-      warning (_("\
-A task termination request was registered before the debugger registered\n\
-its own.  This is unexpected, but should otherwise not have any actual\n\
-impact on the debugging session."));
-    }
+  darwin_setup_request_notification (inf);
 
-  kret = darwin_save_exception_ports (inf->priv);
-  if (kret != KERN_SUCCESS)
-    error (_("Unable to save exception ports, task_get_exception_ports"
-     "returned: %d"),
-   kret);
-
-  /* Set exception port.  */
-  if (enable_mach_exceptions)
-    mask = EXC_MASK_ALL;
-  else
-    mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
-  kret = task_set_exception_ports (inf->priv->task, mask, darwin_ex_port,
-   EXCEPTION_DEFAULT, THREAD_STATE_NONE);
-  if (kret != KERN_SUCCESS)
-    error (_("Unable to set exception ports, task_set_exception_ports"
-     "returned: %d"),
-   kret);
+  darwin_setup_exceptions (inf);
 
   if (!target_is_pushed (darwin_ops))
     push_target (darwin_ops);