Modernize the aix-thread later by getting rid of the base_target
[deliverable/binutils-gdb.git] / gdb / rs6000-nat.c
index f4b2831708c0943f276f0157bb9b6cd52e8b2265..9f8a43f8d1be9d94b4363ecdaacf4b2fe45426ff 100644 (file)
@@ -1,12 +1,14 @@
 /* IBM RS/6000 native-dependent code for GDB, the GNU debugger.
-   Copyright 1986, 1987, 1989, 1991, 1992, 1994, 1995, 1996, 1997, 1998
+
+   Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008, 2009
    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,
@@ -15,9 +17,7 @@
    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 "inferior.h"
 #include "xcoffsolib.h"
 #include "symfile.h"
 #include "objfiles.h"
-#include "libbfd.h"            /* For bfd_cache_lookup (FIXME) */
+#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 "inf-ptrace.h"
+#include "ppc-tdep.h"
+#include "rs6000-tdep.h"
+#include "exec.h"
+#include "observer.h"
+#include "xcoffread.h"
 
 #include <sys/ptrace.h>
 #include <sys/reg.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/core.h>
+#define __LDINFO_PTRACE32__    /* for __ld_info32 */
+#define __LDINFO_PTRACE64__    /* for __ld_info64 */
 #include <sys/ldr.h>
+#include <sys/systemcfg.h>
 
-extern int errno;
+/* 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
+   accessing fields in the appropriate structures. */
 
-extern struct vmap *map_vmap PARAMS ((bfd * bf, bfd * arch));
+/* 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. */
 
-extern struct target_ops exec_ops;
+#ifdef __ld_info32
+# define ARCH3264
+#endif
 
-static void
-vmap_exec PARAMS ((void));
+/* Return whether the current architecture is 64-bit. */
 
-static void
-vmap_ldinfo PARAMS ((struct ld_info *));
+#ifndef ARCH3264
+# define ARCH64() 0
+#else
+# define ARCH64() (register_size (current_gdbarch, 0) == 8)
+#endif
 
-static struct vmap *
-  add_vmap PARAMS ((struct ld_info *));
+/* Union of 32-bit and 64-bit versions of ld_info. */
 
-static int
-objfile_symbol_add PARAMS ((char *));
+typedef union {
+#ifndef ARCH3264
+  struct ld_info l32;
+  struct ld_info l64;
+#else
+  struct __ld_info32 l32;
+  struct __ld_info64 l64;
+#endif
+} LdInfo;
 
-static void
-vmap_symtab PARAMS ((struct vmap *));
+/* 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. */
 
-static void
-fetch_core_registers PARAMS ((char *, unsigned int, int, CORE_ADDR));
+#ifndef ARCH3264
+# define ARCH64_DECL(var)
+#else
+# define ARCH64_DECL(var) int var = ARCH64 ()
+#endif
 
-static void
-exec_one_dummy_insn PARAMS ((void));
+/* 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. */
 
-extern void
-fixup_breakpoints PARAMS ((CORE_ADDR low, CORE_ADDR high, CORE_ADDR delta));
+#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
 
-/* Conversion from gdb-to-system special purpose register numbers.. */
+/* Return various LDI fields for a 64-bit process if ARCH64 and for a 32-bit
+   process otherwise. */
 
-static int special_regs[] =
-{
-  IAR,                         /* PC_REGNUM    */
-  MSR,                         /* PS_REGNUM    */
-  CR,                          /* CR_REGNUM    */
-  LR,                          /* LR_REGNUM    */
-  CTR,                         /* CTR_REGNUM   */
-  XER,                         /* XER_REGNUM   */
-  MQ                           /* MQ_REGNUM    */
-};
+#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)
 
