[ gas/testsuite/ChangeLog ]
[deliverable/binutils-gdb.git] / gdb / ppcnbsd-tdep.c
index ba863d07a7923839207758d13086326623309b43..57ba742c85a5708cc9cf88d0cfc2ae29e1b36029 100644 (file)
@@ -1,5 +1,7 @@
 /* Target-dependent code for PowerPC systems running NetBSD.
-   Copyright 2002, 2003 Free Software Foundation, Inc.
+
+   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+
    Contributed by Wasabi Systems, Inc.
 
    This file is part of GDB.
@@ -16,8 +18,8 @@
 
    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.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "defs.h"
 #include "gdbcore.h"
@@ -30,7 +32,9 @@
 #include "ppc-tdep.h"
 #include "ppcnbsd-tdep.h"
 #include "nbsd-tdep.h"
-
+#include "tramp-frame.h"
+#include "trad-frame.h"
+#include "gdb_assert.h"
 #include "solib-svr4.h"
 
 #define REG_FIXREG_OFFSET(x)   ((x) * 4)
@@ -51,26 +55,32 @@ ppcnbsd_supply_reg (char *regs, int regno)
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   int i;
 
-  for (i = 0; i <= 31; i++)
+  for (i = 0; i < ppc_num_gprs; i++)
     {
-      if (regno == i || regno == -1)
-       supply_register (i, regs + REG_FIXREG_OFFSET (i));
+      if (regno == tdep->ppc_gp0_regnum + i || regno == -1)
+       regcache_raw_supply (current_regcache, tdep->ppc_gp0_regnum + i,
+                            regs + REG_FIXREG_OFFSET (i));
     }
 
   if (regno == tdep->ppc_lr_regnum || regno == -1)
-    supply_register (tdep->ppc_lr_regnum, regs + REG_LR_OFFSET);
+    regcache_raw_supply (current_regcache, tdep->ppc_lr_regnum,
+                        regs + REG_LR_OFFSET);
 
   if (regno == tdep->ppc_cr_regnum || regno == -1)
-    supply_register (tdep->ppc_cr_regnum, regs + REG_CR_OFFSET);
+    regcache_raw_supply (current_regcache, tdep->ppc_cr_regnum,
+                        regs + REG_CR_OFFSET);
 
   if (regno == tdep->ppc_xer_regnum || regno == -1)
-    supply_register (tdep->ppc_xer_regnum, regs + REG_XER_OFFSET);
+    regcache_raw_supply (current_regcache, tdep->ppc_xer_regnum,
+                        regs + REG_XER_OFFSET);
 
   if (regno == tdep->ppc_ctr_regnum || regno == -1)
-    supply_register (tdep->ppc_ctr_regnum, regs + REG_CTR_OFFSET);
+    regcache_raw_supply (current_regcache, tdep->ppc_ctr_regnum,
+                        regs + REG_CTR_OFFSET);
 
   if (regno == PC_REGNUM || regno == -1)
-    supply_register (PC_REGNUM, regs + REG_PC_OFFSET);
+    regcache_raw_supply (current_regcache, PC_REGNUM,
+                        regs + REG_PC_OFFSET);
 }
 
 void
@@ -79,26 +89,31 @@ ppcnbsd_fill_reg (char *regs, int regno)
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   int i;
 
-  for (i = 0; i <= 31; i++)
+  for (i = 0; i < ppc_num_gprs; i++)
     {
-      if (regno == i || regno == -1)
-       regcache_collect (i, regs + REG_FIXREG_OFFSET (i));
+      if (regno == tdep->ppc_gp0_regnum + i || regno == -1)
+       regcache_raw_collect (current_regcache, tdep->ppc_gp0_regnum + i,
+                             regs + REG_FIXREG_OFFSET (i));
     }
 
   if (regno == tdep->ppc_lr_regnum || regno == -1)
-    regcache_collect (tdep->ppc_lr_regnum, regs + REG_LR_OFFSET);
+    regcache_raw_collect (current_regcache, tdep->ppc_lr_regnum,
+                         regs + REG_LR_OFFSET);
 
   if (regno == tdep->ppc_cr_regnum || regno == -1)
-    regcache_collect (tdep->ppc_cr_regnum, regs + REG_CR_OFFSET);
+    regcache_raw_collect (current_regcache, tdep->ppc_cr_regnum,
+                         regs + REG_CR_OFFSET);
 
   if (regno == tdep->ppc_xer_regnum || regno == -1)
-    regcache_collect (tdep->ppc_xer_regnum, regs + REG_XER_OFFSET);
+    regcache_raw_collect (current_regcache, tdep->ppc_xer_regnum,
+                         regs + REG_XER_OFFSET);
 
   if (regno == tdep->ppc_ctr_regnum || regno == -1)
-    regcache_collect (tdep->ppc_ctr_regnum, regs + REG_CTR_OFFSET);
+    regcache_raw_collect (current_regcache, tdep->ppc_ctr_regnum,
+                         regs + REG_CTR_OFFSET);
 
   if (regno == PC_REGNUM || regno == -1)
-    regcache_collect (PC_REGNUM, regs + REG_PC_OFFSET);
+    regcache_raw_collect (current_regcache, PC_REGNUM, regs + REG_PC_OFFSET);
 }
 
 void
@@ -107,14 +122,28 @@ ppcnbsd_supply_fpreg (char *fpregs, int regno)
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   int i;
 
-  for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++)
+  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
+     point registers.  Traditionally, GDB's register set has still
+     listed the floating point registers for such machines, so this
+     code is harmless.  However, the new E500 port actually omits the
+     floating point registers entirely from the register set --- they
+     don't even have register numbers assigned to them.
+
+     It's not clear to me how best to update this code, so this assert
+     will alert the first person to encounter the NetBSD/E500
+     combination to the problem.  */
+  gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
+
+  for (i = 0; i < ppc_num_fprs; i++)
     {
-      if (regno == i || regno == -1)
-       supply_register (i, fpregs + FPREG_FPR_OFFSET (i - FP0_REGNUM));
+      if (regno == tdep->ppc_fp0_regnum + i || regno == -1)
+       regcache_raw_supply (current_regcache, tdep->ppc_fp0_regnum + i,
+                            fpregs + FPREG_FPR_OFFSET (i));
     }
 
   if (regno == tdep->ppc_fpscr_regnum || regno == -1)
