* rs6000-tdep.c (gdb_print_insn_powerpc): Get the current endianess
[deliverable/binutils-gdb.git] / gdb / rs6000-tdep.c
index f133b78823ab9113c8449dbb1a8de1f39e45e22d..fc12619a7b06ecec9da7e01845672681c0291402 100644 (file)
@@ -1,7 +1,7 @@
 /* Target-dependent code for GDB, the GNU debugger.
 
    Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -49,6 +49,7 @@
 #include "libxcoff.h"
 
 #include "elf-bfd.h"
+#include "elf/ppc.h"
 
 #include "solib-svr4.h"
 #include "ppc-tdep.h"
 #include "features/rs6000/powerpc-e500.c"
 #include "features/rs6000/rs6000.c"
 
+/* Determine if regnum is an SPE pseudo-register.  */
+#define IS_SPE_PSEUDOREG(tdep, regnum) ((tdep)->ppc_ev0_regnum >= 0 \
+    && (regnum) >= (tdep)->ppc_ev0_regnum \
+    && (regnum) < (tdep)->ppc_ev0_regnum + 32)
+
+/* Determine if regnum is a decimal float pseudo-register.  */
+#define IS_DFP_PSEUDOREG(tdep, regnum) ((tdep)->ppc_dl0_regnum >= 0 \
+    && (regnum) >= (tdep)->ppc_dl0_regnum \
+    && (regnum) < (tdep)->ppc_dl0_regnum + 16)
+
+/* The list of available "set powerpc ..." and "show powerpc ..."
+   commands.  */
+static struct cmd_list_element *setpowerpccmdlist = NULL;
+static struct cmd_list_element *showpowerpccmdlist = NULL;
+
+static enum auto_boolean powerpc_soft_float_global = AUTO_BOOLEAN_AUTO;
+
+/* The vector ABI to use.  Keep this in sync with powerpc_vector_abi.  */
+static const char *powerpc_vector_strings[] =
+{
+  "auto",
+  "generic",
+  "altivec",
+  "spe",
+  NULL
+};
+
+/* A variable that can be configured by the user.  */
+static enum powerpc_vector_abi powerpc_vector_abi_global = POWERPC_VEC_AUTO;
+static const char *powerpc_vector_abi_string = "auto";
+
 /* If the kernel has to deliver a signal, it pushes a sigcontext
    structure on the stack and then calls the signal handler, passing
    the address of the sigcontext in an argument register. Usually
@@ -135,14 +167,14 @@ CORE_ADDR (*rs6000_find_toc_address_hook) (CORE_ADDR) = NULL;
 
 static CORE_ADDR branch_dest (struct frame_info *frame, int opcode,
                              int instr, CORE_ADDR pc, CORE_ADDR safety);
-static CORE_ADDR skip_prologue (CORE_ADDR, CORE_ADDR,
+static CORE_ADDR skip_prologue (struct gdbarch *, CORE_ADDR, CORE_ADDR,
                                 struct rs6000_framedata *);
 
 /* Is REGNO an AltiVec register?  Return 1 if so, 0 otherwise.  */
 int
-altivec_register_p (int regno)
+altivec_register_p (struct gdbarch *gdbarch, int regno)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   if (tdep->ppc_vr0_regnum < 0 || tdep->ppc_vrsave_regnum < 0)
     return 0;
   else
@@ -152,14 +184,12 @@ altivec_register_p (int regno)
 
 /* Return true if REGNO is an SPE register, false otherwise.  */
 int
-spe_register_p (int regno)
+spe_register_p (struct gdbarch *gdbarch, int regno)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   
   /* Is it a reference to EV0 -- EV31, and do we have those?  */
-  if (tdep->ppc_ev0_regnum >= 0
-      && tdep->ppc_ev31_regnum >= 0
-      && tdep->ppc_ev0_regnum <= regno && regno <= tdep->ppc_ev31_regnum)
+  if (IS_SPE_PSEUDOREG (tdep, regno))
     return 1;
 
   /* Is it a reference to one of the raw upper GPR halves?  */
@@ -320,17 +350,17 @@ init_sim_regno_table (struct gdbarch *arch)
 /* Given a GDB register number REG, return the corresponding SIM
    register number.  */
 static int