-void
-fetch_inferior_registers (regno)
-     int regno;
-{
-  int ii;
+extern struct vmap *map_vmap (bfd * bf, bfd * arch);
 
-  if (regno < 0)
-    {                          /* for all registers */
+static void vmap_exec (void);
 
-      /* read 32 general purpose registers. */
+static void vmap_ldinfo (LdInfo *);
 
-      for (ii = 0; ii < 32; ++ii)
-       *(int *) &registers[REGISTER_BYTE (ii)] =
-         ptrace (PT_READ_GPR, inferior_pid, (PTRACE_ARG3_TYPE) ii, 0, 0);
+static struct vmap *add_vmap (LdInfo *);
 
-      /* read general purpose floating point registers. */
+static int objfile_symbol_add (void *);
 
-      for (ii = 0; ii < 32; ++ii)
-       ptrace (PT_READ_FPR, inferior_pid,
-           (PTRACE_ARG3_TYPE) & registers[REGISTER_BYTE (FP0_REGNUM + ii)],
-               FPR0 + ii, 0);
+static void vmap_symtab (struct vmap *);
 
-      /* read special registers. */
-      for (ii = 0; ii <= LAST_UISA_SP_REGNUM - FIRST_UISA_SP_REGNUM; ++ii)
-       *(int *) &registers[REGISTER_BYTE (FIRST_UISA_SP_REGNUM + ii)] =
-         ptrace (PT_READ_GPR, inferior_pid, (PTRACE_ARG3_TYPE) special_regs[ii],
-                 0, 0);
+static void exec_one_dummy_insn (struct gdbarch *);
 
-      registers_fetched ();
-      return;
-    }
+extern void fixup_breakpoints (CORE_ADDR low, CORE_ADDR high, CORE_ADDR delta);
 
-  /* else an individual register is addressed. */
+/* Given REGNO, a gdb register number, return the corresponding
+   number suitable for use as a ptrace() parameter.  Return -1 if
+   there's no suitable mapping.  Also, set the int pointed to by
+   ISFLOAT to indicate whether REGNO is a floating point register.  */
 
-  else if (regno < FP0_REGNUM)
-    {                          /* a GPR */
-      *(int *) &registers[REGISTER_BYTE (regno)] =
-       ptrace (PT_READ_GPR, inferior_pid, (PTRACE_ARG3_TYPE) regno, 0, 0);
-    }
-  else if (regno <= FPLAST_REGNUM)
-    {                          /* a FPR */
-      ptrace (PT_READ_FPR, inferior_pid,
-             (PTRACE_ARG3_TYPE) & registers[REGISTER_BYTE (regno)],
-             (regno - FP0_REGNUM + FPR0), 0);
-    }
-  else if (regno <= LAST_UISA_SP_REGNUM)
-    {                          /* a special register */
-      *(int *) &registers[REGISTER_BYTE (regno)] =
-       ptrace (PT_READ_GPR, inferior_pid,
-             (PTRACE_ARG3_TYPE) special_regs[regno - FIRST_UISA_SP_REGNUM],
-               0, 0);
+static int
+regmap (struct gdbarch *gdbarch, int regno, int *isfloat)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *isfloat = 0;
+  if (tdep->ppc_gp0_regnum <= regno
+      && regno < tdep->ppc_gp0_regnum + ppc_num_gprs)
+    return regno;
+  else if (tdep->ppc_fp0_regnum >= 0
+           && tdep->ppc_fp0_regnum <= regno
+           && regno < tdep->ppc_fp0_regnum + ppc_num_fprs)
+    {
+      *isfloat = 1;
+      return regno - tdep->ppc_fp0_regnum + FPR0;
     }
+  else if (regno == gdbarch_pc_regnum (gdbarch))
+    return IAR;
+  else if (regno == tdep->ppc_ps_regnum)
+    return MSR;
+  else if (regno == tdep->ppc_cr_regnum)
+    return CR;
+  else if (regno == tdep->ppc_lr_regnum)
+    return LR;
+  else if (regno == tdep->ppc_ctr_regnum)
+    return CTR;
+  else if (regno == tdep->ppc_xer_regnum)
+    return XER;
+  else if (tdep->ppc_fpscr_regnum >= 0
+           && regno == tdep->ppc_fpscr_regnum)
+    return FPSCR;
+  else if (tdep->ppc_mq_regnum >= 0 && regno == tdep->ppc_mq_regnum)
+    return MQ;
   else
-    fprintf_unfiltered (gdb_stderr,
-                       "gdb error: register no %d not implemented.\n",
-                       regno);
+    return -1;
+}
+
+/* Call ptrace(REQ, ID, ADDR, DATA, BUF). */
 
-  register_valid[regno] = 1;
+static int
+rs6000_ptrace32 (int req, int id, int *addr, int data, int *buf)
+{
+  int ret = ptrace (req, id, (int *)addr, data, buf);
+#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);
+#endif
+  return ret;
 }
 
-/* Store our register values back into the inferior.
-   If REGNO is -1, do this for all registers.
-   Otherwise, REGNO specifies which register (so we can save time).  */
+/* Call ptracex(REQ, ID, ADDR, DATA, BUF). */
 
-void
-store_inferior_registers (regno)
-     int regno;
+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);
+#else
+  int ret = 0;
+#endif
+#if 0
+  printf ("rs6000_ptrace64 (%d, %d, 0x%llx, %08x, 0x%x) = 0x%x\n",
+         req, id, addr, data, (unsigned int)buf, ret);
+#endif
+  return ret;
+}
+
+/* Fetch register REGNO from the inferior. */
+
+static void
+fetch_register (struct regcache *regcache, int regno)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int addr[MAX_REGISTER_SIZE];
+  int nr, isfloat;
 
+  /* Retrieved values may be -1, so infer errors from errno. */
   errno = 0;
 
-  if (regno == -1)
-    {                          /* for all registers..  */
-      int ii;
+  nr = regmap (gdbarch, regno, &isfloat);
 
-      /* execute one dummy instruction (which is a breakpoint) in inferior
-         process. So give kernel a chance to do internal house keeping.
-         Otherwise the following ptrace(2) calls will mess up user stack
-         since kernel will get confused about the bottom of the stack (%sp) */
+  /* Floating-point registers. */
+  if (isfloat)
+    rs6000_ptrace32 (PT_READ_FPR, PIDGET (inferior_ptid), addr, nr, 0);
 
-      exec_one_dummy_insn ();
+  /* Bogus register number. */
+  else if (nr < 0)
+    {
+      if (regno >= gdbarch_num_regs (gdbarch))
+       fprintf_unfiltered (gdb_stderr,
+                           "gdb error: register no %d not implemented.\n",
+                           regno);
+      return;
+    }
 
-      /* write general purpose registers first! */
-      for (ii = GPR0; ii <= GPR31; ++ii)
+  /* Fixed-point registers. */
+  else
+    {
+      if (!ARCH64 ())
+       *addr = rs6000_ptrace32 (PT_READ_GPR, PIDGET (inferior_ptid), (int *)nr, 0, 0);
+      else
        {
-         ptrace (PT_WRITE_GPR, inferior_pid, (PTRACE_ARG3_TYPE) ii,
-                 *(int *) &registers[REGISTER_BYTE (ii)], 0);
-         if (errno)
-           {
-             perror ("ptrace write_gpr");
-             errno = 0;
-           }
+         /* 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);
+         if (register_size (gdbarch, regno) == 8)
+           memcpy (addr, &buf, 8);
+         else
+           *addr = buf;
        }
+    }
 
-      /* write floating point registers now. */
-      for (ii = 0; ii < 32; ++ii)
-       {
-         ptrace (PT_WRITE_FPR, inferior_pid,
-           (PTRACE_ARG3_TYPE) & registers[REGISTER_BYTE (FP0_REGNUM + ii)],
-                 FPR0 + ii, 0);
-         if (errno)
-           {
-             perror ("ptrace write_fpr");
-             errno = 0;
-           }
-       }
+  if (!errno)
+    regcache_raw_supply (regcache, regno, (char *) addr);
+  else
+    {
+#if 0
+      /* FIXME: this happens 3 times at the start of each 64-bit program. */
+      perror ("ptrace read");
+#endif
+      errno = 0;
+    }
+}
+
+/* Store register REGNO back into the inferior. */
+
+static void
+store_register (const struct regcache *regcache, int regno)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int addr[MAX_REGISTER_SIZE];
+  int nr, isfloat;
+
+  /* Fetch the register's value from the register cache.  */
+  regcache_raw_collect (regcache, regno, addr);
+
+  /* -1 can be a successful return value, so infer errors from errno. */
+  errno = 0;
 
-      /* write special registers. */
-      for (ii = 0; ii <= LAST_UISA_SP_REGNUM - FIRST_UISA_SP_REGNUM; ++ii)
+  nr = regmap (gdbarch, regno, &isfloat);
+
+  /* Floating-point registers. */
+  if (isfloat)
+    rs6000_ptrace32 (PT_WRITE_FPR, PIDGET (inferior_ptid), addr, nr, 0);
+
+  /* Bogus register number. */
+  else if (nr < 0)
+    {
+      if (regno >= gdbarch_num_regs (gdbarch))
+       fprintf_unfiltered (gdb_stderr,
+                           "gdb error: register no %d not implemented.\n",
+                           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 (gdbarch);
+
+      /* 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);
+      else
        {
-         ptrace (PT_WRITE_GPR, inferior_pid,
-                 (PTRACE_ARG3_TYPE) special_regs[ii],
-            *(int *) &registers[REGISTER_BYTE (FIRST_UISA_SP_REGNUM + ii)],
-                 0);
-         if (errno)
-           {
-             perror ("ptrace write_gpr");
-             errno = 0;
-           }
+         /* PT_WRITE_GPR requires the buffer parameter to point to an 8-byte
+            area, even if the register is really only 32 bits. */
+         long long buf;
+         if (register_size (gdbarch, regno) == 8)
+           memcpy (&buf, addr, 8);
+         else
+           buf = *addr;
+         rs6000_ptrace64 (PT_WRITE_GPR, PIDGET (inferior_ptid), nr, 0, &buf);
        }
     }
 
-  /* else, a specific register number is given... */
-
-  else if (regno < FP0_REGNUM) /* a GPR */
+  if (errno)
     {
-      if (regno == SP_REGNUM)
-       exec_one_dummy_insn ();
-      ptrace (PT_WRITE_GPR, inferior_pid, (PTRACE_ARG3_TYPE) regno,
-             *(int *) &registers[REGISTER_BYTE (regno)], 0);
+      perror ("ptrace write");
+      errno = 0;
     }
+}
+
+/* Read from the inferior all registers if REGNO == -1 and just register
+   REGNO otherwise. */
 
-  else if (regno <= FPLAST_REGNUM)     /* a FPR */
+static void
+rs6000_fetch_inferior_registers (struct target_ops *ops,
+                                struct regcache *regcache, int regno)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  if (regno != -1)
+    fetch_register (regcache, regno);
+
+  else
     {
-      ptrace (PT_WRITE_FPR, inferior_pid,
-             (PTRACE_ARG3_TYPE) & registers[REGISTER_BYTE (regno)],
-             regno - FP0_REGNUM + FPR0, 0);
+      struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+      /* Read 32 general purpose registers.  */
+      for (regno = tdep->ppc_gp0_regnum;
+           regno < tdep->ppc_gp0_regnum + ppc_num_gprs;
+          regno++)
+       {
+         fetch_register (regcache, regno);
+       }
+
+      /* Read general purpose floating point registers.  */
+      if (tdep->ppc_fp0_regnum >= 0)
+        for (regno = 0; regno < ppc_num_fprs; regno++)
+          fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
+
+      /* Read special registers.  */
+      fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
+      fetch_register (regcache, tdep->ppc_ps_regnum);
+      fetch_register (regcache, tdep->ppc_cr_regnum);
+      fetch_register (regcache, tdep->ppc_lr_regnum);
+      fetch_register (regcache, tdep->ppc_ctr_regnum);
+      fetch_register (regcache, tdep->ppc_xer_regnum);
+      if (tdep->ppc_fpscr_regnum >= 0)
+        fetch_register (regcache, tdep->ppc_fpscr_regnum);
+      if (tdep->ppc_mq_regnum >= 0)
+       fetch_register (regcache, tdep->ppc_mq_regnum);
     }
+}
 
