packaging: bump to 2.24.90
[platform/upstream/binutils.git] / gdb / inf-ptrace.c
index 538816d..6eb8080 100644 (file)
@@ -1,8 +1,6 @@
 /* Low-level child interface to ptrace.
 
-   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
-   1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   Copyright (C) 1988-2014 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "command.h"
 #include "inferior.h"
 #include "inflow.h"
+#include "terminal.h"
 #include "gdbcore.h"
 #include "regcache.h"
-
-#include "gdb_assert.h"
-#include "gdb_string.h"
 #include "gdb_ptrace.h"
 #include "gdb_wait.h"
 #include <signal.h>
 
+#include "inf-ptrace.h"
 #include "inf-child.h"
 #include "gdbthread.h"
 
 
 #ifdef PT_GET_PROCESS_STATE
 
+/* Target hook for follow_fork.  On entry and at return inferior_ptid is
+   the ptid of the followed inferior.  */
+
 static int
-inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
+inf_ptrace_follow_fork (struct target_ops *ops, int follow_child,
+                       int detach_fork)
 {
-  pid_t pid, fpid;
-  ptrace_state_t pe;
-  struct thread_info *last_tp = NULL;
-
-  /* FIXME: kettenis/20050720: This stuff should really be passed as
-     an argument by our caller.  */
-  {
-    ptid_t ptid;
-    struct target_waitstatus status;
-
-    get_last_target_status (&ptid, &status);
-    gdb_assert (status.kind == TARGET_WAITKIND_FORKED);
-
-    pid = ptid_get_pid (ptid);
-    last_tp = find_thread_pid (ptid);
-  }
-
-  if (ptrace (PT_GET_PROCESS_STATE, pid,
-              (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
-    perror_with_name (("ptrace"));
-
-  gdb_assert (pe.pe_report_event == PTRACE_FORK);
-  fpid = pe.pe_other_pid;
-
-  if (follow_child)
+  if (!follow_child)
     {
-      /* Copy user stepping state to the new inferior thread.  */
-      struct breakpoint *step_resume_breakpoint = last_tp->step_resume_breakpoint;
-      CORE_ADDR step_range_start = last_tp->step_range_start;
-      CORE_ADDR step_range_end = last_tp->step_range_end;
-      struct frame_id step_frame_id = last_tp->step_frame_id;
-
-      struct thread_info *tp;
+      pid_t child_pid = inferior_thread->pending_follow.value.related_pid;
 
-      /* Otherwise, deleting the parent would get rid of this
-        breakpoint.  */
-      last_tp->step_resume_breakpoint = NULL;
+      /* Breakpoints have already been detached from the child by
+        infrun.c.  */
 
-      /* Before detaching from the parent, remove all breakpoints from
-        it.  */
-      detach_breakpoints (pid);
-
-      if (ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
+      if (ptrace (PT_DETACH, child_pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
        perror_with_name (("ptrace"));
-
-      /* Switch inferior_ptid out of the parent's way.  */
-      inferior_ptid = pid_to_ptid (fpid);
-
-      /* Delete the parent.  */
-      detach_inferior (pid);
-
-      /* Add the child.  */
-      add_inferior (fpid);
-      tp = add_thread_silent (inferior_ptid);
-
-      tp->step_resume_breakpoint = step_resume_breakpoint;
-      tp->step_range_start = step_range_start;
-      tp->step_range_end = step_range_end;
-      tp->step_frame_id = step_frame_id;
-
-      /* Reset breakpoints in the child as appropriate.  */
-      follow_inferior_reset_breakpoints ();
-    }
-  else
-    {
-      inferior_ptid = pid_to_ptid (pid);
-      detach_breakpoints (fpid);
-
-      if (ptrace (PT_DETACH, fpid, (PTRACE_TYPE_ARG3)1, 0) == -1)
-       perror_with_name (("ptrace"));
-      detach_inferior (pid);
     }
 
   return 0;
@@ -142,21 +81,23 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 {
   int pid;
 
-  pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
-                      NULL, NULL);
+  /* Do not change either targets above or the same target if already present.
+     The reason is the target stack is shared across multiple inferiors.  */
+  int ops_already_pushed = target_is_pushed (ops);
+  struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
 
-  push_target (ops);
+  if (! ops_already_pushed)
+    {
+      /* Clear possible core file with its process_stratum.  */
+      push_target (ops);
+      make_cleanup_unpush_target (ops);
+    }
 
-  /* On some targets, there must be some explicit synchronization
-     between the parent and child processes after the debugger
-     forks, and before the child execs the debuggee program.  This
-     call basically gives permission for the child to exec.  */
+  pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
+                      NULL, NULL, NULL);
 
-  target_acknowledge_created_inferior (pid);
+  discard_cleanups (back_to);
 
-  /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h, and will
-     be 1 or 2 depending on whether we're starting without or with a
-     shell.  */
   startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
 
   /* On some targets, there must be some explicit actions taken after
@@ -167,7 +108,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 #ifdef PT_GET_PROCESS_STATE
 
 static void
-inf_ptrace_post_startup_inferior (ptid_t pid)
+inf_ptrace_post_startup_inferior (struct target_ops *self, ptid_t pid)
 {
   ptrace_event_t pe;
 
@@ -194,33 +135,37 @@ inf_ptrace_mourn_inferior (struct target_ops *ops)
      only report its exit status to its original parent.  */
   waitpid (ptid_get_pid (inferior_ptid), &status, 0);
 
-  unpush_target (ops);
-  generic_mourn_inferior ();
+  inf_child_mourn_inferior (ops);
 }
 
 /* Attach to the process specified by ARGS.  If FROM_TTY is non-zero,
    be chatty about it.  */
 
 static void
-inf_ptrace_attach (struct target_ops *ops, char *args, int from_tty)
+inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
 {
   char *exec_file;
   pid_t pid;
-  char *dummy;
   struct inferior *inf;
 
-  if (!args)
-    error_no_arg (_("process-id to attach"));
+  /* Do not change either targets above or the same target if already present.
+     The reason is the target stack is shared across multiple inferiors.  */
+  int ops_already_pushed = target_is_pushed (ops);
+  struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
 
-  dummy = args;
-  pid = strtol (args, &dummy, 0);
-  /* Some targets don't set errno on errors, grrr!  */
-  if (pid == 0 && args == dummy)
-    error (_("Illegal process-id: %s."), args);
+  pid = parse_pid_to_attach (args);
 
   if (pid == getpid ())                /* Trying to masturbate?  */
     error (_("I refuse to debug myself!"));
 
+  if (! ops_already_pushed)
+    {
+      /* target_pid_to_str already uses the target.  Also clear possible core
+        file with its process_stratum.  */
+      push_target (ops);
+      make_cleanup_unpush_target (ops);
+    }
+
   if (from_tty)
     {
       exec_file = get_exec_file (0);
@@ -244,22 +189,22 @@ inf_ptrace_attach (struct target_ops *ops, char *args, int from_tty)
   error (_("This system does not support attaching to a process"));
 #endif
 
-  inferior_ptid = pid_to_ptid (pid);
-
-  inf = add_inferior (pid);
+  inf = current_inferior ();
+  inferior_appeared (inf, pid);
   inf->attach_flag = 1;
+  inferior_ptid = pid_to_ptid (pid);
 
   /* Always add a main thread.  If some target extends the ptrace
      target, it should decorate the ptid later with more info.  */
   add_thread_silent (inferior_ptid);
 
-  push_target(ops);
+  discard_cleanups (back_to);
 }
 
 #ifdef PT_GET_PROCESS_STATE
 
-void
-inf_ptrace_post_attach (int pid)
+static void
+inf_ptrace_post_attach (struct target_ops *self, int pid)
 {
   ptrace_event_t pe;
 
@@ -277,7 +222,7 @@ inf_ptrace_post_attach (int pid)
    specified by ARGS.  If FROM_TTY is non-zero, be chatty about it.  */
 
 static void
-inf_ptrace_detach (struct target_ops *ops, char *args, int from_tty)
+inf_ptrace_detach (struct target_ops *ops, const char *args, int from_tty)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
   int sig = 0;
@@ -310,14 +255,13 @@ inf_ptrace_detach (struct target_ops *ops, char *args, int from_tty)
   inferior_ptid = null_ptid;
   detach_inferior (pid);
 
-  if (!have_inferiors ())
-    unpush_target (ops);
+  inf_child_maybe_unpush_target (ops);
 }
 
 /* Kill the inferior.  */
 
 static void
-inf_ptrace_kill (void)
+inf_ptrace_kill (struct target_ops *ops)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
   int status;
@@ -334,14 +278,14 @@ inf_ptrace_kill (void)
 /* Stop the inferior.  */
 
 static void
-inf_ptrace_stop (ptid_t ptid)
+inf_ptrace_stop (struct target_ops *self, ptid_t ptid)
 {
   /* Send a SIGINT to the process group.  This acts just like the user
      typed a ^C on the controlling terminal.  Note that using a
      negative process number in kill() is a System V-ism.  The proper
      BSD interface is killpg().  However, all modern BSDs support the
      System V interface too.  */
-  kill (-inferior_process_group, SIGINT);
+  kill (-inferior_process_group (), SIGINT);
 }
 
 /* Resume execution of thread PTID, or all threads if PTID is -1.  If
@@ -349,16 +293,22 @@ inf_ptrace_stop (ptid_t ptid)
    that signal.  */
 
 static void
-inf_ptrace_resume (ptid_t ptid, int step, enum target_signal signal)
+inf_ptrace_resume (struct target_ops *ops,
+                  ptid_t ptid, int step, enum gdb_signal signal)
 {
   pid_t pid = ptid_get_pid (ptid);
-  int request = PT_CONTINUE;
+  int request;
 
   if (pid == -1)
     /* Resume all threads.  Traditionally ptrace() only supports
        single-threaded processes, so simply resume the inferior.  */
     pid = ptid_get_pid (inferior_ptid);
 
+  if (catch_syscall_enabled () > 0)
+    request = PT_SYSCALL;
+  else
+    request = PT_CONTINUE;
+
   if (step)
     {
       /* If this system does not support PT_STEP, a higher level
@@ -373,7 +323,7 @@ inf_ptrace_resume (ptid_t ptid, int step, enum target_signal signal)
      where it was.  If GDB wanted it to start some other way, we have
      already written a new program counter value to the child.  */
   errno = 0;
-  ptrace (request, pid, (PTRACE_TYPE_ARG3)1, target_signal_to_host (signal));
+  ptrace (request, pid, (PTRACE_TYPE_ARG3)1, gdb_signal_to_host (signal));
   if (errno != 0)
     perror_with_name (("ptrace"));
 }
@@ -383,7 +333,8 @@ inf_ptrace_resume (ptid_t ptid, int step, enum target_signal signal)
    the status in *OURSTATUS.  */
 
 static ptid_t
-inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+inf_ptrace_wait (struct target_ops *ops,
+                ptid_t ptid, struct target_waitstatus *ourstatus, int options)
 {
   pid_t pid;
   int status, save_errno;
@@ -409,7 +360,7 @@ inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 
          /* Claim it exited with unknown signal.  */
          ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-         ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+         ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
          return inferior_ptid;
        }
 
@@ -461,15 +412,13 @@ inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   return pid_to_ptid (pid);
 }
 
-/* Attempt a transfer all LEN bytes starting at OFFSET between the
-   inferior's OBJECT:ANNEX space and GDB's READBUF/WRITEBUF buffer.
-   Return the number of bytes actually transferred.  */
+/* Implement the to_xfer_partial target_ops method.  */
 
-static LONGEST
+static enum target_xfer_status
 inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
                         const char *annex, gdb_byte *readbuf,
                         const gdb_byte *writebuf,
-                        ULONGEST offset, LONGEST len)
+                        ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
 
@@ -496,13 +445,16 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
 
        errno = 0;
        if (ptrace (PT_IO, pid, (caddr_t)&piod, 0) == 0)
-         /* Return the actual number of bytes read or written.  */
-         return piod.piod_len;
+         {
+           /* Return the actual number of bytes read or written.  */
+           *xfered_len = piod.piod_len;
+           return (piod.piod_len == 0) ? TARGET_XFER_EOF : TARGET_XFER_OK;
+         }
        /* If the PT_IO request is somehow not supported, fallback on
           using PT_WRITE_D/PT_READ_D.  Otherwise we will return zero
           to indicate failure.  */
        if (errno != EINVAL)
-         return 0;
+         return TARGET_XFER_EOF;
       }
 #endif
       {
@@ -512,7 +464,7 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
          gdb_byte byte[sizeof (PTRACE_TYPE_RET)];
        } buffer;
        ULONGEST rounded_offset;
-       LONGEST partial_len;
+       ULONGEST partial_len;
 
        /* Round the start offset down to the next long word
           boundary.  */
@@ -558,7 +510,7 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
                        (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
                        buffer.word);
                if (errno)
-                 return 0;
+                 return TARGET_XFER_EOF;
              }
          }
 
@@ -569,33 +521,57 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
                                  (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
                                  0);
            if (errno)
-             return 0;
+             return TARGET_XFER_EOF;
            /* Copy appropriate bytes out of the buffer.  */
            memcpy (readbuf, buffer.byte + (offset - rounded_offset),
                    partial_len);
          }
 
-       return partial_len;
+       *xfered_len = partial_len;
+       return TARGET_XFER_OK;
       }
 
     case TARGET_OBJECT_UNWIND_TABLE:
