Generalize gdb.reverse/aarch64.exp
[deliverable/binutils-gdb.git] / gdb / rs6000-nat.c
index a16ccf267cc88783157d347099cad473aa539316..ca333f216d8e8167b18e1c2462ff6c6deebb0afd 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-2016 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -25,7 +25,6 @@
 #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"
@@ -33,6 +32,7 @@
 #include "inf-ptrace.h"
 #include "ppc-tdep.h"
 #include "rs6000-tdep.h"
+#include "rs6000-aix-tdep.h"
 #include "exec.h"
 #include "observer.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 */
 #define __LDINFO_PTRACE64__    /* for __ld_info64 */
 #include <sys/ldr.h>
 #include <sys/systemcfg.h>
-#include "xml-utils.h"
 
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
@@ -66,7 +63,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
 
-/* Union of 32-bit and 64-bit versions of ld_info.  */
-
-typedef union {
-#ifndef ARCH3264
-  struct ld_info l32;
-  struct ld_info l64;
-#else
-  struct __ld_info32 l32;
-  struct __ld_info64 l64;
-#endif
-} LdInfo;
-
-/* If compiling with 32-bit and 64-bit debugging capability (e.g. AIX 4.x),
-   declare and initialize a variable named VAR suitable for use as the arch64
-   parameter to the various LDI_*() macros.  */
-
-#ifndef ARCH3264
-# define ARCH64_DECL(var)
-#else
-# define ARCH64_DECL(var) int var = ARCH64 ()
-#endif
-
-/* Return LDI's FIELD for a 64-bit process if ARCH64 and for a 32-bit process
-   otherwise.  This technique only works for FIELDs with the same data type in
-   32-bit and 64-bit versions of ld_info.  */
-
-#ifndef ARCH3264
-# define LDI_FIELD(ldi, arch64, field) (ldi)->l32.ldinfo_##field
-#else
-# define LDI_FIELD(ldi, arch64, field) \
-  (arch64 ? (ldi)->l64.ldinfo_##field : (ldi)->l32.ldinfo_##field)
-#endif
-
-/* Return various LDI fields for a 64-bit process if ARCH64 and for a 32-bit
-   process otherwise.  */
-
-#define LDI_NEXT(ldi, arch64)          LDI_FIELD(ldi, arch64, next)
-#define LDI_FD(ldi, arch64)            LDI_FIELD(ldi, arch64, fd)
-#define LDI_FILENAME(ldi, arch64)      LDI_FIELD(ldi, arch64, filename)
-
-static void exec_one_dummy_insn (struct regcache *);
-
-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);
+static target_xfer_partial_ftype rs6000_xfer_shared_libraries;
 
 /* Given REGNO, a gdb register number, return the corresponding
    number suitable for use as a ptrace() parameter.  Return -1 if
@@ -172,7 +124,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);
@@ -186,7 +142,11 @@ static int
 rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
 {
 #ifdef ARCH3264
+#  ifdef HAVE_PTRACE64
+  int ret = ptrace64 (req, id, addr, data, buf);
+#  else
   int ret = ptracex (req, id, addr, data, buf);
+#  endif
 #else
   int ret = 0;
 #endif
@@ -213,7 +173,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, ptid_get_pid (inferior_ptid), addr, nr, 0);
 
   /* Bogus register number.  */
   else if (nr < 0)
@@ -229,14 +189,15 @@ fetch_register (struct regcache *regcache, int regno)
   else
     {
       if (!ARCH64 ())
-       *addr = rs6000_ptrace32 (PT_READ_GPR, PIDGET (inferior_ptid),
+       *addr = rs6000_ptrace32 (PT_READ_GPR, ptid_get_pid (inferior_ptid),
                                 (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, ptid_get_pid (inferior_ptid),
+                          nr, 0, &buf);
          if (register_size (gdbarch, regno) == 8)
            memcpy (addr, &buf, 8);
          else
@@ -275,7 +236,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, ptid_get_pid (inferior_ptid), addr, nr, 0);
 
   /* Bogus register number.  */
   else if (nr < 0)
@@ -289,19 +250,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),
+       rs6000_ptrace32 (PT_WRITE_GPR, ptid_get_pid (inferior_ptid),
                         (int *) nr, *addr, 0);
       else
        {
@@ -312,7 +265,8 @@ 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, ptid_get_pid (inferior_ptid),
+                          nr, 0, &buf);
        }
     }
 
