gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / darwin-nat.c
index bb46cfbfcfa53dc9b16f6c596b7dad807c4d1b2b..2d74bc010c35e29a3048b880355b3be5d55d9706 100644 (file)
@@ -1,5 +1,5 @@
 /* Darwin support for GDB, the GNU debugger.
-   Copyright (C) 2008-2018 Free Software Foundation, Inc.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
 
    Contributed by AdaCore.
 
@@ -37,7 +37,9 @@
 #include "arch-utils.h"
 #include "bfd.h"
 #include "bfd/mach-o.h"
+#include "gdbarch.h"
 
+#include <copyfile.h>
 #include <sys/ptrace.h>
 #include <sys/signal.h>
 #include <setjmp.h>
 #include <mach/port.h>
 
 #include "darwin-nat.h"
-#include "common/filestuff.h"
+#include "filenames.h"
+#include "gdbsupport/filestuff.h"
+#include "gdbsupport/gdb_unlinker.h"
+#include "gdbsupport/pathstuff.h"
+#include "gdbsupport/scoped_fd.h"
 #include "nat/fork-inferior.h"
 
 /* Quick overview.
 #define PTRACE(CMD, PID, ADDR, SIG) \
  darwin_ptrace(#CMD, CMD, (PID), (ADDR), (SIG))
 
-static ptid_t darwin_wait (ptid_t ptid, struct target_waitstatus *status);
-
 static void darwin_ptrace_me (void);
 
-static void darwin_ptrace_him (int pid);
-
 static void darwin_encode_reply (mig_reply_error_t *reply,
                                 mach_msg_header_t *hdr, integer_t code);
 
@@ -114,11 +116,15 @@ static vm_size_t mach_page_size;
 
 /* If Set, catch all mach exceptions (before they are converted to signals
    by the kernel).  */
-static int enable_mach_exceptions;
+static bool enable_mach_exceptions;
 
 /* Inferior that should report a fake stop event.  */
 static struct inferior *darwin_inf_fake_stop;
 
+/* If non-NULL, the shell we actually invoke.  See maybe_cache_shell
+   for details.  */
+static const char *copied_shell;
+
 #define PAGE_TRUNC(x) ((x) & ~(mach_page_size - 1))
 #define PAGE_ROUND(x) PAGE_TRUNC((x) + mach_page_size - 1)
 
@@ -248,8 +254,8 @@ cmp_thread_t (const void *l, const void *r)
   return (int)(tl - tr);
 }
 
