gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / rs6000-nat.c
index 1b600f0fb5e0d957b3aa7cd3d2a98e0dfa0b899c..654e06e3e4bf319206787f86685817b173e7fcfe 100644 (file)
@@ -1,6 +1,6 @@
 /* IBM RS/6000 native-dependent code for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2013 Free Software Foundation, Inc.
+   Copyright (C) 1986-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -23,9 +23,7 @@
 #include "gdbcore.h"
 #include "symfile.h"
 #include "objfiles.h"
-#include "libbfd.h"            /* For bfd_default_set_arch_mach (FIXME) */
 #include "bfd.h"
-#include "exceptions.h"
 #include "gdb-stabs.h"
 #include "regcache.h"
 #include "arch-utils.h"
 #include "rs6000-tdep.h"
 #include "rs6000-aix-tdep.h"
 #include "exec.h"
-#include "observer.h"
+#include "observable.h"
 #include "xcoffread.h"
 
 #include <sys/ptrace.h>
 #include <sys/reg.h>
 
-#include <sys/param.h>
 #include <sys/dir.h>
 #include <sys/user.h>
 #include <signal.h>
 #include <sys/ioctl.h>
 #include <fcntl.h>
-#include <errno.h>
 
 #include <a.out.h>
 #include <sys/file.h>
-#include "gdb_stat.h"
+#include <sys/stat.h>
 #include "gdb_bfd.h"
 #include <sys/core.h>
 #define __LDINFO_PTRACE32__    /* for __ld_info32 */
@@ -66,7 +62,7 @@
 /* In 32-bit compilation mode (which is the only mode from which ptrace()
    works on 4.3), __ld_info32 is #defined as equivalent to ld_info.  */
 
-#ifdef __ld_info32
+#if defined (__ld_info32) || defined (__ld_info64)
 # define ARCH3264
 #endif
 
 # define ARCH64() (register_size (target_gdbarch (), 0) == 8)
 #endif
 
-static void exec_one_dummy_insn (struct regcache *);
+class rs6000_nat_target final : public inf_ptrace_target
+{
+public:
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
 
-static LONGEST rs6000_xfer_shared_libraries
-  (struct target_ops *ops, enum target_object object,
-   const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf,
-   ULONGEST offset, LONGEST len);
+  enum target_xfer_status xfer_partial (enum target_object object,
+                                       const char *annex,
+                                       gdb_byte *readbuf,
+                                       const gdb_byte *writebuf,
+                                       ULONGEST offset, ULONGEST len,
+                                       ULONGEST *xfered_len) override;
+
+  void create_inferior (const char *, const std::string &,
+                       char **, int) override;
+
+  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+
+private:
+  enum target_xfer_status
+    xfer_shared_libraries (enum target_object object,
+                          const char *annex, gdb_byte *readbuf,
+                          const gdb_byte *writebuf,
+                          ULONGEST offset, ULONGEST len,
+                          ULONGEST *xfered_len);
+};
+
+static rs6000_nat_target the_rs6000_nat_target;
 
 /* Given REGNO, a gdb register number, return the corresponding
    number suitable for use as a ptrace() parameter.  Return -1 if
@@ -132,7 +150,11 @@ regmap (struct gdbarch *gdbarch, int regno, int *isfloat)
 static int
 rs6000_ptrace32 (int req, int id, int *addr, int data, int *buf)
 {
+#ifdef HAVE_PTRACE64
+  int ret = ptrace64 (req, id, (uintptr_t) addr, data, buf);
+#else
   int ret = ptrace (req, id, (int *)addr, data, buf);
+#endif
 #if 0
   printf ("rs6000_ptrace32 (%d, %d, 0x%x, %08x, 0x%x) = 0x%x\n",
          req, id, (unsigned int)addr, data, (unsigned int)buf, ret);
@@ -146,7 +168,11 @@ static int
 rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
 {
 #ifdef ARCH3264
-  int ret = ptracex (req, id, addr, data, buf);
+#  ifdef HAVE_PTRACE64
+  int ret = ptrace64 (req, id, addr, data, (PTRACE_TYPE_ARG5) buf);
+#  else
+  int ret = ptracex (req, id, addr, data, (PTRACE_TYPE_ARG5) buf);
+#  endif
 #else
   int ret = 0;
 #endif
@@ -162,9 +188,10 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
 static void
 fetch_register (struct regcache *regcache, int regno)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  int addr[MAX_REGISTER_SIZE];
+  struct gdbarch *gdbarch = regcache->arch ();
+  int addr[PPC_MAX_REGISTER_SIZE];
   int nr, isfloat;
+  pid_t pid = regcache->ptid ().pid ();
 
   /* Retrieved values may be -1, so infer errors from errno.  */
   errno = 0;