-rs6000_register_sim_regno (int reg)
+rs6000_register_sim_regno (struct gdbarch *gdbarch, int reg)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   int sim_regno;
 
   if (tdep->sim_regno == NULL)
-    init_sim_regno_table (current_gdbarch);
+    init_sim_regno_table (gdbarch);
 
   gdb_assert (0 <= reg 
-             && reg <= gdbarch_num_regs (current_gdbarch)
-                       + gdbarch_num_pseudo_regs (current_gdbarch));
+             && reg <= gdbarch_num_regs (gdbarch)
+                       + gdbarch_num_pseudo_regs (gdbarch));
   sim_regno = tdep->sim_regno[reg];
 
   if (sim_regno >= 0)
@@ -732,7 +762,7 @@ read_memory_addr (CORE_ADDR memaddr, int len)
 }
 
 static CORE_ADDR
-rs6000_skip_prologue (CORE_ADDR pc)
+rs6000_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   struct rs6000_framedata frame;
   CORE_ADDR limit_pc, func_addr;
@@ -757,7 +787,7 @@ rs6000_skip_prologue (CORE_ADDR pc)
   if (limit_pc == 0)
     limit_pc = pc + 100;          /* Magic.  */
 
-  pc = skip_prologue (pc, limit_pc, &frame);
+  pc = skip_prologue (gdbarch, pc, limit_pc, &frame);
   return pc;
 }
 
@@ -943,12 +973,13 @@ branch_dest (struct frame_info *frame, int opcode, int instr,
 /* Sequence of bytes for breakpoint instruction.  */
 
 const static unsigned char *
-rs6000_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size)
+rs6000_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr,
+                          int *bp_size)
 {
   static unsigned char big_breakpoint[] = { 0x7d, 0x82, 0x10, 0x08 };
   static unsigned char little_breakpoint[] = { 0x08, 0x10, 0x82, 0x7d };
   *bp_size = 4;
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
     return big_breakpoint;
   else
     return little_breakpoint;
@@ -1057,7 +1088,8 @@ rs6000_software_single_step (struct frame_info *frame)
 {
   CORE_ADDR dummy;
   int breakp_sz;
-  const gdb_byte *breakp = rs6000_breakpoint_from_pc (&dummy, &breakp_sz);
+  const gdb_byte *breakp
+    = rs6000_breakpoint_from_pc (get_frame_arch (frame), &dummy, &breakp_sz);
   int ii, insn;
   CORE_ADDR loc;
   CORE_ADDR breaks[2];
@@ -1227,7 +1259,8 @@ bl_to_blrl_insn_p (CORE_ADDR pc, int insn)
  */
 
 static CORE_ADDR
-skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata)
+skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
+              struct rs6000_framedata *fdata)
 {
   CORE_ADDR orig_pc = pc;
   CORE_ADDR last_prologue_pc = pc;
@@ -1248,8 +1281,8 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata)
   int prev_insn_was_prologue_insn = 1;
   int num_skip_non_prologue_insns = 0;
   int r0_contains_arg = 0;
-  const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (current_gdbarch);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   memset (fdata, 0, sizeof (struct rs6000_framedata));
   fdata->saved_gpr = -1;
@@ -2333,9 +2366,9 @@ regsize (const struct reg *reg, int wordsize)
    is an anonymous register.  */
 
 static const char *
-rs6000_register_name (int regno)
+rs6000_register_name (struct gdbarch *gdbarch, int regno)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   /* The upper half "registers" have names in the XML description,
      but we present only the low GPRs and the full 64-bit registers
@@ -2346,9 +2379,7 @@ rs6000_register_name (int regno)
     return "";
 
   /* Check if the SPE pseudo registers are available.  */
