2012-03-01 Pedro Alves <palves@redhat.com>
[deliverable/binutils-gdb.git] / gdb / darwin-nat.c
index 2b456893b9991ce9ef06c67132cb606c9530d185..0feebe3ab587e84d50a8b74a0b7a495b86bb1785 100644 (file)
@@ -1,5 +1,5 @@
 /* Darwin support for GDB, the GNU debugger.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008-2012 Free Software Foundation, Inc.
 
    Contributed by AdaCore.
 
@@ -53,6 +53,7 @@
 #include <sys/proc.h>
 #include <libproc.h>
 #include <sys/syscall.h>
+#include <spawn.h>
 
 #include <mach/mach_error.h>
 #include <mach/mach_vm.h>
@@ -99,8 +100,6 @@ static ptid_t darwin_wait (ptid_t ptid, struct target_waitstatus *status);
 
 static void darwin_mourn_inferior (struct target_ops *ops);
 
-static int darwin_lookup_task (char *args, task_t * ptask, int *ppid);
-
 static void darwin_kill_inferior (struct target_ops *ops);
 
 static void darwin_ptrace_me (void);
@@ -131,7 +130,7 @@ mach_port_t darwin_ex_port;
 /* Port set.  */
 mach_port_t darwin_port_set;
 
-/* Page size. */
+/* Page size.  */
 static vm_size_t mach_page_size;
 
 /* If Set, catch all mach exceptions (before they are converted to signals
@@ -147,6 +146,34 @@ static struct inferior *darwin_inf_fake_stop;
 /* This controls output of inferior debugging.  */
 static int darwin_debug_flag = 0;
 
+/* Create a __TEXT __info_plist section in the executable so that gdb could
+   be signed.  This is required to get an authorization for task_for_pid.
+
+   Once gdb is built, you can either:
+   * make it setgid procmod
+   * or codesign it with any system-trusted signing authority.
+   See taskgated(8) for details.  */
+static const unsigned char info_plist[]
+__attribute__ ((section ("__TEXT,__info_plist"),used)) =
+  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+  "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\""
+  " \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+  "<plist version=\"1.0\">\n"
+  "<dict>\n"
+  "  <key>CFBundleIdentifier</key>\n"
+  "  <string>org.gnu.gdb</string>\n"
+  "  <key>CFBundleName</key>\n"
+  "  <string>gdb</string>\n"
+  "  <key>CFBundleVersion</key>\n"
+  "  <string>1.0</string>\n"
+  "  <key>SecTaskAccess</key>\n"
+  "  <array>\n"
+  "    <string>allowed</string>\n"
+  "    <string>debug</string>\n"
+  "  </array>\n"
+  "</dict>\n"
+  "</plist>\n";
+
 static void
 inferior_debug (int level, const char *fmt, ...)
 {
@@ -170,7 +197,7 @@ mach_check_error (kern_return_t ret, const char *file,
   if (func == NULL)
     func = _("[UNKNOWN]");
 
-  warning (_("Mach error at \"%s:%u\" in function \"%s\": %s (0x%lx)\n"),
+  warning (_("Mach error at \"%s:%u\" in function \"%s\": %s (0x%lx)"),
           file, line, func, mach_error_string (ret), (unsigned long) ret);
 }
 
@@ -207,13 +234,25 @@ unparse_exception_type (unsigned int i)
     }
 }
 
+/* Set errno to zero, and then call ptrace with the given arguments.
+   If inferior debugging traces are on, then also print a debug
+   trace.
+
+   The returned value is the same as the value returned by ptrace,
+   except in the case where that value is -1 but errno is zero.
+   This case is documented to be a non-error situation, so we
+   return zero in that case. */
+
 static int
 darwin_ptrace (const char *name,
               int request, int pid, PTRACE_TYPE_ARG3 arg3, int arg4)
 {
   int ret;
 
+  errno = 0;
   ret = ptrace (request, pid, (caddr_t) arg3, arg4);
+  if (ret == -1 && errno == 0)
+    ret = 0;
 
   inferior_debug (4, _("ptrace (%s, %d, 0x%x, %d): %d (%s)\n"),
                   name, pid, arg3, arg4, ret,
@@ -337,7 +376,7 @@ darwin_check_new_threads (struct inferior *inf)
          old_ix++;
          continue;
        }
-      gdb_assert (0);
+      gdb_assert_not_reached ("unexpected thread case");
     }
 
   if (darwin_inf->threads)
@@ -577,8 +616,11 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
     return -1;
   *pthread = thread;
 
+  /* The thread should be running.  However we have observed cases where a thread
+     got a SIGTTIN message after being stopped.  */
+  gdb_assert (thread->msg_state != DARWIN_MESSAGE);
+
   /* Finish decoding.  */
-  gdb_assert (thread->msg_state == DARWIN_RUNNING);
   thread->event.header = *hdr;
   thread->event.thread_port = thread_port;
   thread->event.task_port = task_port;