-  else if (regno <= LAST_UISA_SP_REGNUM)       /* a special register */
+/* Store our register values back into the inferior.
+   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)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  if (regno != -1)
+    store_register (regcache, regno);
+
+  else
     {
-      ptrace (PT_WRITE_GPR, inferior_pid,
-             (PTRACE_ARG3_TYPE) special_regs[regno - FIRST_UISA_SP_REGNUM],
-             *(int *) &registers[REGISTER_BYTE (regno)], 0);
+      struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+      /* Write general purpose registers first.  */
+      for (regno = tdep->ppc_gp0_regnum;
+           regno < tdep->ppc_gp0_regnum + ppc_num_gprs;
+          regno++)
+       {
+         store_register (regcache, regno);
+       }
+
+      /* Write floating point registers.  */
+      if (tdep->ppc_fp0_regnum >= 0)
+        for (regno = 0; regno < ppc_num_fprs; regno++)
+          store_register (regcache, tdep->ppc_fp0_regnum + regno);
+
+      /* Write special registers.  */
+      store_register (regcache, gdbarch_pc_regnum (gdbarch));
+      store_register (regcache, tdep->ppc_ps_regnum);
+      store_register (regcache, tdep->ppc_cr_regnum);
+      store_register (regcache, tdep->ppc_lr_regnum);
+      store_register (regcache, tdep->ppc_ctr_regnum);
+      store_register (regcache, tdep->ppc_xer_regnum);
+      if (tdep->ppc_fpscr_regnum >= 0)
+        store_register (regcache, tdep->ppc_fpscr_regnum);
+      if (tdep->ppc_mq_regnum >= 0)
+       store_register (regcache, tdep->ppc_mq_regnum);
     }
+}
+
+
+/* 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.  */
 
