2007-11-07 Markus Deuling <deuling@de.ibm.com>
[deliverable/binutils-gdb.git] / gdb / inf-ptrace.c
index 07ebb9d41205dc93ed5441e0d02338e6704beafc..af0b1b818835144e1a00b7ff1739d912ccbe2073 100644 (file)
@@ -1,14 +1,14 @@
 /* Low-level child interface to ptrace.
 
-   Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
-   1998, 1999, 2000, 2001, 2002, 2004, 2005
+   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+   1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "command.h"
 #include "inferior.h"
 #include "inflow.h"
 #include "gdbcore.h"
-#include "observer.h"
 #include "regcache.h"
 
+#include "gdb_stdint.h"
 #include "gdb_assert.h"
 #include "gdb_string.h"
 #include "gdb_ptrace.h"
@@ -138,12 +136,6 @@ inf_ptrace_create_inferior (char *exec_file, char *allargs, char **env,
 {
   fork_inferior (exec_file, allargs, env, inf_ptrace_me, inf_ptrace_him,
                 NULL, NULL);
-
-  /* We are at the first instruction we care about.  */
-  observer_notify_inferior_created (&current_target, from_tty);
-
-  /* Pedal to the metal...  */
-  proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
 }
 
 #ifdef PT_GET_PROCESS_STATE
@@ -171,9 +163,9 @@ inf_ptrace_mourn_inferior (void)
   int status;
 
   /* Wait just one more time to collect the inferior's exit status.
-     Don not check whether this succeeds though, since we may be
+     Do not check whether this succeeds though, since we may be
      dealing with a process that we attached to.  Such a process will
-     only report its exit status to its origional parent.  */
+     only report its exit status to its original parent.  */
   waitpid (ptid_get_pid (inferior_ptid), &status, 0);
 
   unpush_target (ptrace_ops_hack);
@@ -228,10 +220,6 @@ inf_ptrace_attach (char *args, int from_tty)
 
   inferior_ptid = pid_to_ptid (pid);
   push_target (ptrace_ops_hack);
-
-  /* Do this first, before anything has had a chance to query the
-     inferior's symbol table or similar.  */
-  observer_notify_inferior_created (&current_target, from_tty);
 }
 
 #ifdef PT_GET_PROCESS_STATE
@@ -252,7 +240,7 @@ inf_ptrace_post_attach (int pid)
 #endif
 
 /* Detach from the inferior, optionally passing it the signal
-   specified ARGS.  If FROM_TTY is non-zero, be chatty about it.  */
+   specified by ARGS.  If FROM_TTY is non-zero, be chatty about it.  */
 
 static void
 inf_ptrace_detach (char *args, int from_tty)
@@ -274,7 +262,7 @@ inf_ptrace_detach (char *args, int from_tty)
 
 #ifdef PT_DETACH
   /* We'd better not have left any breakpoints in the program or it'll
-     die when it hits one.  Alsno note that this may only work if we
+     die when it hits one.  Also note that this may only work if we
      previously attached to the inferior.  It *might* work if we
      started the process ourselves.  */
   errno = 0;
@@ -462,8 +450,12 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
        struct ptrace_io_desc piod;
 
        /* NOTE: We assume that there are no distinct address spaces
-          for instruction and data.  */
-       piod.piod_op = writebuf ? PIOD_WRITE_D : PIOD_READ_D;
+          for instruction and data.  However, on OpenBSD 3.9 and
+          later, PIOD_WRITE_D doesn't allow changing memory that's
+          mapped read-only.  Since most code segments will be
+          read-only, using PIOD_WRITE_D will prevent us from
+          inserting breakpoints, so we use PIOD_WRITE_I instead.  */
+       piod.piod_op = writebuf ? PIOD_WRITE_I : PIOD_READ_D;
        piod.piod_addr = writebuf ? (void *) writebuf : readbuf;
        piod.piod_offs = (void *) (long) offset;
        piod.piod_len = len;
@@ -511,7 +503,8 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
                    < rounded_offset + sizeof (PTRACE_TYPE_RET)))
              /* Need part of initial word -- fetch it.  */
              buffer.word = ptrace (PT_READ_I, pid,
-                                   (PTRACE_TYPE_ARG3)(long)rounded_offset, 0);
+                                   (PTRACE_TYPE_ARG3)(uintptr_t)
+                                   rounded_offset, 0);
 
            /* Copy data to be written over corresponding part of
               buffer.  */
@@ -520,14 +513,16 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
 
            errno = 0;
            ptrace (PT_WRITE_D, pid,
-                   (PTRACE_TYPE_ARG3)(long)rounded_offset, buffer.word);
+                   (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+                   buffer.word);
            if (errno)
              {
                /* Using the appropriate one (I or D) is necessary for
                   Gould NP1, at least.  */
                errno = 0;
                ptrace (PT_WRITE_I, pid,
-                       (PTRACE_TYPE_ARG3)(long)rounded_offset, buffer.word);
+                       (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+                       buffer.word);
                if (errno)
                  return 0;
              }