-  if (tdep->ppc_ev0_regnum >= 0
-      && tdep->ppc_ev0_regnum <= regno
-      && regno < tdep->ppc_ev0_regnum + ppc_num_gprs)
+  if (IS_SPE_PSEUDOREG (tdep, regno))
     {
       static const char *const spe_regnames[] = {
        "ev0", "ev1", "ev2", "ev3", "ev4", "ev5", "ev6", "ev7",
@@ -2359,7 +2390,19 @@ rs6000_register_name (int regno)
       return spe_regnames[regno - tdep->ppc_ev0_regnum];
     }
 
-  return tdesc_register_name (regno);
+  /* Check if the decimal128 pseudo-registers are available.  */
+  if (IS_DFP_PSEUDOREG (tdep, regno))
+    {
+      static const char *const dfp128_regnames[] = {
+       "dl0", "dl1", "dl2", "dl3",
+       "dl4", "dl5", "dl6", "dl7",
+       "dl8", "dl9", "dl10", "dl11",
+       "dl12", "dl13", "dl14", "dl15"
+      };
+      return dfp128_regnames[regno - tdep->ppc_dl0_regnum];
+    }
+
+  return tdesc_register_name (gdbarch, regno);
 }
 
 /* Return the GDB type object for the "standard" data type of data in
@@ -2371,11 +2414,15 @@ rs6000_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   /* These are the only pseudo-registers we support.  */
-  gdb_assert (tdep->ppc_ev0_regnum >= 0
-             && regnum >= tdep->ppc_ev0_regnum
-             && regnum < tdep->ppc_ev0_regnum + 32);
+  gdb_assert (IS_SPE_PSEUDOREG (tdep, regnum)
+             || IS_DFP_PSEUDOREG (tdep, regnum));
 
-  return rs6000_builtin_type_vec64 (gdbarch);
+  /* These are the e500 pseudo-registers.  */
+  if (IS_SPE_PSEUDOREG (tdep, regnum))
+    return rs6000_builtin_type_vec64 (gdbarch);
+  else
+    /* Could only be the ppc decimal128 pseudo-registers.  */
+    return builtin_type (gdbarch)->builtin_declong;
 }
 
 /* Is REGNUM a member of REGGROUP?  */
@@ -2386,23 +2433,25 @@ rs6000_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   /* These are the only pseudo-registers we support.  */
-  gdb_assert (tdep->ppc_ev0_regnum >= 0
-             && regnum >= tdep->ppc_ev0_regnum
-             && regnum < tdep->ppc_ev0_regnum + 32);
+  gdb_assert (IS_SPE_PSEUDOREG (tdep, regnum)
+             || IS_DFP_PSEUDOREG (tdep, regnum));
 
-  if (group == all_reggroup || group == vector_reggroup)
-    return 1;
+  /* These are the e500 pseudo-registers.  */
+  if (IS_SPE_PSEUDOREG (tdep, regnum))
+    return group == all_reggroup || group == vector_reggroup;
   else
-    return 0;
+    /* Could only be the ppc decimal128 pseudo-registers.  */
+    return group == all_reggroup || group == float_reggroup;
 }
 
 /* The register format for RS/6000 floating point registers is always
    double, we need a conversion if the memory format is float.  */
 
 static int