-  else if (regno < NUM_REGS)
+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)
+{
+  pid_t pid = ptid_get_pid (inferior_ptid);
+  int arch64 = ARCH64 ();
+
+  switch (object)
     {
-      /* Ignore it.  */
+    case TARGET_OBJECT_MEMORY:
+      {
+       union
+       {
+         PTRACE_TYPE_RET word;
+         gdb_byte byte[sizeof (PTRACE_TYPE_RET)];
+       } buffer;
+       ULONGEST rounded_offset;
+       LONGEST partial_len;
+
+       /* Round the start offset down to the next long word
+          boundary.  */
+       rounded_offset = offset & -(ULONGEST) sizeof (PTRACE_TYPE_RET);
+
+       /* Since ptrace will transfer a single word starting at that
+          rounded_offset the partial_len needs to be adjusted down to
+          that (remember this function only does a single transfer).
+          Should the required length be even less, adjust it down
+          again.  */
+       partial_len = (rounded_offset + sizeof (PTRACE_TYPE_RET)) - offset;
+       if (partial_len > len)
+         partial_len = len;
+
+       if (writebuf)
+         {
+           /* If OFFSET:PARTIAL_LEN is smaller than
+              ROUNDED_OFFSET:WORDSIZE then a read/modify write will
+              be needed.  Read in the entire word.  */
+           if (rounded_offset < offset
+               || (offset + partial_len
+                   < rounded_offset + sizeof (PTRACE_TYPE_RET)))
+             {
+               /* Need part of initial word -- fetch it.  */
+               if (arch64)
+                 buffer.word = rs6000_ptrace64 (PT_READ_I, pid,
+                                                rounded_offset, 0, NULL);
+               else
+                 buffer.word = rs6000_ptrace32 (PT_READ_I, pid,
+                                                (int *)(uintptr_t)rounded_offset,
+                                                0, NULL);
+             }
+
+           /* Copy data to be written over corresponding part of
+              buffer.  */
+           memcpy (buffer.byte + (offset - rounded_offset),
+                   writebuf, partial_len);
+
+           errno = 0;
+           if (arch64)
+             rs6000_ptrace64 (PT_WRITE_D, pid,
+                              rounded_offset, buffer.word, NULL);
+           else
+             rs6000_ptrace32 (PT_WRITE_D, pid,
+                              (int *)(uintptr_t)rounded_offset, buffer.word, NULL);
+           if (errno)
+             return 0;
+         }
+
+       if (readbuf)
+         {
+           errno = 0;
+           if (arch64)
+             buffer.word = rs6000_ptrace64 (PT_READ_I, pid,
+                                            rounded_offset, 0, NULL);
+           else
+             buffer.word = rs6000_ptrace32 (PT_READ_I, pid,
+                                            (int *)(uintptr_t)rounded_offset,
+                                            0, NULL);
+           if (errno)
+             return 0;
+
+           /* Copy appropriate bytes out of the buffer.  */
+           memcpy (readbuf, buffer.byte + (offset - rounded_offset),
+                   partial_len);
+         }
+
+       return partial_len;
+      }
+
+    default:
+      return -1;
     }
+}
 
-  else
-    fprintf_unfiltered (gdb_stderr,
-                       "Gdb error: register no %d not implemented.\n",
-                       regno);
+/* Wait for the child specified by PTID to do something.  Return the
+   process ID of the child, or MINUS_ONE_PTID in case of error; store
+   the status in *OURSTATUS.  */
 
-  if (errno)
+static ptid_t
+rs6000_wait (struct target_ops *ops,
+            ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+  pid_t pid;
+  int status, save_errno;
+
+  do
     {
-      perror ("ptrace write");
-      errno = 0;
+      set_sigint_trap ();
+
+      do
+       {
+         pid = waitpid (ptid_get_pid (ptid), &status, 0);
+         save_errno = errno;
+       }
+      while (pid == -1 && errno == EINTR);
+
+      clear_sigint_trap ();
+
+      if (pid == -1)
+       {
+         fprintf_unfiltered (gdb_stderr,
+                             _("Child process unexpectedly missing: %s.\n"),
+                             safe_strerror (save_errno));
+
+         /* Claim it exited with unknown signal.  */
+         ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+         ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+         return inferior_ptid;
+       }
+
+      /* Ignore terminated detached child processes.  */
+      if (!WIFSTOPPED (status) && pid != ptid_get_pid (inferior_ptid))
+       pid = -1;
     }
+  while (pid == -1);
+
+  /* AIX has a couple of strange returns from wait().  */
+
+  /* stop after load" status.  */
+  if (status == 0x57c)
+    ourstatus->kind = TARGET_WAITKIND_LOADED;
+  /* signal 0. I have no idea why wait(2) returns with this status word.  */
+  else if (status == 0x7f)
+    ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+  /* A normal waitstatus.  Let the usual macros deal with it.  */
+  else
+    store_waitstatus (ourstatus, status);
+
+  return pid_to_ptid (pid);
 }
 
 /* Execute one dummy breakpoint instruction.  This way we give the kernel
@@ -257,21 +577,19 @@ store_inferior_registers (regno)
    including u_area. */
 
 static void
-exec_one_dummy_insn ()
+exec_one_dummy_insn (struct gdbarch *gdbarch)
 {
-#define        DUMMY_INSN_ADDR (TEXT_SEGMENT_BASE)+0x200
+#define        DUMMY_INSN_ADDR AIX_TEXT_SEGMENT_BASE+0x200
 
-  char shadow_contents[BREAKPOINT_MAX];                /* Stash old bkpt addr contents */
-  int status, pid;
+  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. */
 
-  target_insert_breakpoint (DUMMY_INSN_ADDR, shadow_contents);
-
-  errno = 0;
+  bp = deprecated_insert_raw_breakpoint (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
@@ -280,62 +598,59 @@ exec_one_dummy_insn ()
      powerpc-ibm-aix4.1.3 works correctly).  */
   prev_pc = read_pc ();
   write_pc (DUMMY_INSN_ADDR);
-  ptrace (PT_CONTINUE, inferior_pid, (PTRACE_ARG3_TYPE) 1, 0, 0);
+  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 (errno)
+  if (ret != 0)
     perror ("pt_continue");
 
   do
     {
       pid = wait (&status);
     }
-  while (pid != inferior_pid);
+  while (pid != PIDGET (inferior_ptid));
 
   write_pc (prev_pc);
-  target_remove_breakpoint (DUMMY_INSN_ADDR, shadow_contents);
+  deprecated_remove_raw_breakpoint (bp);
 }
+\f
+
+/* Copy information about text and data sections from LDI to VP for a 64-bit
+   process if ARCH64 and for a 32-bit process otherwise. */
 
 static void
-fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
-     char *core_reg_sect;
-     unsigned core_reg_size;
-     int which;
-     CORE_ADDR reg_addr;       /* Unused in this version */
+vmap_secs (struct vmap *vp, LdInfo *ldi, int arch64)
 {
-  /* fetch GPRs and special registers from the first register section
-     in core bfd. */
-  if (which == 0)
+  if (arch64)
     {
-      /* copy GPRs first. */
-      memcpy (registers, core_reg_sect, 32 * 4);
-
-      /* gdb's internal register template and bfd's register section layout
-         should share a common include file. FIXMEmgo */
-      /* then comes special registes. They are supposed to be in the same
-         order in gdb template and bfd `.reg' section. */
-      core_reg_sect += (32 * 4);
-      memcpy (&registers[REGISTER_BYTE (FIRST_UISA_SP_REGNUM)],
-             core_reg_sect,
-             (LAST_UISA_SP_REGNUM - FIRST_UISA_SP_REGNUM + 1) * 4);
+      vp->tstart = (CORE_ADDR) ldi->l64.ldinfo_textorg;
+      vp->tend = vp->tstart + ldi->l64.ldinfo_textsize;
+      vp->dstart = (CORE_ADDR) ldi->l64.ldinfo_dataorg;
+      vp->dend = vp->dstart + ldi->l64.ldinfo_datasize;
     }
-
-  /* fetch floating point registers from register section 2 in core bfd. */
-  else if (which == 2)
-    memcpy (&registers[REGISTER_BYTE (FP0_REGNUM)], core_reg_sect, 32 * 8);
-
   else
-    fprintf_unfiltered
-      (gdb_stderr,
-       "Gdb error: unknown parameter to fetch_core_registers().\n");
+    {
+      vp->tstart = (unsigned long) ldi->l32.ldinfo_textorg;
+      vp->tend = vp->tstart + ldi->l32.ldinfo_textsize;
+      vp->dstart = (unsigned long) ldi->l32.ldinfo_dataorg;
+      vp->dend = vp->dstart + ldi->l32.ldinfo_datasize;
+    }
+
+  /* The run time loader maps the file header in addition to the text
+     section and returns a pointer to the header in ldinfo_textorg.
+     Adjust the text start address to point to the real start address
+     of the text section.  */
+  vp->tstart += vp->toffs;
 }