-      return -1;
+      return TARGET_XFER_E_IO;
 
     case TARGET_OBJECT_AUXV:
-      return -1;
+#if defined (PT_IO) && defined (PIOD_READ_AUXV)
+      /* OpenBSD 4.5 has a new PIOD_READ_AUXV operation for the PT_IO
+        request that allows us to read the auxilliary vector.  Other
+        BSD's may follow if they feel the need to support PIE.  */
+      {
+       struct ptrace_io_desc piod;
+
+       if (writebuf)
+         return TARGET_XFER_E_IO;
+       piod.piod_op = PIOD_READ_AUXV;
+       piod.piod_addr = readbuf;
+       piod.piod_offs = (void *) (long) offset;
+       piod.piod_len = len;
+
+       errno = 0;
+       if (ptrace (PT_IO, pid, (caddr_t)&piod, 0) == 0)
+         {
+           /* Return the actual number of bytes read or written.  */
+           *xfered_len = piod.piod_len;
+           return (piod.piod_len == 0) ? TARGET_XFER_EOF : TARGET_XFER_OK;
+         }
+      }
+#endif
+      return TARGET_XFER_E_IO;
 
     case TARGET_OBJECT_WCOOKIE:
-      return -1;
+      return TARGET_XFER_E_IO;
 
     default:
-      return -1;
+      return TARGET_XFER_E_IO;
     }
 }
 
 /* Return non-zero if the thread specified by PTID is alive.  */
 
 static int
-inf_ptrace_thread_alive (ptid_t ptid)
+inf_ptrace_thread_alive (struct target_ops *ops, ptid_t ptid)
 {
   /* ??? Is kill the right way to do this?  */
   return (kill (ptid_get_pid (ptid), 0) != -1);
@@ -613,6 +589,47 @@ inf_ptrace_files_info (struct target_ops *ignore)
                   target_pid_to_str (inferior_ptid));
 }
 
+static char *
+inf_ptrace_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+  return normal_pid_to_str (ptid);
+}
+
+#if defined (PT_IO) && defined (PIOD_READ_AUXV)
+
+/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
+   Return 0 if *READPTR is already at the end of the buffer.
+   Return -1 if there is insufficient buffer for a whole entry.
+   Return 1 if an entry was read into *TYPEP and *VALP.  */
+
+static int
+inf_ptrace_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
+                      gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
+{
+  struct type *int_type = builtin_type (target_gdbarch ())->builtin_int;
+  struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
+  const int sizeof_auxv_type = TYPE_LENGTH (int_type);
+  const int sizeof_auxv_val = TYPE_LENGTH (ptr_type);
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+  gdb_byte *ptr = *readptr;
+
+  if (endptr == ptr)
+    return 0;
+
+  if (endptr - ptr < 2 * sizeof_auxv_val)
+    return -1;
+
+  *typep = extract_unsigned_integer (ptr, sizeof_auxv_type, byte_order);
+  ptr += sizeof_auxv_val;      /* Alignment.  */
+  *valp = extract_unsigned_integer (ptr, sizeof_auxv_val, byte_order);
+  ptr += sizeof_auxv_val;
+
+  *readptr = ptr;
+  return 1;
+}
+
+#endif
+
 /* Create a prototype ptrace target.  The client can override it with
    local methods.  */
 