@@ -173,7 +200,7 @@ fetch_register (struct regcache *regcache, int regno)
 
   /* Floating-point registers.  */
   if (isfloat)
-    rs6000_ptrace32 (PT_READ_FPR, PIDGET (inferior_ptid), addr, nr, 0);
+    rs6000_ptrace32 (PT_READ_FPR, pid, addr, nr, 0);
 
   /* Bogus register number.  */
   else if (nr < 0)
@@ -189,14 +216,13 @@ fetch_register (struct regcache *regcache, int regno)
   else
     {
       if (!ARCH64 ())
-       *addr = rs6000_ptrace32 (PT_READ_GPR, PIDGET (inferior_ptid),
-                                (int *) nr, 0, 0);
+       *addr = rs6000_ptrace32 (PT_READ_GPR, pid, (int *) nr, 0, 0);
       else
        {
          /* PT_READ_GPR requires the buffer parameter to point to long long,
             even if the register is really only 32 bits.  */
          long long buf;
-         rs6000_ptrace64 (PT_READ_GPR, PIDGET (inferior_ptid), nr, 0, &buf);
+         rs6000_ptrace64 (PT_READ_GPR, pid, nr, 0, &buf);
          if (register_size (gdbarch, regno) == 8)
            memcpy (addr, &buf, 8);
          else
@@ -205,7 +231,7 @@ fetch_register (struct regcache *regcache, int regno)
     }
 
   if (!errno)
-    regcache_raw_supply (regcache, regno, (char *) addr);
+    regcache->raw_supply (regno, (char *) addr);
   else
     {
 #if 0
@@ -221,12 +247,13 @@ fetch_register (struct regcache *regcache, int regno)
 static void
 store_register (struct regcache *regcache, int regno)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  int addr[MAX_REGISTER_SIZE];
+  struct gdbarch *gdbarch = regcache->arch ();
+  int addr[PPC_MAX_REGISTER_SIZE];
   int nr, isfloat;
+  pid_t pid = regcache->ptid ().pid ();
 
   /* Fetch the register's value from the register cache.  */
-  regcache_raw_collect (regcache, regno, addr);
+  regcache->raw_collect (regno, addr);
 
   /* -1 can be a successful return value, so infer errors from errno.  */
   errno = 0;
@@ -235,7 +262,7 @@ store_register (struct regcache *regcache, int regno)
 
   /* Floating-point registers.  */
   if (isfloat)
-    rs6000_ptrace32 (PT_WRITE_FPR, PIDGET (inferior_ptid), addr, nr, 0);
+    rs6000_ptrace32 (PT_WRITE_FPR, pid, addr, nr, 0);
 
   /* Bogus register number.  */
   else if (nr < 0)
@@ -249,20 +276,11 @@ store_register (struct regcache *regcache, int regno)
   /* Fixed-point registers.  */
   else
     {
-      if (regno == gdbarch_sp_regnum (gdbarch))
-       /* Execute one dummy instruction (which is a breakpoint) in inferior
-          process to give kernel a chance to do internal housekeeping.
-          Otherwise the following ptrace(2) calls will mess up user stack
-          since kernel will get confused about the bottom of the stack
-          (%sp).  */
-       exec_one_dummy_insn (regcache);
-
       /* The PT_WRITE_GPR operation is rather odd.  For 32-bit inferiors,
          the register's value is passed by value, but for 64-bit inferiors,
         the address of a buffer containing the value is passed.  */
       if (!ARCH64 ())
-       rs6000_ptrace32 (PT_WRITE_GPR, PIDGET (inferior_ptid),
-                        (int *) nr, *addr, 0);
+       rs6000_ptrace32 (PT_WRITE_GPR, pid, (int *) nr, *addr, 0);
       else
        {
          /* PT_WRITE_GPR requires the buffer parameter to point to an 8-byte
@@ -272,7 +290,7 @@ store_register (struct regcache *regcache, int regno)
            memcpy (&buf, addr, 8);
          else
            buf = *addr;
-         rs6000_ptrace64 (PT_WRITE_GPR, PIDGET (inferior_ptid), nr, 0, &buf);
+         rs6000_ptrace64 (PT_WRITE_GPR, pid, nr, 0, &buf);
        }
     }
 
@@ -286,11 +304,10 @@ store_register (struct regcache *regcache, int regno)
 /* Read from the inferior all registers if REGNO == -1 and just register
    REGNO otherwise.  */
 
-static void
-rs6000_fetch_inferior_registers (struct target_ops *ops,
-                                struct regcache *regcache, int regno)
+void
+rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
   if (regno != -1)
     fetch_register (regcache, regno);
 
@@ -329,11 +346,10 @@ rs6000_fetch_inferior_registers (struct target_ops *ops,
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
 
-static void
-rs6000_store_inferior_registers (struct target_ops *ops,
-                                struct regcache *regcache, int regno)
+void
+rs6000_nat_target::store_registers (struct regcache *regcache, int regno)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
   if (regno != -1)
     store_register (regcache, regno);
 
@@ -368,26 +384,24 @@ rs6000_store_inferior_registers (struct target_ops *ops,
     }
 }
 
+/* Implement the to_xfer_partial target_ops method.  */
 
-/* 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.  */
-
-static LONGEST
-rs6000_xfer_partial (struct target_ops *ops, enum target_object object,
-                    const char *annex, gdb_byte *readbuf,
-                    const gdb_byte *writebuf,
-                    ULONGEST offset, LONGEST len)
+enum target_xfer_status
+rs6000_nat_target::xfer_partial (enum target_object object,
+                                const char *annex, gdb_byte *readbuf,
+                                const gdb_byte *writebuf,
+                                ULONGEST offset, ULONGEST len,
+                                ULONGEST *xfered_len)
 {
-  pid_t pid = ptid_get_pid (inferior_ptid);
+  pid_t pid = inferior_ptid.pid ();
   int arch64 = ARCH64 ();
 
   switch (object)
     {
     case TARGET_OBJECT_LIBRARIES_AIX:
-      return rs6000_xfer_shared_libraries (ops, object, annex,
-                                          readbuf, writebuf,
-                                          offset, len);
+      return xfer_shared_libraries (object, annex,
+                                   readbuf, writebuf,
+                                   offset, len, xfered_len);
     case TARGET_OBJECT_MEMORY:
       {
        union
@@ -445,7 +459,7 @@ rs6000_xfer_partial (struct target_ops *ops, enum target_object object,
                               (int *) (uintptr_t) rounded_offset,
                               buffer.word, NULL);
            if (errno)
-             return 0;
+             return TARGET_XFER_EOF;
          }
 
        if (readbuf)
@@ -459,18 +473,19 @@ rs6000_xfer_partial (struct target_ops *ops, enum target_object object,
                                             (int *)(uintptr_t)rounded_offset,
                                             0, NULL);
            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 = (ULONGEST) partial_len;
+       return TARGET_XFER_OK;
       }
 
     default:
-      return -1;
+      return TARGET_XFER_E_IO;
     }
 }
 
@@ -478,9 +493,9 @@ rs6000_xfer_partial (struct target_ops *ops, enum target_object object,
    process ID of the child, or MINUS_ONE_PTID in case of error; store
    the status in *OURSTATUS.  */
 
-static ptid_t
-rs6000_wait (struct target_ops *ops,
-            ptid_t ptid, struct target_waitstatus *ourstatus, int options)
+ptid_t
+rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+                        int options)
 {
   pid_t pid;
   int status, save_errno;
@@ -491,7 +506,7 @@ rs6000_wait (struct target_ops *ops,
 
       do
        {
-         pid = waitpid (ptid_get_pid (ptid), &status, 0);
+         pid = waitpid (ptid.pid (), &status, 0);
          save_errno = errno;
        }
       while (pid == -1 && errno == EINTR);
@@ -511,7 +526,7 @@ rs6000_wait (struct target_ops *ops,
        }
 
       /* Ignore terminated detached child processes.  */
-      if (!WIFSTOPPED (status) && pid != ptid_get_pid (inferior_ptid))
+      if (!WIFSTOPPED (status) && pid != inferior_ptid.pid ())
        pid = -1;
     }
   while (pid == -1);
@@ -528,71 +543,24 @@ rs6000_wait (struct target_ops *ops,
   else
     store_waitstatus (ourstatus, status);
 
-  return pid_to_ptid (pid);
-}
-
-/* Execute one dummy breakpoint instruction.  This way we give the kernel
-   a chance to do some housekeeping and update inferior's internal data,
-   including u_area.  */
-
-static void
-exec_one_dummy_insn (struct regcache *regcache)
-{
-#define        DUMMY_INSN_ADDR AIX_TEXT_SEGMENT_BASE+0x200
-
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  int ret, status, pid;
-  CORE_ADDR prev_pc;
-  void *bp;
-
-  /* We plant one dummy breakpoint into DUMMY_INSN_ADDR address.  We
-     assume that this address will never be executed again by the real
-     code.  */
-
-  bp = deprecated_insert_raw_breakpoint (gdbarch, NULL, DUMMY_INSN_ADDR);
-
-  /* You might think this could be done with a single ptrace call, and
-     you'd be correct for just about every platform I've ever worked
-     on.  However, rs6000-ibm-aix4.1.3 seems to have screwed this up --
-     the inferior never hits the breakpoint (it's also worth noting
-     powerpc-ibm-aix4.1.3 works correctly).  */
-  prev_pc = regcache_read_pc (regcache);
-  regcache_write_pc (regcache, DUMMY_INSN_ADDR);
-  if (ARCH64 ())
-    ret = rs6000_ptrace64 (PT_CONTINUE, PIDGET (inferior_ptid), 1, 0, NULL);
-  else
-    ret = rs6000_ptrace32 (PT_CONTINUE, PIDGET (inferior_ptid),
-                          (int *) 1, 0, NULL);
-
-  if (ret != 0)
-    perror (_("pt_continue"));
-
-  do
-    {
-      pid = waitpid (PIDGET (inferior_ptid), &status, 0);
-    }
-  while (pid != PIDGET (inferior_ptid));
-
-  regcache_write_pc (regcache, prev_pc);
-  deprecated_remove_raw_breakpoint (gdbarch, bp);
+  return ptid_t (pid);
 }
 \f
 
 /* Set the current architecture from the host running GDB.  Called when
    starting a child process.  */
 
-static void (*super_create_inferior) (struct target_ops *,char *exec_file, 
-                                     char *allargs, char **env, int from_tty);
-static void
-rs6000_create_inferior (struct target_ops * ops, char *exec_file,
-                       char *allargs, char **env, int from_tty)
+void
+rs6000_nat_target::create_inferior (const char *exec_file,
+                                   const std::string &allargs,
+                                   char **env, int from_tty)
 {
   enum bfd_architecture arch;
   unsigned long mach;
   bfd abfd;
   struct gdbarch_info info;
 
-  super_create_inferior (ops, exec_file, allargs, env, from_tty);
+  inf_ptrace_target::create_inferior (exec_file, allargs, env, from_tty);
 
   if (__power_rs ())
     {
@@ -638,25 +606,23 @@ rs6000_create_inferior (struct target_ops * ops, char *exec_file,
 /* Shared Object support.  */
 
 /* Return the LdInfo data for the given process.  Raises an error
-   if the data could not be obtained.
-
-   The returned value must be deallocated after use.  */
+   if the data could not be obtained.  */
 
-static gdb_byte *
+static gdb::byte_vector
 rs6000_ptrace_ldinfo (ptid_t ptid)
 {
-  const int pid = ptid_get_pid (ptid);
-  int ldi_size = 1024;
-  gdb_byte *ldi = xmalloc (ldi_size);
+  const int pid = ptid.pid ();
+  gdb::byte_vector ldi (1024);
   int rc = -1;
 
   while (1)
     {
       if (ARCH64 ())
-       rc = rs6000_ptrace64 (PT_LDINFO, pid, (unsigned long) ldi, ldi_size,
-                             NULL);
+       rc = rs6000_ptrace64 (PT_LDINFO, pid, (unsigned long) ldi.data (),
+                             ldi.size (), NULL);
       else
-       rc = rs6000_ptrace32 (PT_LDINFO, pid, (int *) ldi, ldi_size, NULL);
+       rc = rs6000_ptrace32 (PT_LDINFO, pid, (int *) ldi.data (),
+                             ldi.size (), NULL);
 
       if (rc != -1)
        break; /* Success, we got the entire ld_info data.  */
@@ -665,8 +631,7 @@ rs6000_ptrace_ldinfo (ptid_t ptid)
        perror_with_name (_("ptrace ldinfo"));
 
       /* ldi is not big enough.  Double it and try again.  */
-      ldi_size *= 2;
-      ldi = xrealloc (ldi, ldi_size);
+      ldi.resize (ldi.size () * 2);
     }
 
   return ldi;
@@ -675,50 +640,37 @@ rs6000_ptrace_ldinfo (ptid_t ptid)
 /* Implement the to_xfer_partial target_ops method for
    TARGET_OBJECT_LIBRARIES_AIX objects.  */
 
-static LONGEST
-rs6000_xfer_shared_libraries
-  (struct target_ops *ops, enum target_object object,
+enum target_xfer_status
+rs6000_nat_target::xfer_shared_libraries
+  (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)
 {
-  gdb_byte *ldi_buf;
   ULONGEST result;
-  struct cleanup *cleanup;
 
   /* This function assumes that it is being run with a live process.
      Core files are handled via gdbarch.  */
   gdb_assert (target_has_execution);
 
   if (writebuf)
-    return -1;
+    return TARGET_XFER_E_IO;
 
-  ldi_buf = rs6000_ptrace_ldinfo (inferior_ptid);
-  gdb_assert (ldi_buf != NULL);
-  cleanup = make_cleanup (xfree, ldi_buf);
-  result = rs6000_aix_ld_info_to_xml (target_gdbarch (), ldi_buf,
+  gdb::byte_vector ldi_buf = rs6000_ptrace_ldinfo (inferior_ptid);
+  result = rs6000_aix_ld_info_to_xml (target_gdbarch (), ldi_buf.data (),
                                      readbuf, offset, len, 1);
-  xfree (ldi_buf);
 
-  do_cleanups (cleanup);
-  return result;
+  if (result == 0)
+    return TARGET_XFER_EOF;
+  else
+    {
+      *xfered_len = result;
+      return TARGET_XFER_OK;
+    }
 }
 
-void _initialize_rs6000_nat (void);
-
+void _initialize_rs6000_nat ();
 void
-_initialize_rs6000_nat (void)
+_initialize_rs6000_nat ()
 {
-  struct target_ops *t;
-
-  t = inf_ptrace_target ();
-  t->to_fetch_registers = rs6000_fetch_inferior_registers;
-  t->to_store_registers = rs6000_store_inferior_registers;
-  t->to_xfer_partial = rs6000_xfer_partial;
-
-  super_create_inferior = t->to_create_inferior;
-  t->to_create_inferior = rs6000_create_inferior;
-
-  t->to_wait = rs6000_wait;
-
-  add_target (t);
+  add_inf_child_target (&the_rs6000_nat_target);
 }
This page took 0.033033 seconds and 4 git commands to generate.