-\f
+
 /* handle symbol translation on vmapping */
 
 static void
-vmap_symtab (vp)
-     register struct vmap *vp;
+vmap_symtab (struct vmap *vp)
 {
-  register struct objfile *objfile;
+  struct objfile *objfile;
   struct section_offsets *new_offsets;
   int i;
 
@@ -349,17 +664,22 @@ vmap_symtab (vp)
        return;
       objfile = symfile_objfile;
     }
+  else if (!vp->loaded)
+    /* If symbols are not yet loaded, offsets are not yet valid. */
+    return;
 
-  new_offsets = (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS);
+  new_offsets =
+    (struct section_offsets *)
+    alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
 
   for (i = 0; i < objfile->num_sections; ++i)
-    ANOFFSET (new_offsets, i) = ANOFFSET (objfile->section_offsets, i);
+    new_offsets->offsets[i] = ANOFFSET (objfile->section_offsets, i);
 
   /* The symbols in the object file are linked to the VMA of the section,
      relocate them VMA relative.  */
-  ANOFFSET (new_offsets, SECT_OFF_TEXT) = vp->tstart - vp->tvma;
-  ANOFFSET (new_offsets, SECT_OFF_DATA) = vp->dstart - vp->dvma;
-  ANOFFSET (new_offsets, SECT_OFF_BSS) = vp->dstart - vp->dvma;
+  new_offsets->offsets[SECT_OFF_TEXT (objfile)] = vp->tstart - vp->tvma;
+  new_offsets->offsets[SECT_OFF_DATA (objfile)] = vp->dstart - vp->dvma;
+  new_offsets->offsets[SECT_OFF_BSS (objfile)] = vp->dstart - vp->dvma;
 
   objfile_relocate (objfile, new_offsets);
 }
@@ -367,16 +687,32 @@ vmap_symtab (vp)
 /* Add symbols for an objfile.  */
 
 static int
-objfile_symbol_add (arg)
-     char *arg;
+objfile_symbol_add (void *arg)
 {
   struct objfile *obj = (struct objfile *) arg;
 
-  syms_from_objfile (obj, NULL, 0, 0);
+  syms_from_objfile (obj, NULL, 0, 0, 0, 0);
   new_symfile_objfile (obj, 0, 0);
   return 1;
 }
 
+/* Add symbols for a vmap. Return zero upon error.  */
+
+int
+vmap_add_symbols (struct vmap *vp)
+{
+  if (catch_errors (objfile_symbol_add, vp->objfile,
+                   "Error while reading shared library symbols:\n",
+                   RETURN_MASK_ALL))
+    {
+      /* Note this is only done if symbol reading was successful.  */
+      vp->loaded = 1;
+      vmap_symtab (vp);
+      return 1;
+    }
+  return 0;
+}
+
 /* Add a new vmap entry based on ldinfo() information.
 
    If ldi->ldinfo_fd is not valid (e.g. this struct ld_info is from a
@@ -385,31 +721,37 @@ objfile_symbol_add (arg)
    Return the vmap new entry.  */
 
 static struct vmap *
-add_vmap (ldi)
-     register struct ld_info *ldi;
+add_vmap (LdInfo *ldi)
 {
   bfd *abfd, *last;
-  register char *mem, *objname;
+  char *mem, *objname, *filename;
   struct objfile *obj;
   struct vmap *vp;
+  int fd;
+  ARCH64_DECL (arch64);
 
   /* This ldi structure was allocated using alloca() in 
      xcoff_relocate_symtab(). Now we need to have persistent object 
      and member names, so we should save them. */
 
-  mem = ldi->ldinfo_filename + strlen (ldi->ldinfo_filename) + 1;
+  filename = LDI_FILENAME (ldi, arch64);
+  mem = filename + strlen (filename) + 1;
   mem = savestring (mem, strlen (mem));
-  objname = savestring (ldi->ldinfo_filename, strlen (ldi->ldinfo_filename));
+  objname = savestring (filename, strlen (filename));
 
-  if (ldi->ldinfo_fd < 0)
+  fd = LDI_FD (ldi, arch64);
+  if (fd < 0)
     /* Note that this opens it once for every member; a possible
        enhancement would be to only open it once for every object.  */
     abfd = bfd_openr (objname, gnutarget);
   else
-    abfd = bfd_fdopenr (objname, gnutarget, ldi->ldinfo_fd);
+    abfd = bfd_fdopenr (objname, gnutarget, fd);
   if (!abfd)
-    error ("Could not open `%s' as an executable file: %s",
-          objname, bfd_errmsg (bfd_get_error ()));
+    {
+      warning (_("Could not open `%s' as an executable file: %s"),
+              objname, bfd_errmsg (bfd_get_error ()));
+      return NULL;
+    }
 
   /* make sure we have an object file */
 
@@ -421,46 +763,40 @@ add_vmap (ldi)
       last = 0;
       /* FIXME??? am I tossing BFDs?  bfd? */
       while ((last = bfd_openr_next_archived_file (abfd, last)))
-       if (STREQ (mem, last->filename))
+       if (strcmp (mem, last->filename) == 0)
          break;
 
       if (!last)
        {
+         warning (_("\"%s\": member \"%s\" missing."), objname, mem);
          bfd_close (abfd);
-         /* FIXME -- should be error */
-         warning ("\"%s\": member \"%s\" missing.", abfd->filename, mem);
-         return 0;
+         return NULL;
        }
 
       if (!bfd_check_format (last, bfd_object))
        {
-         bfd_close (last);     /* XXX???       */
-         goto obj_err;
+         warning (_("\"%s\": member \"%s\" not in executable format: %s."),
+                  objname, mem, bfd_errmsg (bfd_get_error ()));
+         bfd_close (last);
+         bfd_close (abfd);
+         return NULL;
        }
 
       vp = map_vmap (last, abfd);
     }
   else
     {
-    obj_err:
+      warning (_("\"%s\": not in executable format: %s."),
+              objname, bfd_errmsg (bfd_get_error ()));
       bfd_close (abfd);
-      error ("\"%s\": not in executable format: %s.",
-            objname, bfd_errmsg (bfd_get_error ()));
-      /*NOTREACHED */
+      return NULL;
     }
   obj = allocate_objfile (vp->bfd, 0);
   vp->objfile = obj;
 