-rs6000_convert_register_p (int regnum, struct type *type)
+rs6000_convert_register_p (struct gdbarch *gdbarch, int regnum,
+                          struct type *type)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   return (tdep->ppc_fp0_regnum >= 0
          && regnum >= tdep->ppc_fp0_regnum
@@ -2473,8 +2522,7 @@ e500_move_ev_register (void (*move) (struct regcache *regcache,
   int reg_index;
   gdb_byte *byte_buffer = buffer;
 
-  gdb_assert (tdep->ppc_ev0_regnum <= ev_reg
-              && ev_reg < tdep->ppc_ev0_regnum + ppc_num_gprs);
+  gdb_assert (IS_SPE_PSEUDOREG (tdep, ev_reg));
 
   reg_index = ev_reg - tdep->ppc_ev0_regnum;
 
@@ -2493,48 +2541,118 @@ e500_move_ev_register (void (*move) (struct regcache *regcache,
 static void
 e500_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
                           int reg_nr, gdb_byte *buffer)
+{
+  e500_move_ev_register (regcache_raw_read, regcache, reg_nr, buffer);
+}
+
+static void
+e500_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+                           int reg_nr, const gdb_byte *buffer)
+{
+  e500_move_ev_register ((void (*) (struct regcache *, int, gdb_byte *))
+                        regcache_raw_write,
+                        regcache, reg_nr, (gdb_byte *) buffer);
+}
+
+/* Read method for PPC pseudo-registers. Currently this is handling the
+   16 decimal128 registers that map into 16 pairs of FP registers.  */
+static void
+ppc_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+                          int reg_nr, gdb_byte *buffer)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int reg_index = reg_nr - tdep->ppc_dl0_regnum;
+
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    {
+      /* Read two FP registers to form a whole dl register.  */
+      regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+                        2 * reg_index, buffer);
+      regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+                        2 * reg_index + 1, buffer + 8);
+    }
+  else
+    {
+      regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+                        2 * reg_index + 1, buffer + 8);
+      regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+                        2 * reg_index, buffer);
+    }
+}
+
+/* Write method for PPC pseudo-registers. Currently this is handling the
+   16 decimal128 registers that map into 16 pairs of FP registers.  */
+static void
+ppc_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+                           int reg_nr, const gdb_byte *buffer)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int reg_index = reg_nr - tdep->ppc_dl0_regnum;
+
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    {
+      /* Write each half of the dl register into a separate
+      FP register.  */
+      regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+                         2 * reg_index, buffer);
+      regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+                         2 * reg_index + 1, buffer + 8);
+    }
+  else
+    {
+      regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+                         2 * reg_index + 1, buffer + 8);
+      regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+                         2 * reg_index, buffer);
+    }
+}
+
+static void
+rs6000_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+                            int reg_nr, gdb_byte *buffer)
 {
   struct gdbarch *regcache_arch = get_regcache_arch (regcache);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 
 
   gdb_assert (regcache_arch == gdbarch);
-  if (tdep->ppc_ev0_regnum <= reg_nr
-      && reg_nr < tdep->ppc_ev0_regnum + ppc_num_gprs)
-    e500_move_ev_register (regcache_raw_read, regcache, reg_nr, buffer);
+
+  if (IS_SPE_PSEUDOREG (tdep, reg_nr))
+    e500_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
+  else if (IS_DFP_PSEUDOREG (tdep, reg_nr))
+    ppc_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
   else
     internal_error (__FILE__, __LINE__,
-                    _("e500_pseudo_register_read: "
-                    "called on unexpected register '%s' (%d)"),
-                    gdbarch_register_name (gdbarch, reg_nr), reg_nr);
+                   _("rs6000_pseudo_register_read: "
+                   "called on unexpected register '%s' (%d)"),
+                   gdbarch_register_name (gdbarch, reg_nr), reg_nr);
 }
 
 static void
-e500_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
-                           int reg_nr, const gdb_byte *buffer)
+rs6000_pseudo_register_write (struct gdbarch *gdbarch,
+                             struct regcache *regcache,
+                             int reg_nr, const gdb_byte *buffer)
 {
   struct gdbarch *regcache_arch = get_regcache_arch (regcache);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 
 
   gdb_assert (regcache_arch == gdbarch);
-  if (tdep->ppc_ev0_regnum <= reg_nr
-      && reg_nr < tdep->ppc_ev0_regnum + ppc_num_gprs)
-    e500_move_ev_register ((void (*) (struct regcache *, int, gdb_byte *))
-                           regcache_raw_write,
-                           regcache, reg_nr, (gdb_byte *) buffer);
+
+  if (IS_SPE_PSEUDOREG (tdep, reg_nr))
+    e500_pseudo_register_write (gdbarch, regcache, reg_nr, buffer);
+  else if (IS_DFP_PSEUDOREG (tdep, reg_nr))
+    ppc_pseudo_register_write (gdbarch, regcache, reg_nr, buffer);
   else
     internal_error (__FILE__, __LINE__,
-                    _("e500_pseudo_register_read: "
-                    "called on unexpected register '%s' (%d)"),
-                    gdbarch_register_name (gdbarch, reg_nr), reg_nr);
+                   _("rs6000_pseudo_register_write: "
+                   "called on unexpected register '%s' (%d)"),
+                   gdbarch_register_name (gdbarch, reg_nr), reg_nr);
 }
 
 /* Convert a DBX STABS register number to a GDB register number.  */
 static int