-    supply_register (tdep->ppc_fpscr_regnum, fpregs + FPREG_FPSCR_OFFSET);
+    regcache_raw_supply (current_regcache, tdep->ppc_fpscr_regnum,
+                        fpregs + FPREG_FPSCR_OFFSET);
 }
 
 void
@@ -123,14 +152,28 @@ ppcnbsd_fill_fpreg (char *fpregs, int regno)
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   int i;
 
-  for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++)
+  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
+     point registers.  Traditionally, GDB's register set has still
+     listed the floating point registers for such machines, so this
+     code is harmless.  However, the new E500 port actually omits the
+     floating point registers entirely from the register set --- they
+     don't even have register numbers assigned to them.
+
+     It's not clear to me how best to update this code, so this assert
+     will alert the first person to encounter the NetBSD/E500
+     combination to the problem.  */
+  gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
+
+  for (i = 0; i < ppc_num_fprs; i++)
     {
-      if (regno == i || regno == -1)
-       regcache_collect (i, fpregs + FPREG_FPR_OFFSET (i - FP0_REGNUM));
+      if (regno == tdep->ppc_fp0_regnum + i || regno == -1)
+       regcache_raw_collect (current_regcache, tdep->ppc_fp0_regnum + i,
+                             fpregs + FPREG_FPR_OFFSET (i));
     }
 
   if (regno == tdep->ppc_fpscr_regnum || regno == -1)
-    regcache_collect (tdep->ppc_fpscr_regnum, fpregs + FPREG_FPSCR_OFFSET);
+    regcache_raw_collect (current_regcache, tdep->ppc_fpscr_regnum,
+                         fpregs + FPREG_FPSCR_OFFSET);
 }
 
 static void
@@ -161,14 +204,14 @@ fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
     {
     case 0:  /* Integer registers.  */
       if (core_reg_size != SIZEOF_STRUCT_REG)
-       warning ("Wrong size register set in core file.");
+       warning (_("Wrong size register set in core file."));
       else
        ppcnbsd_supply_reg (core_reg_sect, -1);
       break;
 
     case 2:  /* Floating point registers.  */
       if (core_reg_size != SIZEOF_STRUCT_FPREG)
-       warning ("Wrong size FP register set in core file.");
+       warning (_("Wrong size FP register set in core file."));
       else
        ppcnbsd_supply_fpreg (core_reg_sect, -1);
       break;
@@ -197,24 +240,93 @@ static struct core_fns ppcnbsd_elfcore_fns =
   NULL                                 /* next */
 };
 