-static void
-darwin_check_new_threads (struct inferior *inf)
+void
+darwin_nat_target::check_new_threads (inferior *inf)
 {
   kern_return_t kret;
   thread_array_t thread_list;
@@ -259,6 +265,9 @@ darwin_check_new_threads (struct inferior *inf)
   darwin_inferior *darwin_inf = get_darwin_inferior (inf);
   std::vector<darwin_thread_t *> new_thread_vec;
 
+  if (darwin_inf == nullptr)
+    return;
+
   /* Get list of threads.  */
   kret = task_threads (darwin_inf->task, &thread_list, &new_nbr);
   MACH_CHECK_ERROR (kret);
@@ -342,7 +351,7 @@ darwin_check_new_threads (struct inferior *inf)
          pti->msg_state = DARWIN_RUNNING;
 
          /* Add the new thread.  */
-         add_thread_with_info (ptid_t (inf->pid, 0, new_id), pti);
+         add_thread_with_info (this, ptid_t (inf->pid, 0, new_id), pti);
          new_thread_vec.push_back (pti);
          new_ix++;
          continue;
@@ -351,7 +360,7 @@ darwin_check_new_threads (struct inferior *inf)
        {
          /* A thread was removed.  */
          struct thread_info *thr
-           = find_thread_ptid (ptid_t (inf->pid, 0, old_id));
+           = find_thread_ptid (this, ptid_t (inf->pid, 0, old_id));
          delete_thread (thr);
          kret = mach_port_deallocate (gdb_task, old_id);
          MACH_CHECK_ERROR (kret);
@@ -369,32 +378,30 @@ darwin_check_new_threads (struct inferior *inf)
   MACH_CHECK_ERROR (kret);
 }
 
-static int
-find_inferior_task_it (struct inferior *inf, void *port_ptr)
-{
-  darwin_inferior *priv = get_darwin_inferior (inf);
-
-  return priv->task == *(task_t *)port_ptr;
-}
-
-static int
-find_inferior_pid_it (struct inferior *inf, void *pid_ptr)
-{
-  return inf->pid == *(int *)pid_ptr;
-}
-
 /* Return an inferior by task port.  */
 static struct inferior *
 darwin_find_inferior_by_task (task_t port)
 {
-  return iterate_over_inferiors (&find_inferior_task_it, &port);
+  for (inferior *inf : all_inferiors ())
+    {
+      darwin_inferior *priv = get_darwin_inferior (inf);
+
+      if (priv != nullptr && priv->task == port)
+       return inf;
+    }
+  return nullptr;
 }
 
 /* Return an inferior by pid port.  */
 static struct inferior *
 darwin_find_inferior_by_pid (int pid)
 {
-  return iterate_over_inferiors (&find_inferior_pid_it, &pid);
+  for (inferior *inf : all_inferiors ())
+    {
+      if (inf->pid == pid)
+       return inf;
+    }
+  return nullptr;
 }
 
 /* Return a thread by port.  */
@@ -403,11 +410,12 @@ darwin_find_thread (struct inferior *inf, thread_t thread)
 {
   darwin_inferior *priv = get_darwin_inferior (inf);
 
-  for (darwin_thread_t *t : priv->threads)
-    {
-      if (t->gdb_port == thread)
-       return t;
-    }
+  if (priv != nullptr)
+    for (darwin_thread_t *t : priv->threads)
+      {
+       if (t->gdb_port == thread)
+         return t;
+      }
 
   return NULL;
 }
@@ -419,7 +427,7 @@ darwin_suspend_inferior (struct inferior *inf)
 {
   darwin_inferior *priv = get_darwin_inferior (inf);
 
-  if (!priv->suspended)
+  if (priv != nullptr && !priv->suspended)
     {
       kern_return_t kret;
 
@@ -437,7 +445,7 @@ darwin_resume_inferior (struct inferior *inf)
 {
   darwin_inferior *priv = get_darwin_inferior (inf);
 
-  if (priv->suspended)
+  if (priv != nullptr && priv->suspended)
     {
       kern_return_t kret;
 
@@ -448,23 +456,6 @@ darwin_resume_inferior (struct inferior *inf)
     }
 }
 
-/* Iterator functions.  */
-
-static int
-darwin_suspend_inferior_it (struct inferior *inf, void *arg)
-{
-  darwin_suspend_inferior (inf);
-  darwin_check_new_threads (inf);
-  return 0;
-}
-
-static int
-darwin_resume_inferior_it (struct inferior *inf, void *arg)
-{
-  darwin_resume_inferior (inf);
-  return 0;
-}
-
 static void
 darwin_dump_message (mach_msg_header_t *hdr, int disp_body)
 {
@@ -597,10 +588,10 @@ darwin_check_message_ndr (NDR_record_t *ndr)
 
 /* Decode an exception message.  */
 
-static int
-darwin_decode_exception_message (mach_msg_header_t *hdr,
-                                struct inferior **pinf,
-                                darwin_thread_t **pthread)
+int
+darwin_nat_target::decode_exception_message (mach_msg_header_t *hdr,
+                                            inferior **pinf,
+                                            darwin_thread_t **pthread)
 {
   mach_msg_body_t *bod = (mach_msg_body_t*)(hdr + 1);
   mach_msg_port_descriptor_t *desc = (mach_msg_port_descriptor_t *)(bod + 1);
@@ -674,7 +665,6 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
       /* 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;
 
       inferior_debug
@@ -699,7 +689,7 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
   /* 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);
+  check_new_threads (inf);
 
   /* Free the thread port (as gdb knows the thread, it has already has a right
      for it, so this just decrement a reference counter).  */
@@ -742,11 +732,7 @@ 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)
@@ -766,11 +752,13 @@ darwin_decode_notify_message (mach_msg_header_t *hdr, struct inferior **pinf)
   inf = darwin_find_inferior_by_task (task_port);
   *pinf = inf;
 
-  darwin_inferior *priv = get_darwin_inferior (inf);
-
   /* Check message destination.  */
-  if (inf != NULL && hdr->msgh_local_port != priv->notify_port)
-    return -4;
+  if (inf != NULL)
+    {
+      darwin_inferior *priv = get_darwin_inferior (inf);
+      if (hdr->msgh_local_port != priv->notify_port)
+       return -4;
+    }
 
   return 0;
 }
@@ -882,25 +870,9 @@ darwin_resume_inferior_threads (struct inferior *inf, int step, int nsignal)
 {
   darwin_inferior *priv = get_darwin_inferior (inf);
 
-  for (darwin_thread_t *thread : priv->threads)
-    darwin_resume_thread (inf, thread, step, nsignal);
-}
-
-struct resume_inferior_threads_param
-{
-  int step;
-  int nsignal;
-};
-
-static int
-darwin_resume_inferior_threads_it (struct inferior *inf, void *param)
-{
-  int step = ((struct resume_inferior_threads_param *)param)->step;
-  int nsignal = ((struct resume_inferior_threads_param *)param)->nsignal;
-
-  darwin_resume_inferior_threads (inf, step, nsignal);
-
-  return 0;
+  if (priv != nullptr)
+    for (darwin_thread_t *thread : priv->threads)
+      darwin_resume_thread (inf, thread, step, nsignal);
 }
 
 /* Suspend all threads of INF.  */
@@ -932,12 +904,8 @@ void
 darwin_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
 {
   struct target_waitstatus status;
-  int pid;
 
-  kern_return_t kret;
-  int res;
   int nsignal;
-  struct inferior *inf;
 
   inferior_debug
     (2, _("darwin_resume: pid=%d, tid=0x%lx, step=%d, signal=%d\n"),
@@ -955,19 +923,17 @@ darwin_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
   /* minus_one_ptid is RESUME_ALL.  */
   if (ptid == minus_one_ptid)
     {
-      struct resume_inferior_threads_param param;
-
-      param.nsignal = nsignal;
-      param.step = step;
-
       /* Resume threads.  */
-      iterate_over_inferiors (darwin_resume_inferior_threads_it, &param);
+      for (inferior *inf : all_inferiors ())
+       darwin_resume_inferior_threads (inf, step, nsignal);
+
       /* Resume tasks.  */
-      iterate_over_inferiors (darwin_resume_inferior_it, NULL);
+      for (inferior *inf : all_inferiors ())
+       darwin_resume_inferior (inf);
     }
   else
     {
-      struct inferior *inf = find_inferior_ptid (ptid);
+      inferior *inf = find_inferior_ptid (this, ptid);
       long tid = ptid.tid ();
 
       /* Stop the inferior (should be useless).  */
@@ -993,11 +959,11 @@ darwin_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
     }
 }
 
-static ptid_t
-darwin_decode_message (mach_msg_header_t *hdr,
-                      darwin_thread_t **pthread,
-                      struct inferior **pinf,
-                      struct target_waitstatus *status)
+ptid_t
+darwin_nat_target::decode_message (mach_msg_header_t *hdr,
+                                  darwin_thread_t **pthread,
+                                  inferior **pinf,
+                                  target_waitstatus *status)
 {
   darwin_thread_t *thread;
   struct inferior *inf;
@@ -1008,7 +974,7 @@ darwin_decode_message (mach_msg_header_t *hdr,
       int res;
 
       /* Decode message.  */
-      res = darwin_decode_exception_message (hdr, &inf, &thread);
+      res = decode_exception_message (hdr, &inf, &thread);
 
       if (res < 0)
        {
@@ -1117,14 +1083,14 @@ darwin_decode_message (mach_msg_header_t *hdr,
 
          if (!priv->no_ptrace)
            {
-             pid_t res;
+             pid_t res_pid;
              int wstatus;
 
-             res = wait4 (inf->pid, &wstatus, 0, NULL);
-             if (res < 0 || res != inf->pid)
+             res_pid = wait4 (inf->pid, &wstatus, 0, NULL);
+             if (res_pid < 0 || res_pid != inf->pid)
                {
                  printf_unfiltered (_("wait4: res=%d: %s\n"),
-                                    res, safe_strerror (errno));
+                                    res_pid, safe_strerror (errno));
                  status->kind = TARGET_WAITKIND_IGNORE;
                  return minus_one_ptid;
                }
@@ -1140,7 +1106,7 @@ darwin_decode_message (mach_msg_header_t *hdr,
                }
 
              inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"),
-                             res, wstatus);
+                             res_pid, wstatus);
 
              /* Looks necessary on Leopard and harmless...  */
              wait4 (inf->pid, &wstatus, 0, NULL);
@@ -1164,8 +1130,8 @@ darwin_decode_message (mach_msg_header_t *hdr,
   return minus_one_ptid;
 }
 
-static int
-cancel_breakpoint (ptid_t ptid)
+int
+darwin_nat_target::cancel_breakpoint (ptid_t ptid)
 {
   /* Arrange for a breakpoint to be hit again later.  We will handle
      the current event, eventually we will resume this thread, and this
@@ -1175,7 +1141,7 @@ cancel_breakpoint (ptid_t ptid)
      delete or disable the breakpoint, but the thread will have already
      tripped on it.  */
 
-  struct regcache *regcache = get_thread_regcache (ptid);
+  struct regcache *regcache = get_thread_regcache (this, ptid);
   struct gdbarch *gdbarch = regcache->arch ();
   CORE_ADDR pc;
 
@@ -1194,8 +1160,8 @@ cancel_breakpoint (ptid_t ptid)
   return 0;
 }
 
-static ptid_t
-darwin_wait (ptid_t ptid, struct target_waitstatus *status)
+ptid_t
+darwin_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *status)
 {
   kern_return_t kret;
   union
@@ -1206,7 +1172,6 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status)
   mach_msg_header_t *hdr = &msgin.hdr;
   ptid_t res;
   darwin_thread_t *thread;
-  struct inferior *inf;
 
   inferior_debug
     (2, _("darwin_wait: waiting for a message pid=%d thread=%lx\n"),
@@ -1215,7 +1180,7 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status)
   /* Handle fake stop events at first.  */
   if (darwin_inf_fake_stop != NULL)
     {
-      inf = darwin_inf_fake_stop;
+      inferior *inf = darwin_inf_fake_stop;
       darwin_inf_fake_stop = NULL;
 
       darwin_inferior *priv = get_darwin_inferior (inf);
@@ -1254,7 +1219,8 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status)
       if (darwin_debug_flag > 10)
        darwin_dump_message (hdr, darwin_debug_flag > 11);
 
-      res = darwin_decode_message (hdr, &thread, &inf, status);
+      inferior *inf;
+      res = decode_message (hdr, &thread, &inf, status);
       if (res == minus_one_ptid)
        continue;
 
@@ -1265,7 +1231,11 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status)
   while (status->kind == TARGET_WAITKIND_IGNORE);
 
   /* Stop all tasks.  */
-  iterate_over_inferiors (darwin_suspend_inferior_it, NULL);
+  for (inferior *inf : all_inferiors (this))
+    {
+      darwin_suspend_inferior (inf);
+      check_new_threads (inf);
+    }
 
   /* Read pending messages.  */
   while (1)
@@ -1290,7 +1260,8 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status)
       if (darwin_debug_flag > 10)
        darwin_dump_message (hdr, darwin_debug_flag > 11);
 
-      ptid2 = darwin_decode_message (hdr, &thread, &inf, &status2);
+      inferior *inf;
+      ptid2 = decode_message (hdr, &thread, &inf, &status2);
 
       if (inf != NULL && thread != NULL
          && thread->event.ex_type == EXC_BREAKPOINT)
@@ -1317,7 +1288,7 @@ ptid_t
 darwin_nat_target::wait (ptid_t ptid, struct target_waitstatus *status,
                         int options)
 {
-  return darwin_wait (ptid, status);
+  return wait_1 (ptid, status);
 }
 
 void
@@ -1354,7 +1325,6 @@ darwin_nat_target::mourn_inferior ()
   darwin_inferior *priv = get_darwin_inferior (inf);
   kern_return_t kret;
   mach_port_t prev;
-  int i;
 
   /* Deallocate threads.  */
   darwin_deallocate_threads (inf);
@@ -1408,13 +1378,11 @@ darwin_reply_to_all_pending_messages (struct inferior *inf)
     }
 }
 
-static void
-darwin_stop_inferior (struct inferior *inf)
+void
+darwin_nat_target::stop_inferior (inferior *inf)
 {
   struct target_waitstatus wstatus;
   ptid_t ptid;
-  kern_return_t kret;
-  int status;
   int res;
   darwin_inferior *priv = get_darwin_inferior (inf);
 
@@ -1427,14 +1395,14 @@ darwin_stop_inferior (struct inferior *inf)
   if (priv->no_ptrace)
     return;
 
-  res = kill (inf->pid, SIGSTOP);
+  res = ::kill (inf->pid, SIGSTOP);
   if (res != 0)
     warning (_("cannot kill: %s"), safe_strerror (errno));
 
   /* Wait until the process is really stopped.  */
   while (1)
     {
-      ptid = darwin_wait (inferior_ptid, &wstatus);
+      ptid = wait_1 (inferior_ptid, &wstatus);
       if (wstatus.kind == TARGET_WAITKIND_STOPPED
          && wstatus.value.sig == GDB_SIGNAL_STOP)
        break;
@@ -1495,7 +1463,6 @@ darwin_setup_exceptions (struct inferior *inf)
 {
   darwin_inferior *priv = get_darwin_inferior (inf);
   kern_return_t kret;
-  int traps_expected;
   exception_mask_t mask;
 
   kret = darwin_save_exception_ports (priv);
@@ -1525,7 +1492,6 @@ darwin_nat_target::kill ()
   struct target_waitstatus wstatus;
   ptid_t ptid;
   kern_return_t kret;
-  int status;
   int res;
 
   if (inferior_ptid == null_ptid)
@@ -1542,9 +1508,26 @@ darwin_nat_target::kill ()
 
   if (res == 0)
     {
+      /* On MacOS version Sierra, the darwin_restore_exception_ports call
+         does not work as expected.
+         When the kill function is called, the SIGKILL signal is received
+         by gdb whereas it should have been received by the kernel since
+         the exception ports have been restored.
+         This behavior is not the expected one thus gdb does not reply to
+         the received SIGKILL message. This situation leads to a "busy"
+         resource from the kernel point of view and the inferior is never
+         released, causing it to remain as a zombie process, even after
+        GDB exits.
+         To work around this, we mark all the threads of the inferior as
+         signaled thus darwin_decode_message function knows that the kill
+         signal was sent by gdb and will take the appropriate action
+         (cancel signal and reply to the signal message).  */
+      for (darwin_thread_t *thread : priv->threads)
+        thread->signaled = 1;
+
       darwin_resume_inferior (inf);
 
-      ptid = darwin_wait (inferior_ptid, &wstatus);
+      ptid = wait_1 (inferior_ptid, &wstatus);
     }
   else if (errno != ESRCH)
     warning (_("Failed to kill inferior: kill (%d, 9) returned [%s]"),
@@ -1586,15 +1569,11 @@ static void
 darwin_attach_pid (struct inferior *inf)
 {
   kern_return_t kret;
-  mach_port_t prev_port;
-  int traps_expected;
-  mach_port_t prev_not;
-  exception_mask_t mask;
 
   darwin_inferior *priv = new darwin_inferior;
   inf->priv.reset (priv);
 
-  TRY
+  try
     {
       kret = task_for_pid (gdb_task, inf->pid, &priv->task);
       if (kret != KERN_SUCCESS)
@@ -1671,14 +1650,13 @@ darwin_attach_pid (struct inferior *inf)
 
       darwin_setup_exceptions (inf);
     }
-  CATCH (ex, RETURN_MASK_ALL)
+  catch (const gdb_exception &ex)
     {
       exit_inferior (inf);
       inferior_ptid = null_ptid;
 
-      throw_exception (ex);
+      throw;
     }
-  END_CATCH
 
   target_ops *darwin_ops = get_native_target ();
   if (!target_is_pushed (darwin_ops))
@@ -1690,25 +1668,21 @@ darwin_attach_pid (struct inferior *inf)
 static struct thread_info *
 thread_info_from_private_thread_info (darwin_thread_info *pti)
 {
-  struct thread_info *it;
-
-  ALL_THREADS (it)
+  for (struct thread_info *it : all_threads ())
     {
       darwin_thread_info *iter_pti = get_darwin_thread_info (it);
 
       if (iter_pti->gdb_port == pti->gdb_port)
-       break;
+       return it;
     }
 
-  gdb_assert (it != NULL);
-
-  return it;
+  gdb_assert_not_reached ("did not find gdb thread for darwin thread");
 }
 
-static void
-darwin_init_thread_list (struct inferior *inf)
+void
+darwin_nat_target::init_thread_list (inferior *inf)
 {
-  darwin_check_new_threads (inf);
+  check_new_threads (inf);
 
   darwin_inferior *priv = get_darwin_inferior (inf);
 
@@ -1772,25 +1746,21 @@ darwin_pre_ptrace (void)
   mark_fd_no_cloexec (ptrace_fds[1]);
 }
 
-static void
-darwin_ptrace_him (int pid)
+void
+darwin_nat_target::ptrace_him (int pid)
 {
-  task_t itask;
-  kern_return_t kret;
-  mach_port_t prev_port;
-  int traps_expected;
   struct inferior *inf = current_inferior ();
 
   darwin_attach_pid (inf);
 
   /* Let's the child run.  */
-  close (ptrace_fds[0]);
-  close (ptrace_fds[1]);
+  ::close (ptrace_fds[0]);
+  ::close (ptrace_fds[1]);
 
   unmark_fd_no_cloexec (ptrace_fds[0]);
   unmark_fd_no_cloexec (ptrace_fds[1]);
 
-  darwin_init_thread_list (inf);
+  init_thread_list (inf);
 
   gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 }
@@ -1829,14 +1799,174 @@ darwin_execvp (const char *file, char * const argv[], char * const env[])
   posix_spawnp (NULL, argv[0], NULL, &attr, argv, env);
 }
 
+/* Read kernel version, and return TRUE if this host may have System
+   Integrity Protection (Sierra or later).  */
+
+static bool
+may_have_sip ()
+{
+  char str[16];
+  size_t sz = sizeof (str);
+  int ret;
+
+  ret = sysctlbyname ("kern.osrelease", str, &sz, NULL, 0);
+  if (ret == 0 && sz < sizeof (str))
+    {
+      unsigned long ver = strtoul (str, NULL, 10);
+      if (ver >= 16)
+        return true;
+    }
+  return false;
+}
+
+/* A helper for maybe_cache_shell.  This copies the shell to the
+   cache.  It will throw an exception on any failure.  */
+
+static void
+copy_shell_to_cache (const char *shell, const std::string &new_name)
+{
+  scoped_fd from_fd (gdb_open_cloexec (shell, O_RDONLY, 0));
+  if (from_fd.get () < 0)
+    error (_("Could not open shell (%s) for reading: %s"),
+          shell, safe_strerror (errno));
+
+  std::string new_dir = ldirname (new_name.c_str ());
+  if (!mkdir_recursive (new_dir.c_str ()))
+    error (_("Could not make cache directory \"%s\": %s"),
+          new_dir.c_str (), safe_strerror (errno));
+
+  gdb::char_vector temp_name = make_temp_filename (new_name);
+  scoped_fd to_fd (gdb_mkostemp_cloexec (&temp_name[0]));
+  gdb::unlinker unlink_file_on_error (temp_name.data ());
+
+  if (to_fd.get () < 0)
+    error (_("Could not open temporary file \"%s\" for writing: %s"),
+          temp_name.data (), safe_strerror (errno));
+
+  if (fcopyfile (from_fd.get (), to_fd.get (), nullptr,
+                COPYFILE_STAT | COPYFILE_DATA) != 0)
+    error (_("Could not copy shell to cache as \"%s\": %s"),
+          temp_name.data (), safe_strerror (errno));
+
+  /* Be sure that the caching is atomic so that we don't get bad
+     results from multiple copies of gdb running at the same time.  */
+  if (rename (temp_name.data (), new_name.c_str ()) != 0)
+    error (_("Could not rename shell cache file to \"%s\": %s"),
+          new_name.c_str (), safe_strerror (errno));
+
+  unlink_file_on_error.keep ();
+}
+
+/* If $SHELL is restricted, try to cache a copy.  Starting with El
+   Capitan, macOS introduced System Integrity Protection.  Among other
+   things, this prevents certain executables from being ptrace'd.  In
+   particular, executables in /bin, like most shells, are affected.
+   To work around this, while preserving command-line glob expansion
+   and redirections, gdb will cache a copy of the shell.  Return true
+   if all is well -- either the shell is not subject to SIP or it has
+   been successfully cached.  Returns false if something failed.  */
+
+static bool
+maybe_cache_shell ()
+{
+  /* SF_RESTRICTED is defined in sys/stat.h and lets us determine if a
+     given file is subject to SIP.  */
+#ifdef SF_RESTRICTED
+
+  /* If a check fails we want to revert -- maybe the user deleted the
+     cache while gdb was running, or something like that.  */
+  copied_shell = nullptr;
+
+  const char *shell = get_shell ();
+  if (!IS_ABSOLUTE_PATH (shell))
+    {
+      warning (_("This version of macOS has System Integrity Protection.\n\
+Normally gdb would try to work around this by caching a copy of your shell,\n\
+but because your shell (%s) is not an absolute path, this is being skipped."),
+              shell);
+      return false;
+    }
+
+  struct stat sb;
+  if (stat (shell, &sb) < 0)
+    {
+      warning (_("This version of macOS has System Integrity Protection.\n\
+Normally gdb would try to work around this by caching a copy of your shell,\n\
+but because gdb could not stat your shell (%s), this is being skipped.\n\
+The error was: %s"),
+              shell, safe_strerror (errno));
+      return false;
+    }
+
+  if ((sb.st_flags & SF_RESTRICTED) == 0)
+    return true;
+
+  /* Put the copy somewhere like ~/Library/Caches/gdb/bin/sh.  */
+  std::string new_name = get_standard_cache_dir ();
+  /* There's no need to insert a directory separator here, because
+     SHELL is known to be absolute.  */
+  new_name.append (shell);
+
+  /* Maybe it was cached by some earlier gdb.  */
+  if (stat (new_name.c_str (), &sb) != 0 || !S_ISREG (sb.st_mode))
+    {
+      try
+       {
+         copy_shell_to_cache (shell, new_name);
+       }
+      catch (const gdb_exception_error &ex)
+       {
+         warning (_("This version of macOS has System Integrity Protection.\n\
+Because `startup-with-shell' is enabled, gdb tried to work around SIP by\n\
+caching a copy of your shell.  However, this failed:\n\
+%s\n\
+If you correct the problem, gdb will automatically try again the next time\n\
+you \"run\".  To prevent these attempts, you can use:\n\
+    set startup-with-shell off"),
+                  ex.what ());
+         return false;
+       }
+
+      printf_filtered (_("Note: this version of macOS has System Integrity Protection.\n\
+Because `startup-with-shell' is enabled, gdb has worked around this by\n\
+caching a copy of your shell.  The shell used by \"run\" is now:\n\
+    %s\n"),
+                      new_name.c_str ());
+    }
+
+  /* We need to make sure that the new name has the correct lifetime.  */
+  static std::string saved_shell = std::move (new_name);
+  copied_shell = saved_shell.c_str ();
+
+#endif /* SF_RESTRICTED */
+
+  return true;
+}
+
 void
 darwin_nat_target::create_inferior (const char *exec_file,
                                    const std::string &allargs,
                                    char **env, int from_tty)
 {
+  gdb::optional<scoped_restore_tmpl<bool>> restore_startup_with_shell;
+  darwin_nat_target *the_target = this;
+
+  if (startup_with_shell && may_have_sip ())
+    {
+      if (!maybe_cache_shell ())
+       {
+         warning (_("startup-with-shell is now temporarily disabled"));
+         restore_startup_with_shell.emplace (&startup_with_shell, 0);
+       }
+    }
+
   /* Do the hard work.  */
   fork_inferior (exec_file, allargs, env, darwin_ptrace_me,
-                darwin_ptrace_him, darwin_pre_ptrace, NULL,
+                [the_target] (int pid)
+                  {
+                    the_target->ptrace_him (pid);
+                  },
+                darwin_pre_ptrace, copied_shell,
                 darwin_execvp);
 }
 \f
@@ -1874,11 +2004,7 @@ void
 darwin_nat_target::attach (const char *args, int from_tty)
 {
   pid_t pid;
-  pid_t pid2;
-  int wstatus;
-  int res;
   struct inferior *inf;
-  kern_return_t kret;
 
   pid = parse_pid_to_attach (args);
 
@@ -1887,16 +2013,14 @@ darwin_nat_target::attach (const char *args, int from_tty)
 
   if (from_tty)
     {
-      char *exec_file = get_exec_file (0);
+      const char *exec_file = get_exec_file (0);
 
       if (exec_file)
        printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
-                          target_pid_to_str (ptid_t (pid)));
+                          target_pid_to_str (ptid_t (pid)).c_str ());
       else
        printf_unfiltered (_("Attaching to %s\n"),
-                          target_pid_to_str (ptid_t (pid)));
-
-      gdb_flush (gdb_stdout);
+                          target_pid_to_str (ptid_t (pid)).c_str ());
     }
 
   if (pid == 0 || ::kill (pid, 0) < 0)
@@ -1912,7 +2036,7 @@ darwin_nat_target::attach (const char *args, int from_tty)
 
   darwin_suspend_inferior (inf);
 
-  darwin_init_thread_list (inf);
+  init_thread_list (inf);
 
   darwin_inferior *priv = get_darwin_inferior (inf);
 
@@ -1934,7 +2058,6 @@ darwin_nat_target::attach (const char *args, int from_tty)
 void
 darwin_nat_target::detach (inferior *inf, int from_tty)
 {
-  pid_t pid = inferior_ptid.pid ();
   darwin_inferior *priv = get_darwin_inferior (inf);
   kern_return_t kret;
   int res;
@@ -1944,7 +2067,7 @@ darwin_nat_target::detach (inferior *inf, int from_tty)
 
   /* If ptrace() is in use, stop the process.  */
   if (!priv->no_ptrace)
-    darwin_stop_inferior (inf);
+    stop_inferior (inf);
 
   kret = darwin_restore_exception_ports (priv);
   MACH_CHECK_ERROR (kret);
@@ -1968,18 +2091,14 @@ darwin_nat_target::detach (inferior *inf, int from_tty)
   mourn_inferior ();
 }
 
-const char *
+std::string
 darwin_nat_target::pid_to_str (ptid_t ptid)
 {
-  static char buf[80];
   long tid = ptid.tid ();
 
   if (tid != 0)
-    {
-      snprintf (buf, sizeof (buf), _("Thread 0x%lx of process %u"),
-               tid, ptid.pid ());
-      return buf;
-    }
+    return string_printf (_("Thread 0x%lx of process %u"),
+                         tid, ptid.pid ());
 
   return normal_pid_to_str (ptid);
 }
@@ -1994,7 +2113,7 @@ darwin_nat_target::thread_alive (ptid_t ptid)
    copy it to RDADDR in gdb's address space.
    If WRADDR is not NULL, write gdb's LEN bytes from WRADDR and copy it
    to ADDR in inferior task's address space.
-   Return 0 on failure; number of bytes read / writen otherwise.  */
+   Return 0 on failure; number of bytes read / written otherwise.  */
 
 static int
 darwin_read_write_inferior (task_t task, CORE_ADDR addr,
@@ -2003,11 +2122,6 @@ darwin_read_write_inferior (task_t task, CORE_ADDR addr,
 {
   kern_return_t kret;
   mach_vm_size_t res_length = 0;
-  pointer_t copied;
-  mach_msg_type_number_t copy_count;
-  mach_vm_size_t remaining_length;
-  mach_vm_address_t region_address;
-  mach_vm_size_t region_length;
 
   inferior_debug (8, _("darwin_read_write_inferior(task=0x%x, %s, len=%s)\n"),
                  task, core_addr_to_string (addr), pulongest (length));
@@ -2161,7 +2275,6 @@ darwin_read_dyld_info (task_t task, CORE_ADDR addr, gdb_byte *rdaddr,
 {
   struct task_dyld_info task_dyld_info;
   mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
-  int sz = TASK_DYLD_INFO_COUNT * sizeof (natural_t);
   kern_return_t kret;
 
   if (addr != 0 || length > sizeof (mach_vm_address_t))
@@ -2337,6 +2450,7 @@ darwin_nat_target::supports_multi_process ()
   return true;
 }
 
+void _initialize_darwin_nat ();
 void
 _initialize_darwin_nat ()
 {
This page took 0.05422 seconds and 4 git commands to generate.