-rs6000_stab_reg_to_regnum (int num)
+rs6000_stab_reg_to_regnum (struct gdbarch *gdbarch, int num)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   if (0 <= num && num <= 31)
     return tdep->ppc_gp0_regnum + num;
@@ -2574,9 +2692,9 @@ rs6000_stab_reg_to_regnum (int num)
 
 /* Convert a Dwarf 2 register number to a GDB register number.  */
 static int
-rs6000_dwarf2_reg_to_regnum (int num)
+rs6000_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   if (0 <= num && num <= 31)
     return tdep->ppc_gp0_regnum + num;
@@ -2811,7 +2929,7 @@ gdb_print_insn_powerpc (bfd_vma memaddr, disassemble_info *info)
   if (!info->disassembler_options)
     info->disassembler_options = "any";
 
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (info->endian == BFD_ENDIAN_BIG)
     return print_insn_big_powerpc (memaddr, info);
   else
     return print_insn_little_powerpc (memaddr, info);
@@ -2857,7 +2975,7 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache)
 
   func = frame_func_unwind (next_frame, NORMAL_FRAME);
   pc = frame_pc_unwind (next_frame);
-  skip_prologue (func, pc, &fdata);
+  skip_prologue (gdbarch, func, pc, &fdata);
 
   /* Figure out the parent's stack pointer.  */
 
@@ -2960,7 +3078,7 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache)
 
   /* if != -1, fdata.saved_ev is the smallest number of saved_ev.
      All vr's from saved_ev to ev31 are saved. ????? */
-  if (tdep->ppc_ev0_regnum != -1 && tdep->ppc_ev31_regnum != -1)
+  if (tdep->ppc_ev0_regnum != -1)
     {
       if (fdata.saved_ev >= 0)
        {
@@ -3120,9 +3238,9 @@ ppc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
     }
 
   /* Handle PC register and Stack Pointer correctly.  */
-  if (regnum == gdbarch_pc_regnum (current_gdbarch))
+  if (regnum == gdbarch_pc_regnum (gdbarch))
     reg->how = DWARF2_FRAME_REG_RA;
-  else if (regnum == gdbarch_sp_regnum (current_gdbarch))
+  else if (regnum == gdbarch_sp_regnum (gdbarch))
     reg->how = DWARF2_FRAME_REG_CFA;
 }
 
@@ -3145,11 +3263,14 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   bfd abfd;
   int sysv_abi;
   asection *sect;
-  int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0;
+  enum auto_boolean soft_float_flag = powerpc_soft_float_global;
+  int soft_float;
+  enum powerpc_vector_abi vector_abi = powerpc_vector_abi_global;
+  int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0, have_dfp = 0;
   int tdesc_wordsize = -1;
   const struct target_desc *tdesc = info.target_desc;
   struct tdesc_arch_data *tdesc_data = NULL;
-  int num_sprs = 0;
+  int num_pseudoregs = 0;
 
   from_xcoff_exec = info.abfd && info.abfd->format == bfd_object &&
     bfd_get_flavour (info.abfd) == bfd_target_xcoff_flavour;
@@ -3320,6 +3441,10 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       else
        have_fpu = 0;
 
+      /* The DFP pseudo-registers will be available when there are floating
+         point registers.  */
+      have_dfp = have_fpu;
+
       feature = tdesc_find_feature (tdesc,
                                    "org.gnu.gdb.power.altivec");
       if (feature != NULL)
@@ -3417,6 +3542,76 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       return NULL;
     }
 