@@ -635,9 +652,12 @@ inf_ptrace_target (void)
 #endif
   t->to_mourn_inferior = inf_ptrace_mourn_inferior;
   t->to_thread_alive = inf_ptrace_thread_alive;
-  t->to_pid_to_str = normal_pid_to_str;
+  t->to_pid_to_str = inf_ptrace_pid_to_str;
   t->to_stop = inf_ptrace_stop;
   t->to_xfer_partial = inf_ptrace_xfer_partial;
+#if defined (PT_IO) && defined (PIOD_READ_AUXV)
+  t->to_auxv_parse = inf_ptrace_auxv_parse;
+#endif
 
   return t;
 }
@@ -696,7 +716,8 @@ inf_ptrace_fetch_register (struct regcache *regcache, int regnum)
    for all registers.  */
 
 static void
-inf_ptrace_fetch_registers (struct regcache *regcache, int regnum)
+inf_ptrace_fetch_registers (struct target_ops *ops,
+                           struct regcache *regcache, int regnum)
 {
   if (regnum == -1)
     for (regnum = 0;
@@ -752,8 +773,9 @@ inf_ptrace_store_register (const struct regcache *regcache, int regnum)
 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
    this for all registers.  */
 
-void
-inf_ptrace_store_registers (struct regcache *regcache, int regnum)
+static void
+inf_ptrace_store_registers (struct target_ops *ops,
+                           struct regcache *regcache, int regnum)
 {
   if (regnum == -1)
     for (regnum = 0;