@@ -537,7 +532,8 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
          {
            errno = 0;
            buffer.word = ptrace (PT_READ_I, pid,
-                                 (PTRACE_TYPE_ARG3)(long)rounded_offset, 0);
+                                 (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+                                 0);
            if (errno)
              return 0;
            /* Copy appropriate bytes out of the buffer.  */
@@ -614,90 +610,105 @@ inf_ptrace_target (void)
 
 /* Pointer to a function that returns the offset within the user area
    where a particular register is stored.  */
-static CORE_ADDR (*inf_ptrace_register_u_offset)(int);
+static CORE_ADDR (*inf_ptrace_register_u_offset)(struct gdbarch *, int, int);
 
 /* Fetch register REGNUM from the inferior.  */
 
 static void
-inf_ptrace_fetch_register (int regnum)
+inf_ptrace_fetch_register (struct regcache *regcache, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   CORE_ADDR addr;
   size_t size;
   PTRACE_TYPE_RET *buf;
   int pid, i;
 
+  /* This isn't really an address, but ptrace thinks of it as one.  */
+  addr = inf_ptrace_register_u_offset (gdbarch, regnum, 0);
+  if (addr == (CORE_ADDR)-1
+      || gdbarch_cannot_fetch_register (gdbarch, regnum))
+    {
+      regcache_raw_supply (regcache, regnum, NULL);
+      return;
+    }
+
   /* Cater for systems like GNU/Linux, that implement threads as
-     seperate processes.  */
+     separate processes.  */
   pid = ptid_get_lwp (inferior_ptid);
   if (pid == 0)
     pid = ptid_get_pid (inferior_ptid);
 
-  /* This isn't really an address, but ptrace thinks of it as one.  */
-  addr = inf_ptrace_register_u_offset (regnum);
-  size = register_size (current_gdbarch, regnum);
-
+  size = register_size (gdbarch, regnum);
   gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
   buf = alloca (size);
 
-  /* Read the register contents from the inferior a chuck at the time.  */
+  /* Read the register contents from the inferior a chunk at a time.  */
   for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
     {
       errno = 0;
-      buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)addr, 0);
+      buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)(uintptr_t)addr, 0);
       if (errno != 0)
        error (_("Couldn't read register %s (#%d): %s."),
-              REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+              gdbarch_register_name (gdbarch, regnum),
+              regnum, safe_strerror (errno));
 
       addr += sizeof (PTRACE_TYPE_RET);
     }
-  regcache_raw_supply (current_regcache, regnum, buf);
+  regcache_raw_supply (regcache, regnum, buf);
 }
 
 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
    for all registers.  */
 
 static void
-inf_ptrace_fetch_registers (int regnum)
+inf_ptrace_fetch_registers (struct regcache *regcache, int regnum)
 {
   if (regnum == -1)
-    for (regnum = 0; regnum < NUM_REGS; regnum++)
-      inf_ptrace_fetch_register (regnum);
+    for (regnum = 0;
+        regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+        regnum++)
+      inf_ptrace_fetch_register (regcache, regnum);
   else
-    inf_ptrace_fetch_register (regnum);
+    inf_ptrace_fetch_register (regcache, regnum);
 }
 
 /* Store register REGNUM into the inferior.  */
 
 static void
-inf_ptrace_store_register (int regnum)
+inf_ptrace_store_register (const struct regcache *regcache, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   CORE_ADDR addr;
   size_t size;
   PTRACE_TYPE_RET *buf;
   int pid, i;
 
+  /* This isn't really an address, but ptrace thinks of it as one.  */
+  addr = inf_ptrace_register_u_offset (gdbarch, regnum, 1);
+  if (addr == (CORE_ADDR)-1 
+      || gdbarch_cannot_store_register (gdbarch, regnum))
+    return;
+
   /* Cater for systems like GNU/Linux, that implement threads as
-     seperate processes.  */
+     separate processes.  */
   pid = ptid_get_lwp (inferior_ptid);
   if (pid == 0)
     pid = ptid_get_pid (inferior_ptid);
 
-  /* This isn't really an address, but ptrace thinks of it as one.  */
-  addr = inf_ptrace_register_u_offset (regnum);
-  size = register_size (current_gdbarch, regnum);
-
+  size = register_size (gdbarch, regnum);
   gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
   buf = alloca (size);
 
-  /* Write the register contents into the inferior a chunk at the time.  */
-  regcache_raw_collect (current_regcache, regnum, buf);
+  /* Write the register contents into the inferior a chunk at a time.  */
+  regcache_raw_collect (regcache, regnum, buf);
   for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
     {
       errno = 0;
-      ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)addr, buf[i]);
+      ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)(uintptr_t)addr, buf[i]);
       if (errno != 0)
        error (_("Couldn't write register %s (#%d): %s."),
-              REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+              gdbarch_register_name (gdbarch, regnum),
+              regnum, safe_strerror (errno));
 
       addr += sizeof (PTRACE_TYPE_RET);
     }
@@ -707,13 +718,15 @@ inf_ptrace_store_register (int regnum)
    this for all registers.  */
 
 void
-inf_ptrace_store_registers (int regnum)
+inf_ptrace_store_registers (struct regcache *regcache, int regnum)
 {
   if (regnum == -1)
-    for (regnum = 0; regnum < NUM_REGS; regnum++)
-      inf_ptrace_store_register (regnum);
+    for (regnum = 0;
+        regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+        regnum++)
+      inf_ptrace_store_register (regcache, regnum);
   else
-    inf_ptrace_store_register (regnum);
+    inf_ptrace_store_register (regcache, regnum);
 }
 
 /* Create a "traditional" ptrace target.  REGISTER_U_OFFSET should be
@@ -721,7 +734,8 @@ inf_ptrace_store_registers (int regnum)
    particular register is stored.  */
 
 struct target_ops *
-inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)(int))
+inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)
+                                       (struct gdbarch *, int, int))
 {
   struct target_ops *t = inf_ptrace_target();
 
This page took 0.028241 seconds and 4 git commands to generate.