+#ifdef HAVE_ELF
+  if (soft_float_flag == AUTO_BOOLEAN_AUTO && from_elf_exec)
+    {
+      switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU,
+                                       Tag_GNU_Power_ABI_FP))
+       {
+       case 1:
+         soft_float_flag = AUTO_BOOLEAN_FALSE;
+         break;
+       case 2:
+         soft_float_flag = AUTO_BOOLEAN_TRUE;
+         break;
+       default:
+         break;
+       }
+    }
+
+  if (vector_abi == POWERPC_VEC_AUTO && from_elf_exec)
+    {
+      switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU,
+                                       Tag_GNU_Power_ABI_Vector))
+       {
+       case 1:
+         vector_abi = POWERPC_VEC_GENERIC;
+         break;
+       case 2:
+         vector_abi = POWERPC_VEC_ALTIVEC;
+         break;
+       case 3:
+         vector_abi = POWERPC_VEC_SPE;
+         break;
+       default:
+         break;
+       }
+    }
+#endif
+
+  if (soft_float_flag == AUTO_BOOLEAN_TRUE)
+    soft_float = 1;
+  else if (soft_float_flag == AUTO_BOOLEAN_FALSE)
+    soft_float = 0;
+  else
+    soft_float = !have_fpu;
+
+  /* If we have a hard float binary or setting but no floating point
+     registers, downgrade to soft float anyway.  We're still somewhat
+     useful in this scenario.  */
+  if (!soft_float && !have_fpu)
+    soft_float = 1;
+
+  /* Similarly for vector registers.  */
+  if (vector_abi == POWERPC_VEC_ALTIVEC && !have_altivec)
+    vector_abi = POWERPC_VEC_GENERIC;
+
+  if (vector_abi == POWERPC_VEC_SPE && !have_spe)
+    vector_abi = POWERPC_VEC_GENERIC;
+
+  if (vector_abi == POWERPC_VEC_AUTO)
+    {
+      if (have_altivec)
+       vector_abi = POWERPC_VEC_ALTIVEC;
+      else if (have_spe)
+       vector_abi = POWERPC_VEC_SPE;
+      else
+       vector_abi = POWERPC_VEC_GENERIC;
+    }
+
+  /* Do not limit the vector ABI based on available hardware, since we
+     do not yet know what hardware we'll decide we have.  Yuck!  FIXME!  */
+
   /* Find a candidate among extant architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
        arches != NULL;
@@ -3426,6 +3621,10 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
          meaningful, because 64-bit CPUs can run in 32-bit mode.  So, perform
          separate word size check.  */
       tdep = gdbarch_tdep (arches->gdbarch);
+      if (tdep && tdep->soft_float != soft_float)
+       continue;
+      if (tdep && tdep->vector_abi != vector_abi)
+       continue;
       if (tdep && tdep->wordsize == wordsize)
        {
          if (tdesc_data != NULL)
@@ -3444,6 +3643,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   tdep = XCALLOC (1, struct gdbarch_tdep);
   tdep->wordsize = wordsize;
+  tdep->soft_float = soft_float;
+  tdep->vector_abi = vector_abi;
 
   gdbarch = gdbarch_alloc (&info, tdep);
 
@@ -3490,10 +3691,10 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   else
     tdep->lr_frame_offset = 8;
 
-  if (have_spe)
+  if (have_spe || have_dfp)
     {
-      set_gdbarch_pseudo_register_read (gdbarch, e500_pseudo_register_read);
-      set_gdbarch_pseudo_register_write (gdbarch, e500_pseudo_register_write);
+      set_gdbarch_pseudo_register_read (gdbarch, rs6000_pseudo_register_read);
+      set_gdbarch_pseudo_register_write (gdbarch, rs6000_pseudo_register_write);
     }
 
   set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
@@ -3504,8 +3705,14 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   else
     set_gdbarch_print_insn (gdbarch, gdb_print_insn_powerpc);
 
-  set_gdbarch_num_regs (gdbarch, PPC_NUM_REGS + num_sprs);
-  set_gdbarch_num_pseudo_regs (gdbarch, have_spe ? 32 : 0);
+  set_gdbarch_num_regs (gdbarch, PPC_NUM_REGS);
+
+  if (have_spe)
+    num_pseudoregs += 32;
+  if (have_dfp)
+    num_pseudoregs += 16;
+
+  set_gdbarch_num_pseudo_regs (gdbarch, num_pseudoregs);
 
   set_gdbarch_ptr_bit (gdbarch, wordsize * TARGET_CHAR_BIT);
   set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
@@ -3627,7 +3834,13 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Recording the numbering of pseudo registers.  */
   tdep->ppc_ev0_regnum = have_spe ? gdbarch_num_regs (gdbarch) : -1;
-  tdep->ppc_ev31_regnum = have_spe ? tdep->ppc_ev0_regnum + 31 : -1;
+
+  /* Set the register number for _Decimal128 pseudo-registers.  */
+  tdep->ppc_dl0_regnum = have_dfp? gdbarch_num_regs (gdbarch) : -1;
+
+  if (have_dfp && have_spe)
+    /* Put the _Decimal128 pseudo-registers after the SPE registers.  */
+    tdep->ppc_dl0_regnum += 32;
 
   return gdbarch;
 }