@@ -408,26 +362,23 @@ 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
+static enum target_xfer_status
 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)
+                    ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
   int arch64 = ARCH64 ();
 
   switch (object)
     {
-    case TARGET_OBJECT_AIX_LIBRARIES:
+    case TARGET_OBJECT_LIBRARIES_AIX:
       return rs6000_xfer_shared_libraries (ops, object, annex,
                                           readbuf, writebuf,
-                                          offset, len);
+                                          offset, len, xfered_len);
     case TARGET_OBJECT_MEMORY:
       {
        union
@@ -485,7 +436,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)
@@ -499,18 +450,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;
     }
 }
 
@@ -570,52 +522,6 @@ rs6000_wait (struct target_ops *ops,
 
   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);
-}
 \f
 
 /* Set the current architecture from the host running GDB.  Called when
@@ -682,12 +588,12 @@ rs6000_create_inferior (struct target_ops * ops, char *exec_file,
 
    The returned value must be deallocated after use.  */
 
-static LdInfo *
+static gdb_byte *
 rs6000_ptrace_ldinfo (ptid_t ptid)
 {
   const int pid = ptid_get_pid (ptid);
   int ldi_size = 1024;
-  LdInfo *ldi = xmalloc (ldi_size);
+  gdb_byte *ldi = xmalloc (ldi_size);
   int rc = -1;
 
   while (1)
@@ -712,169 +618,42 @@ rs6000_ptrace_ldinfo (ptid_t ptid)
   return ldi;
 }
 
-/* Assuming ABFD refers to a core file, return the LdInfo data
-   stored in that core file.  Raises an error if the data could
-   not be read or extracted.
-
-   The returned value much be deallocated after use.  */
-
-static LdInfo *
-rs6000_core_ldinfo (bfd *abfd)
-{
-  struct bfd_section *ldinfo_sec;
-  int ldinfo_size;
-  gdb_byte *ldinfo_buf;
-  struct cleanup *cleanup;
-
-  ldinfo_sec = bfd_get_section_by_name (abfd, ".ldinfo");
-  if (ldinfo_sec == NULL)
-    error (_("cannot find .ldinfo section from core file: %s\n"),
-          bfd_errmsg (bfd_get_error ()));
-  ldinfo_size = bfd_get_section_size (ldinfo_sec);
-
-  ldinfo_buf = xmalloc (ldinfo_size);
-  cleanup = make_cleanup (xfree, ldinfo_buf);
-
-  if (! bfd_get_section_contents (abfd, ldinfo_sec,
-                                 ldinfo_buf, 0, ldinfo_size))
-    error (_("unable to read .ldinfo section from core file: %s\n"),
-          bfd_errmsg (bfd_get_error ()));
-
-  discard_cleanups (cleanup);
-  return (LdInfo *) ldinfo_buf;
-}
-
-/* Append to OBJSTACK an XML string description of the shared library
-   corresponding to LDI, following the TARGET_OBJECT_AIX_LIBRARIES
-   format.  */
-
-static void
-rs6000_xfer_shared_library (LdInfo *ldi, struct obstack *obstack)
-{
-  const int arch64 = ARCH64 ();
-  const char *archive_name = LDI_FILENAME (ldi, arch64);
-  const char *member_name = archive_name + strlen (archive_name) + 1;
-  CORE_ADDR text_addr, data_addr;
-  ULONGEST text_size, data_size;
-  char *p;
-
-  if (arch64)
-    {
-      text_addr = ldi->l64.ldinfo_textorg;
-      text_size = ldi->l64.ldinfo_textsize;
-      data_addr = ldi->l64.ldinfo_dataorg;
-      data_size = ldi->l64.ldinfo_datasize;
-    }
-  else
-    {
-      /* The text and data addresses are defined as pointers.
-        To avoid sign-extending their value in the assignments
-        below, we cast their value to unsigned long first.  */
-      text_addr = (unsigned long) ldi->l32.ldinfo_textorg;
-      text_size = ldi->l32.ldinfo_textsize;
-      data_addr = (unsigned long) ldi->l32.ldinfo_dataorg;
-      data_size = ldi->l32.ldinfo_datasize;
-    }
-
-  obstack_grow_str (obstack, "<library name=\"");
-  p = xml_escape_text (archive_name);
-  obstack_grow_str (obstack, p);
-  xfree (p);
-  obstack_grow_str (obstack, "\"");
-
-  if (member_name[0] != '\0')
-    {
-      obstack_grow_str (obstack, " member=\"");
-      p = xml_escape_text (member_name);
-      obstack_grow_str (obstack, p);
-      xfree (p);
-      obstack_grow_str (obstack, "\"");
-    }
-
-  obstack_grow_str (obstack, " text_addr=\"");
-  obstack_grow_str (obstack, core_addr_to_string (text_addr));
-  obstack_grow_str (obstack, "\"");
-
-  obstack_grow_str (obstack, " text_size=\"");
-  obstack_grow_str (obstack, pulongest (text_size));
-  obstack_grow_str (obstack, "\"");
-
-  obstack_grow_str (obstack, " data_addr=\"");
-  obstack_grow_str (obstack, core_addr_to_string (data_addr));
-  obstack_grow_str (obstack, "\"");
-
-  obstack_grow_str (obstack, " data_size=\"");
-  obstack_grow_str (obstack, pulongest (data_size));
-  obstack_grow_str (obstack, "\"");
-
-  obstack_grow_str (obstack, "></library>");
-}
-
 /* Implement the to_xfer_partial target_ops method for
-   TARGET_OBJECT_AIX_LIBRARIES objects.  */
+   TARGET_OBJECT_LIBRARIES_AIX objects.  */
 