-#ifndef SOLIB_SYMBOLS_MANUAL
-  if (catch_errors (objfile_symbol_add, (char *) obj,
-                   "Error while reading shared library symbols:\n",
-                   RETURN_MASK_ALL))
-    {
-      /* Note this is only done if symbol reading was successful.  */
-      vmap_symtab (vp);
-      vp->loaded = 1;
-    }
-#endif
+  /* Always add symbols for the main objfile.  */
+  if (vp == vmap || auto_solib_add)
+    vmap_add_symbols (vp);
   return vp;
 }
 \f
@@ -468,13 +804,14 @@ add_vmap (ldi)
    Input is ptr to ldinfo() results.  */
 
 static void
-vmap_ldinfo (ldi)
-     register struct ld_info *ldi;
+vmap_ldinfo (LdInfo *ldi)
 {
   struct stat ii, vi;
-  register struct vmap *vp;
+  struct vmap *vp;
   int got_one, retried;
   int got_exec_file = 0;
+  uint next;
+  int arch64 = ARCH64 ();
 
   /* For each *ldi, see if we have a corresponding *vp.
      If so, update the mapping, and symbol table.
@@ -482,18 +819,19 @@ vmap_ldinfo (ldi)
 
   do
     {
-      char *name = ldi->ldinfo_filename;
+      char *name = LDI_FILENAME (ldi, arch64);
       char *memb = name + strlen (name) + 1;
+      int fd = LDI_FD (ldi, arch64);
 
       retried = 0;
 
-      if (fstat (ldi->ldinfo_fd, &ii) < 0)
+      if (fstat (fd, &ii) < 0)
        {
          /* The kernel sets ld_info to -1, if the process is still using the
             object, and the object is removed. Keep the symbol info for the
             removed object and issue a warning.  */
-         warning ("%s (fd=%d) has disappeared, keeping its symbols",
-                  name, ldi->ldinfo_fd);
+         warning (_("%s (fd=%d) has disappeared, keeping its symbols"),
+                  name, fd);
          continue;
        }
     retry:
@@ -509,8 +847,8 @@ vmap_ldinfo (ldi)
 
          /* The filenames are not always sufficient to match on. */
 
-         if ((name[0] == '/' && !STREQ (name, vp->name))
-             || (memb[0] && !STREQ (memb, vp->member)))
+         if ((name[0] == '/' && strcmp (name, vp->name) != 0)
+             || (memb[0] && strcmp (memb, vp->member) != 0))
            continue;
 
          /* See if we are referring to the same file.
@@ -521,7 +859,7 @@ vmap_ldinfo (ldi)
              || objfile->obfd == NULL
              || bfd_stat (objfile->obfd, &vi) < 0)
            {
-             warning ("Unable to stat %s, keeping its symbols", name);
+             warning (_("Unable to stat %s, keeping its symbols"), name);
              continue;
            }
 
@@ -529,23 +867,13 @@ vmap_ldinfo (ldi)
            continue;
 
          if (!retried)
-           close (ldi->ldinfo_fd);
+           close (fd);
 
          ++got_one;
 
          /* Found a corresponding VMAP.  Remap!  */
 
-         /* We can assume pointer == CORE_ADDR, this code is native only.  */
-         vp->tstart = (CORE_ADDR) ldi->ldinfo_textorg;
-         vp->tend = vp->tstart + ldi->ldinfo_textsize;
-         vp->dstart = (CORE_ADDR) ldi->ldinfo_dataorg;
-         vp->dend = vp->dstart + ldi->ldinfo_datasize;
-
-         /* The run time loader maps the file header in addition to the text
-            section and returns a pointer to the header in ldinfo_textorg.
-            Adjust the text start address to point to the real start address
-            of the text section.  */
-         vp->tstart += vp->toffs;
+         vmap_secs (vp, ldi, arch64);
 
          /* The objfile is only NULL for the exec file.  */
          if (vp->objfile == NULL)
@@ -554,6 +882,11 @@ vmap_ldinfo (ldi)
          /* relocate symbol table(s). */
          vmap_symtab (vp);
 
+         /* Announce new object files.  Doing this after symbol relocation
+            makes aix-thread.c's job easier.  */
+         if (vp->objfile)
+           observer_notify_new_objfile (vp->objfile);
+
          /* There may be more, so we don't break out of the loop.  */
        }
 
@@ -565,8 +898,8 @@ vmap_ldinfo (ldi)
          goto retry;
        }
     }
-  while (ldi->ldinfo_next
-        && (ldi = (void *) (ldi->ldinfo_next + (char *) ldi)));
+  while ((next = LDI_NEXT (ldi, arch64))
+        && (ldi = (void *) (next + (char *) ldi)));
 
   /* If we don't find the symfile_objfile anywhere in the ldinfo, it
      is unlikely that the symbol file is relocated to the proper
@@ -574,14 +907,12 @@ vmap_ldinfo (ldi)
      running a different copy of the same executable.  */
   if (symfile_objfile != NULL && !got_exec_file)
     {
-      warning_begin ();
-      fputs_unfiltered ("Symbol file ", gdb_stderr);
-      fputs_unfiltered (symfile_objfile->name, gdb_stderr);
-      fputs_unfiltered ("\nis not mapped; discarding it.\n\
+      warning (_("Symbol file %s\nis not mapped; discarding it.\n\
 If in fact that file has symbols which the mapped files listed by\n\
 \"info files\" lack, you can load symbols with the \"symbol-file\" or\n\
 \"add-symbol-file\" commands (note that you must take care of relocating\n\
-symbols to the proper address).\n", gdb_stderr);
+symbols to the proper address)."),
+              symfile_objfile->name);
       free_objfile (symfile_objfile);
       symfile_objfile = NULL;
     }