@@ -888,7 +930,7 @@ darwin_decode_message (mach_msg_header_t *hdr,
        case EXC_BREAKPOINT:
          /* Many internal GDB routines expect breakpoints to be reported
             as TARGET_SIGNAL_TRAP, and will report TARGET_EXC_BREAKPOINT
-            as a spurious signal. */
+            as a spurious signal.  */
          status->value.sig = TARGET_SIGNAL_TRAP;
          break;
        default:
@@ -954,7 +996,7 @@ darwin_decode_message (mach_msg_header_t *hdr,
 static int
 cancel_breakpoint (ptid_t ptid)
 {
-  /* Arrange for a breakpoint to be hit again later. We will handle
+  /* Arrange for a breakpoint to be hit again later.  We will handle
      the current event, eventually we will resume this thread, and this
      breakpoint will trap again.
 
@@ -967,7 +1009,7 @@ cancel_breakpoint (ptid_t ptid)
   CORE_ADDR pc;
 
   pc = regcache_read_pc (regcache) - gdbarch_decr_pc_after_break (gdbarch);
-  if (breakpoint_inserted_here_p (pc))
+  if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
     {
       inferior_debug (4, "cancel_breakpoint for thread %x\n",
                      ptid_get_tid (ptid));
@@ -1210,7 +1252,7 @@ darwin_stop_inferior (struct inferior *inf)
 
   res = kill (inf->pid, SIGSTOP);
   if (res != 0)
-    warning (_("cannot kill: %s\n"), safe_strerror (errno));
+    warning (_("cannot kill: %s"), safe_strerror (errno));
 
   /* Wait until the process is really stopped.  */
   while (1)
@@ -1275,7 +1317,10 @@ darwin_kill_inferior (struct target_ops *ops)
       darwin_stop_inferior (inf);
 
       res = PTRACE (PT_KILL, inf->pid, 0, 0);
-      gdb_assert (res == 0);
+      if (res != 0)
+        warning (_("Failed to kill inferior: ptrace returned %d "
+                  "[%s] (pid=%d)"),
+                res, safe_strerror (errno), inf->pid);
 
       darwin_reply_to_all_pending_messages (inf);
 
@@ -1323,7 +1368,7 @@ darwin_attach_pid (struct inferior *inf)
        }
 
       error (_("Unable to find Mach task port for process-id %d: %s (0x%lx).\n"
-              " (please check gdb is setgid procmod)"),
+              " (please check gdb is codesigned - see taskgated(8))"),
              inf->pid, mach_error_string (kret), (unsigned long) kret);
     }
 
@@ -1462,13 +1507,47 @@ darwin_ptrace_him (int pid)
   startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
 }
 
+static void
+darwin_execvp (const char *file, char * const argv[], char * const env[])
+{
+  posix_spawnattr_t attr;
+  short ps_flags = 0;
+  int res;
+
+  res = posix_spawnattr_init (&attr);
+  if (res != 0)
+    {
+      fprintf_unfiltered
+        (gdb_stderr, "Cannot initialize attribute for posix_spawn\n");
+      return;
+    }
+
+  /* Do like execve: replace the image.  */
+  ps_flags = POSIX_SPAWN_SETEXEC;
+
+  /* Disable ASLR.  The constant doesn't look to be available outside the
+     kernel include files.  */
+#ifndef _POSIX_SPAWN_DISABLE_ASLR
+#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
+#endif
+  ps_flags |= _POSIX_SPAWN_DISABLE_ASLR;
+  res = posix_spawnattr_setflags (&attr, ps_flags);
+  if (res != 0)
+    {
+      fprintf_unfiltered (gdb_stderr, "Cannot set posix_spawn flags\n");
+      return;
+    }
+
+  posix_spawnp (NULL, argv[0], NULL, &attr, argv, env);
+}
+
 static void
 darwin_create_inferior (struct target_ops *ops, char *exec_file,
                        char *allargs, char **env, int from_tty)
 {
   /* Do the hard work.  */
   fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
-                darwin_pre_ptrace, NULL);
+                darwin_pre_ptrace, NULL, darwin_execvp);
 
   /* Return now in case of error.  */
   if (ptid_equal (inferior_ptid, null_ptid))
@@ -1488,12 +1567,9 @@ darwin_attach (struct target_ops *ops, char *args, int from_tty)
   struct inferior *inf;
   kern_return_t kret;
 
-  if (!args)
-    error_no_arg (_("process-id to attach"));
+  pid = parse_pid_to_attach (args);
 
-  pid = atoi (args);
-
-  if (pid == getpid ())                /* Trying to masturbate? */
+  if (pid == getpid ())                /* Trying to masturbate?  */
     error (_("I refuse to debug myself!"));
 
   if (from_tty)
@@ -1515,8 +1591,10 @@ darwin_attach (struct target_ops *ops, char *args, int from_tty)
            pid, safe_strerror (errno), errno);
 
   inferior_ptid = pid_to_ptid (pid);
-  inf = add_inferior (pid);
+  inf = current_inferior ();
+  inferior_appeared (inf, pid);
   inf->attach_flag = 1;