-static LONGEST
+static enum target_xfer_status
 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)
+   ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
 {
-  const int arch64 = ARCH64 ();
-  LdInfo *ldi_data;
-  LdInfo *ldi;
-  struct obstack obstack;
-  const char *buf;
-  LONGEST len_avail;
-
-  if (writebuf)
-    return -1;
-
-  /* Get the ldinfo raw data: If debugging a live process, we get it
-     using ptrace.  Otherwise, the info is stored in the .ldinfo
-     section of the core file.  */
-
-  if (target_has_execution)
-    ldi_data = rs6000_ptrace_ldinfo (inferior_ptid);
-  else
-    ldi_data = rs6000_core_ldinfo (core_bfd);
-
-  /* Convert the raw data into an XML representation.  */
-
-  obstack_init (&obstack);
-  obstack_grow_str (&obstack, "<library-list version=\"1.0\">\n");
-
-  ldi = ldi_data;
-  while (1)
-    {
-      /* Close the fd.  We cannot use it, because we cannot assume
-        that the user of this descriptor will be in the same
-        process.  */
-      close (LDI_FD (ldi, arch64));
+  gdb_byte *ldi_buf;
+  ULONGEST result;
+  struct cleanup *cleanup;
 
-      rs6000_xfer_shared_library (ldi, &obstack);
+  /* This function assumes that it is being run with a live process.
+     Core files are handled via gdbarch.  */
+  gdb_assert (target_has_execution);
 
-      if (!LDI_NEXT (ldi, arch64))
-       break;
-      ldi = (LdInfo *) ((char *) ldi + LDI_NEXT (ldi, arch64));
-    }
+  if (writebuf)
+    return TARGET_XFER_E_IO;
 
-  xfree (ldi_data);
+  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,
+                                     readbuf, offset, len, 1);
+  xfree (ldi_buf);
 
-  obstack_grow_str0 (&obstack, "</library-list>\n");
+  do_cleanups (cleanup);
 
-  buf = obstack_finish (&obstack);
-  len_avail = strlen (buf);
-  if (offset >= len_avail)
-    len= 0;
+  if (result == 0)
+    return TARGET_XFER_EOF;
   else
     {
-      if (len > len_avail - offset)
-        len = len_avail - offset;
-      memcpy (readbuf, buf + offset, len);
+      *xfered_len = result;
+      return TARGET_XFER_OK;
     }
-
-  obstack_free (&obstack, NULL);
-  return len;
 }
 
 void _initialize_rs6000_nat (void);
This page took 0.029121 seconds and 4 git commands to generate.