-static int
-ppcnbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+/* NetBSD is confused.  It appears that 1.5 was using the correct SVr4
+   convention but, 1.6 switched to the below broken convention.  For
+   the moment use the broken convention.  Ulgh!.  */
+
+static enum return_value_convention
+ppcnbsd_return_value (struct gdbarch *gdbarch, struct type *valtype,
+                     struct regcache *regcache, gdb_byte *readbuf,
+                     const gdb_byte *writebuf)
 {
-  /* FIXME: Need to add support for kernel-provided signal trampolines.  */
-  return (nbsd_pc_in_sigtramp (pc, func_name));
+  if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+       || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+      && !((TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 8)
+           && TYPE_VECTOR (valtype))
+      && !(TYPE_LENGTH (valtype) == 1
+          || TYPE_LENGTH (valtype) == 2
+          || TYPE_LENGTH (valtype) == 4
+          || TYPE_LENGTH (valtype) == 8))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+  else
+    return ppc_sysv_abi_broken_return_value (gdbarch, valtype, regcache,
+                                            readbuf, writebuf);
 }
 
 static void
-ppcnbsd_init_abi (struct gdbarch_info info,
-                  struct gdbarch *gdbarch)
+ppcnbsd_sigtramp_cache_init (const struct tramp_frame *self,
+                            struct frame_info *next_frame,
+                            struct trad_frame_cache *this_cache,
+                            CORE_ADDR func)
 {
-  /* Stop at main.  */
-  set_gdbarch_frame_chain_valid (gdbarch, generic_func_frame_chain_valid);
+  CORE_ADDR base;
+  CORE_ADDR offset;
+  int i;
+  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+  offset = base + 0x18 + 2 * tdep->wordsize;
+  for (i = 0; i < ppc_num_gprs; i++)
+    {
+      int regnum = i + tdep->ppc_gp0_regnum;
+      trad_frame_set_reg_addr (this_cache, regnum, offset);
+      offset += tdep->wordsize;
+    }
+  trad_frame_set_reg_addr (this_cache, tdep->ppc_lr_regnum, offset);
+  offset += tdep->wordsize;
+  trad_frame_set_reg_addr (this_cache, tdep->ppc_cr_regnum, offset);
+  offset += tdep->wordsize;
+  trad_frame_set_reg_addr (this_cache, tdep->ppc_xer_regnum, offset);
+  offset += tdep->wordsize;
+  trad_frame_set_reg_addr (this_cache, tdep->ppc_ctr_regnum, offset);
+  offset += tdep->wordsize;
+  trad_frame_set_reg_addr (this_cache, PC_REGNUM, offset); /* SRR0? */
+  offset += tdep->wordsize;
+
+  /* Construct the frame ID using the function start.  */
+  trad_frame_set_id (this_cache, frame_id_build (base, func));
+}
 
-  set_gdbarch_pc_in_sigtramp (gdbarch, ppcnbsd_pc_in_sigtramp);
+/* Given the NEXT frame, examine the instructions at and around this
+   frame's resume address (aka PC) to see of they look like a signal
+   trampoline.  Return the address of the trampolines first
+   instruction, or zero if it isn't a signal trampoline.  */
+
+static const struct tramp_frame ppcnbsd_sigtramp = {
+  SIGTRAMP_FRAME,
+  4, /* insn size */
+  { /* insn */
+    { 0x38610018, -1 }, /* addi r3,r1,24 */
+    { 0x38000127, -1 }, /* li r0,295 */
+    { 0x44000002, -1 }, /* sc */
+    { 0x38000001, -1 }, /* li r0,1 */
+    { 0x44000002, -1 }, /* sc */
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  ppcnbsd_sigtramp_cache_init
+};
 
+static void
+ppcnbsd_init_abi (struct gdbarch_info info,
+                  struct gdbarch *gdbarch)
+{
+  /* For NetBSD, this is an on again, off again thing.  Some systems
+     do use the broken struct convention, and some don't.  */
+  set_gdbarch_return_value (gdbarch, ppcnbsd_return_value);
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
                                 nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
+  tramp_frame_prepend_unwinder (gdbarch, &ppcnbsd_sigtramp);
 }
 
 void
@@ -223,6 +335,6 @@ _initialize_ppcnbsd_tdep (void)
   gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_NETBSD_ELF,
                          ppcnbsd_init_abi);
 
-  add_core_fns (&ppcnbsd_core_fns);
-  add_core_fns (&ppcnbsd_elfcore_fns);
+  deprecated_add_core_fns (&ppcnbsd_core_fns);
+  deprecated_add_core_fns (&ppcnbsd_elfcore_fns);
 }
This page took 0.028025 seconds and 4 git commands to generate.