+
   /* Always add a main thread.  */
   add_thread_silent (inferior_ptid);
 
@@ -1576,7 +1654,11 @@ darwin_detach (struct target_ops *ops, char *args, int from_tty)
 
   darwin_reply_to_all_pending_messages (inf);
 
-  darwin_resume_inferior (inf);
+  /* When using ptrace, we have just performed a PT_DETACH, which
+     resumes the inferior.  On the other hand, when we are not using
+     ptrace, we need to resume its execution ourselves.  */
+  if (inf->private->no_ptrace)
+    darwin_resume_inferior (inf);
 
   darwin_mourn_inferior (ops);
 }
@@ -1612,7 +1694,7 @@ darwin_thread_alive (struct target_ops *ops, 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 / writen otherwise.  */
 static int
 darwin_read_write_inferior (task_t task, CORE_ADDR addr,
                            char *rdaddr, const char *wraddr, int length)
@@ -1630,7 +1712,7 @@ darwin_read_write_inferior (task_t task, CORE_ADDR addr,
   inferior_debug (8, _("darwin_read_write_inferior(task=%x, %s, len=%d)\n"),
                  task, core_addr_to_string (addr), length);
 
-  /* Get memory from inferior with page aligned addresses */
+  /* Get memory from inferior with page aligned addresses */
   kret = mach_vm_read (task, low_address, aligned_length,
                      &copied, &copy_count);
   if (kret != KERN_SUCCESS)
@@ -1682,10 +1764,10 @@ darwin_read_write_inferior (task_t task, CORE_ADDR addr,
         core_addr_to_string (region_start),
         core_addr_to_string (region_length));
 
-      /* Check for holes in memory */
+      /* Check for holes in memory */
       if (region_start > region_address)
        {
-         warning (_("No memory at %s (vs %s+0x%x). Nothing written"),
+         warning (_("No memory at %s (vs %s+0x%x).  Nothing written"),
                   core_addr_to_string (region_address),
                   core_addr_to_string (region_start),
                   (unsigned)region_length);
@@ -1741,9 +1823,35 @@ out:
   return length;
 }
 
+/* Read LENGTH bytes at offset ADDR of task_dyld_info for TASK, and copy them
+   to RDADDR.
+   Return 0 on failure; number of bytes read / writen otherwise.  */
+
+static int
+darwin_read_dyld_info (task_t task, CORE_ADDR addr, char *rdaddr, int length)
+{
+  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 >= sz)
+    return 0;
+
+  kret = task_info (task, TASK_DYLD_INFO, (task_info_t) &task_dyld_info, &count);
+  MACH_CHECK_ERROR (kret);
+  if (kret != KERN_SUCCESS)
+    return -1;
+  /* Truncate.  */
+  if (addr + length > sz)
+    length = sz - addr;
+  memcpy (rdaddr, (char *)&task_dyld_info + addr, length);
+  return length;
+}
+
 \f
 /* Return 0 on failure, number of bytes handled otherwise.  TARGET
-   is ignored. */
+   is ignored.  */
 static int
 darwin_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
                    struct mem_attrib *attrib, struct target_ops *target)
@@ -1772,14 +1880,27 @@ darwin_xfer_partial (struct target_ops *ops,
   struct inferior *inf = current_inferior ();
 
   inferior_debug
-    (8, _("darwin_xfer_partial(%s, %d, rbuf=%p, wbuf=%p) pid=%u\n"),
-     core_addr_to_string (offset), (int)len, readbuf, writebuf, inf->pid);
+    (8, _("darwin_xfer_partial(%s, %d, rbuf=%s, wbuf=%s) pid=%u\n"),
+     core_addr_to_string (offset), (int)len,
+     host_address_to_string (readbuf), host_address_to_string (writebuf),
+     inf->pid);
 
-  if (object != TARGET_OBJECT_MEMORY)
-    return -1;
+  switch (object)
+    {
+    case TARGET_OBJECT_MEMORY:
+      return darwin_read_write_inferior (inf->private->task, offset,
+                                         readbuf, writebuf, len);
+    case TARGET_OBJECT_DARWIN_DYLD_INFO:
+      if (writebuf != NULL || readbuf == NULL)
+        {
+          /* Support only read.  */
+          return -1;
+        }
+      return darwin_read_dyld_info (inf->private->task, offset, readbuf, len);
+    default:
+      return -1;
+    }
 
-  return darwin_read_write_inferior (inf->private->task, offset,
-                                    readbuf, writebuf, len);
 }
 
 static void
@@ -1934,7 +2055,6 @@ _initialize_darwin_inferior (void)
   darwin_ops->to_xfer_partial = darwin_xfer_partial;
   darwin_ops->to_supports_multi_process = darwin_supports_multi_process;
   darwin_ops->to_get_ada_task_ptid = darwin_get_ada_task_ptid;
-  /* darwin_ops->to_has_thread_control = tc_schedlock | tc_switch */;
 
   darwin_complete_target (darwin_ops);
 
This page took 0.030611 seconds and 4 git commands to generate.