@@ -599,7 +930,7 @@ symbols to the proper address).\n", gdb_stderr);
  */
 
 static void
-vmap_exec ()
+vmap_exec (void)
 {
   static bfd *execbfd;
   int i;
@@ -610,69 +941,137 @@ vmap_exec ()
   execbfd = exec_bfd;
 
   if (!vmap || !exec_ops.to_sections)
-    error ("vmap_exec: vmap or exec_ops.to_sections == 0\n");
+    error (_("vmap_exec: vmap or exec_ops.to_sections == 0."));
 
   for (i = 0; &exec_ops.to_sections[i] < exec_ops.to_sections_end; i++)
     {
-      if (STREQ (".text", exec_ops.to_sections[i].the_bfd_section->name))
+      if (strcmp (".text", exec_ops.to_sections[i].the_bfd_section->name) == 0)
        {
          exec_ops.to_sections[i].addr += vmap->tstart - vmap->tvma;
          exec_ops.to_sections[i].endaddr += vmap->tstart - vmap->tvma;
        }
-      else if (STREQ (".data", exec_ops.to_sections[i].the_bfd_section->name))
+      else if (strcmp (".data",
+                      exec_ops.to_sections[i].the_bfd_section->name) == 0)
        {
          exec_ops.to_sections[i].addr += vmap->dstart - vmap->dvma;
          exec_ops.to_sections[i].endaddr += vmap->dstart - vmap->dvma;
        }
-      else if (STREQ (".bss", exec_ops.to_sections[i].the_bfd_section->name))
+      else if (strcmp (".bss",
+                      exec_ops.to_sections[i].the_bfd_section->name) == 0)
        {
          exec_ops.to_sections[i].addr += vmap->dstart - vmap->dvma;
          exec_ops.to_sections[i].endaddr += vmap->dstart - vmap->dvma;
        }
     }
 }
+
+/* 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)
+{
+  enum bfd_architecture arch;
+  unsigned long mach;
+  bfd abfd;
+  struct gdbarch_info info;
+
+  super_create_inferior (ops, exec_file, allargs, env, from_tty);
+
+  if (__power_rs ())
+    {
+      arch = bfd_arch_rs6000;
+      mach = bfd_mach_rs6k;
+    }
+  else
+    {
+      arch = bfd_arch_powerpc;
+      mach = bfd_mach_ppc;
+    }
+
+  /* FIXME: schauer/2002-02-25:
+     We don't know if we are executing a 32 or 64 bit executable,
+     and have no way to pass the proper word size to rs6000_gdbarch_init.
+     So we have to avoid switching to a new architecture, if the architecture
+     matches already.
+     Blindly calling rs6000_gdbarch_init used to work in older versions of
+     GDB, as rs6000_gdbarch_init incorrectly used the previous tdep to
+     determine the wordsize.  */
+  if (exec_bfd)
+    {
+      const struct bfd_arch_info *exec_bfd_arch_info;
+
+      exec_bfd_arch_info = bfd_get_arch_info (exec_bfd);
+      if (arch == exec_bfd_arch_info->arch)
+       return;
+    }
+
+  bfd_default_set_arch_mach (&abfd, arch, mach);
+
+  gdbarch_info_init (&info);
+  info.bfd_arch_info = bfd_get_arch_info (&abfd);
+  info.abfd = exec_bfd;
+
+  if (!gdbarch_update_p (info))
+    internal_error (__FILE__, __LINE__,
+                   _("rs6000_create_inferior: failed to select architecture"));
+}
+
 \f
 /* xcoff_relocate_symtab -      hook for symbol table relocation.
-   also reads shared libraries.. */
+   
+   This is only applicable to live processes, and is a no-op when
+   debugging a core file.  */
 
 void
-xcoff_relocate_symtab (pid)
-     unsigned int pid;
+xcoff_relocate_symtab (unsigned int pid)
 {
   int load_segs = 64; /* number of load segments */
+  int rc;
+  LdInfo *ldi = NULL;
+  int arch64 = ARCH64 ();
+  int ldisize = arch64 ? sizeof (ldi->l64) : sizeof (ldi->l32);
+  int size;
+
+  if (ptid_equal (inferior_ptid, null_ptid))
+    return;
 
   do
     {
-  struct ld_info *ldi;
-      int rc;
-
-      ldi = (void *) alloca (load_segs * sizeof (*ldi));
-      if (ldi == 0)
-       perror_with_name ("xcoff_relocate_symtab");
-
-  /* According to my humble theory, AIX has some timing problems and
-     when the user stack grows, kernel doesn't update stack info in time
-     and ptrace calls step on user stack. That is why we sleep here a little,
-     and give kernel to update its internals. */
+      size = load_segs * ldisize;
+      ldi = (void *) xrealloc (ldi, size);
+
+#if 0
+      /* According to my humble theory, AIX has some timing problems and
+         when the user stack grows, kernel doesn't update stack info in time
+         and ptrace calls step on user stack. That is why we sleep here a
+         little, and give kernel to update its internals. */
+      usleep (36000);
+#endif
 
-  usleep (36000);
+      if (arch64)
+       rc = rs6000_ptrace64 (PT_LDINFO, pid, (unsigned long) ldi, size, NULL);
+      else
+       rc = rs6000_ptrace32 (PT_LDINFO, pid, (int *) ldi, size, NULL);
 
-  errno = 0;
-      rc = ptrace (PT_LDINFO, pid, (PTRACE_ARG3_TYPE) ldi,
-             load_segs * sizeof (*ldi), (int *) ldi);
       if (rc == -1)
         {
-       if (errno == ENOMEM)
-         load_segs *= 2;
-       else
-    perror_with_name ("ptrace ldinfo");
+          if (errno == ENOMEM)
+            load_segs *= 2;
+          else
+            perror_with_name (_("ptrace ldinfo"));
         }
       else
        {
-  vmap_ldinfo (ldi);
-         vmap_exec (); /* relocate the exec and core sections as well. */
+          vmap_ldinfo (ldi);
+          vmap_exec (); /* relocate the exec and core sections as well. */
        }
     } while (rc == -1);
+  if (ldi)
+    xfree (ldi);
 }
 \f
 /* Core file stuff.  */
@@ -681,33 +1080,22 @@ xcoff_relocate_symtab (pid)
    from the core file.  */
 
 void