@@ -3643,6 +3856,61 @@ rs6000_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
   /* FIXME: Dump gdbarch_tdep.  */
 }
 
+/* PowerPC-specific commands.  */
+
+static void
+set_powerpc_command (char *args, int from_tty)
+{
+  printf_unfiltered (_("\
+\"set powerpc\" must be followed by an appropriate subcommand.\n"));
+  help_list (setpowerpccmdlist, "set powerpc ", all_commands, gdb_stdout);
+}
+
+static void
+show_powerpc_command (char *args, int from_tty)
+{
+  cmd_show_list (showpowerpccmdlist, from_tty, "");
+}
+
+static void
+powerpc_set_soft_float (char *args, int from_tty,
+                       struct cmd_list_element *c)
+{
+  struct gdbarch_info info;
+
+  /* Update the architecture.  */
+  gdbarch_info_init (&info);
+  if (!gdbarch_update_p (info))
+    internal_error (__FILE__, __LINE__, "could not update architecture");
+}
+
+static void
+powerpc_set_vector_abi (char *args, int from_tty,
+                       struct cmd_list_element *c)
+{
+  struct gdbarch_info info;
+  enum powerpc_vector_abi vector_abi;
+
+  for (vector_abi = POWERPC_VEC_AUTO;
+       vector_abi != POWERPC_VEC_LAST;
+       vector_abi++)
+    if (strcmp (powerpc_vector_abi_string,
+               powerpc_vector_strings[vector_abi]) == 0)
+      {
+       powerpc_vector_abi_global = vector_abi;
+       break;
+      }
+
+  if (vector_abi == POWERPC_VEC_LAST)
+    internal_error (__FILE__, __LINE__, _("Invalid vector ABI accepted: %s."),
+                   powerpc_vector_abi_string);
+
+  /* Update the architecture.  */
+  gdbarch_info_init (&info);
+  if (!gdbarch_update_p (info))
+    internal_error (__FILE__, __LINE__, "could not update architecture");
+}
+
 /* Initialization code.  */
 
 extern initialize_file_ftype _initialize_rs6000_tdep; /* -Wmissing-prototypes */
@@ -3668,4 +3936,30 @@ _initialize_rs6000_tdep (void)
   initialize_tdesc_powerpc_860 ();
   initialize_tdesc_powerpc_e500 ();
   initialize_tdesc_rs6000 ();
+
+  /* Add root prefix command for all "set powerpc"/"show powerpc"
+     commands.  */
+  add_prefix_cmd ("powerpc", no_class, set_powerpc_command,
+                 _("Various PowerPC-specific commands."),
+                 &setpowerpccmdlist, "set powerpc ", 0, &setlist);
+
+  add_prefix_cmd ("powerpc", no_class, show_powerpc_command,
+                 _("Various PowerPC-specific commands."),
+                 &showpowerpccmdlist, "show powerpc ", 0, &showlist);
+
+  /* Add a command to allow the user to force the ABI.  */
+  add_setshow_auto_boolean_cmd ("soft-float", class_support,
+                               &powerpc_soft_float_global,
+                               _("Set whether to use a soft-float ABI."),
+                               _("Show whether to use a soft-float ABI."),
+                               NULL,
+                               powerpc_set_soft_float, NULL,
+                               &setpowerpccmdlist, &showpowerpccmdlist);
+
+  add_setshow_enum_cmd ("vector-abi", class_support, powerpc_vector_strings,
+                       &powerpc_vector_abi_string,
+                       _("Set the vector ABI."),
+                       _("Show the vector ABI."),
+                       NULL, powerpc_set_vector_abi, NULL,
+                       &setpowerpccmdlist, &showpowerpccmdlist);
 }
This page took 0.033833 seconds and 4 git commands to generate.