-xcoff_relocate_core (target)
-     struct target_ops *target;
+xcoff_relocate_core (struct target_ops *target)
 {
-/* Offset of member MEMBER in a struct of type TYPE.  */
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
-#endif
-
-/* Size of a struct ld_info except for the variable-length filename.  */
-#define LDINFO_SIZE (offsetof (struct ld_info, ldinfo_filename))
-
-  sec_ptr ldinfo_sec;
+  struct bfd_section *ldinfo_sec;
   int offset = 0;
-  struct ld_info *ldip;
+  LdInfo *ldi;
   struct vmap *vp;
+  int arch64 = ARCH64 ();
+
+  /* Size of a struct ld_info except for the variable-length filename. */
+  int nonfilesz = (int)LDI_FILENAME ((LdInfo *)0, arch64);
 
   /* Allocated size of buffer.  */
-  int buffer_size = LDINFO_SIZE;
+  int buffer_size = nonfilesz;
   char *buffer = xmalloc (buffer_size);
   struct cleanup *old = make_cleanup (free_current_contents, &buffer);
 
-  /* FIXME, this restriction should not exist.  For now, though I'll
-     avoid coredumps with error() pending a real fix.  */
-  if (vmap == NULL)
-    error
-      ("Can't debug a core file without an executable file (on the RS/6000)");
-
   ldinfo_sec = bfd_get_section_by_name (core_bfd, ".ldinfo");
   if (ldinfo_sec == NULL)
     {
@@ -724,11 +1112,11 @@ xcoff_relocate_core (target)
 
       /* Read in everything but the name.  */
       if (bfd_get_section_contents (core_bfd, ldinfo_sec, buffer,
-                                   offset, LDINFO_SIZE) == 0)
+                                   offset, nonfilesz) == 0)
        goto bfd_err;
 
       /* Now the name.  */
-      i = LDINFO_SIZE;
+      i = nonfilesz;
       do
        {
          if (i == buffer_size)
@@ -744,30 +1132,26 @@ xcoff_relocate_core (target)
        }
       while (names_found < 2);
 
-      ldip = (struct ld_info *) buffer;
+      ldi = (LdInfo *) buffer;
 
       /* Can't use a file descriptor from the core file; need to open it.  */
-      ldip->ldinfo_fd = -1;
+      if (arch64)
+       ldi->l64.ldinfo_fd = -1;
+      else
+       ldi->l32.ldinfo_fd = -1;
 
       /* The first ldinfo is for the exec file, allocated elsewhere.  */
-      if (offset == 0)
+      if (offset == 0 && vmap != NULL)
        vp = vmap;
       else
-       vp = add_vmap (ldip);
+       vp = add_vmap (ldi);
 
-      offset += ldip->ldinfo_next;
+      /* Process next shared library upon error. */
+      offset += LDI_NEXT (ldi, arch64);
+      if (vp == NULL)
+       continue;
 
-      /* We can assume pointer == CORE_ADDR, this code is native only.  */
-      vp->tstart = (CORE_ADDR) ldip->ldinfo_textorg;
-      vp->tend = vp->tstart + ldip->ldinfo_textsize;
-      vp->dstart = (CORE_ADDR) ldip->ldinfo_dataorg;
-      vp->dend = vp->dstart + ldip->ldinfo_datasize;
-
-      /* The run time loader maps the file header in addition to the text
-         section and returns a pointer to the header in ldinfo_textorg.
-         Adjust the text start address to point to the real start address
-         of the text section.  */
-      vp->tstart += vp->toffs;
+      vmap_secs (vp, ldi, arch64);
 
       /* Unless this is the exec file,
          add our sections to the section table for the core target.  */
@@ -791,18 +1175,15 @@ xcoff_relocate_core (target)
        }
 
       vmap_symtab (vp);
+
+      if (vp != vmap && vp->objfile)
+       observer_notify_new_objfile (vp->objfile);
     }
-  while (ldip->ldinfo_next != 0);
+  while (LDI_NEXT (ldi, arch64) != 0);
   vmap_exec ();
   breakpoint_re_set ();
   do_cleanups (old);
 }
-
-int
-kernel_u_size ()
-{
-  return (sizeof (struct user));
-}
 \f
 /* Under AIX, we have to pass the correct TOC pointer to a function
    when calling functions in the inferior.
@@ -810,8 +1191,7 @@ kernel_u_size ()
    and add the current load address of the data segment from the vmap.  */
 
 static CORE_ADDR
-find_toc_address (pc)
-     CORE_ADDR pc;
+find_toc_address (CORE_ADDR pc)
 {
   struct vmap *vp;
 
@@ -820,35 +1200,33 @@ find_toc_address (pc)
       if (pc >= vp->tstart && pc < vp->tend)
        {
          /* vp->objfile is only NULL for the exec file.  */
-         return vp->dstart + get_toc_offset (vp->objfile == NULL
-                                             ? symfile_objfile
-                                             : vp->objfile);
+         return vp->dstart + xcoff_get_toc_offset (vp->objfile == NULL
+                                                   ? symfile_objfile
+                                                   : vp->objfile);
        }
     }
-  error ("Unable to find TOC entry for pc 0x%x\n", pc);
+  error (_("Unable to find TOC entry for pc %s."), hex_string (pc));
 }
 \f
-/* Register that we are able to handle rs6000 core file formats. */
-
-static struct core_fns rs6000_core_fns =
-{
-  bfd_target_coff_flavour,             /* core_flavour */
-  default_check_format,                        /* check_format */
-  default_core_sniffer,                        /* core_sniffer */
-  fetch_core_registers,                        /* core_read_registers */
-  NULL                                 /* next */
-};
 
 void
-_initialize_core_rs6000 ()
+_initialize_rs6000_nat (void)
 {
-  /* Initialize hook in rs6000-tdep.c for determining the TOC address when
-     calling functions in the inferior.  */
-  find_toc_address_hook = &find_toc_address;
-
-  /* For native configurations, where this module is included, inform
-     the xcoffsolib module where it can find the function for symbol table
-     relocation at runtime. */
-  xcoff_relocate_symtab_hook = &xcoff_relocate_symtab;
-  add_core_fns (&rs6000_core_fns);
+  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);
+
+  /* Initialize hook in rs6000-tdep.c for determining the TOC address
+     when calling functions in the inferior.  */
+  rs6000_find_toc_address_hook = find_toc_address;
 }
This page took 0.039403 seconds and 4 git commands to generate.