*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 648cc3acbafc6890a522259a578d0ac6952efb8b..7e94f208648fb33b8edfbdf205221857d4a52ad7 100644 (file)
@@ -1,7 +1,7 @@
 /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
 
    Copyright (C) 1988, 1989, 1990, 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.
 
    Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
@@ -199,38 +199,6 @@ struct gdbarch_tdep
   int register_size;
 };
 
-static int
-n32n64_floatformat_always_valid (const struct floatformat *fmt,
-                                 const void *from)
-{
-  return 1;
-}
-
-/* FIXME: brobecker/2004-08-08: Long Double values are 128 bit long.
-   They are implemented as a pair of 64bit doubles where the high
-   part holds the result of the operation rounded to double, and
-   the low double holds the difference between the exact result and
-   the rounded result.  So "high" + "low" contains the result with
-   added precision.  Unfortunately, the floatformat structure used
-   by GDB is not powerful enough to describe this format.  As a temporary
-   measure, we define a 128bit floatformat that only uses the high part.
-   We lose a bit of precision but that's probably the best we can do
-   for now with the current infrastructure.  */
-
-static const struct floatformat floatformat_n32n64_long_double_big =
-{
-  floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
-  floatformat_intbit_no,
-  "floatformat_n32n64_long_double_big",
-  n32n64_floatformat_always_valid
-};
-
-static const struct floatformat *floatformats_n32n64_long[BFD_ENDIAN_UNKNOWN] =
-{
-  &floatformat_n32n64_long_double_big,
-  &floatformat_n32n64_long_double_big
-};
-
 const struct mips_regnum *
 mips_regnum (struct gdbarch *gdbarch)
 {
@@ -493,9 +461,9 @@ static const char *mips_irix_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
 
 /* Return the name of the register corresponding to REGNO.  */
 static const char *
-mips_register_name (int regno)
+mips_register_name (struct gdbarch *gdbarch, int regno)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   /* GPR names for all ABIs other than n32/n64.  */
   static char *mips_gpr_names[] = {
     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
@@ -512,12 +480,12 @@ mips_register_name (int regno)
     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
   };
 
-  enum mips_abi abi = mips_abi (current_gdbarch);
+  enum mips_abi abi = mips_abi (gdbarch);
 
   /* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers, 
      but then don't make the raw register names visible.  */
-  int rawnum = regno % gdbarch_num_regs (current_gdbarch);
-  if (regno < gdbarch_num_regs (current_gdbarch))
+  int rawnum = regno % gdbarch_num_regs (gdbarch);
+  if (regno < gdbarch_num_regs (gdbarch))
     return "";
 
   /* The MIPS integer registers are always mapped from 0 to 31.  The
@@ -530,9 +498,9 @@ mips_register_name (int regno)
       else
        return mips_gpr_names[rawnum];
     }
-  else if (tdesc_has_registers (gdbarch_target_desc (current_gdbarch)))
-    return tdesc_register_name (rawnum);
-  else if (32 <= rawnum && rawnum < gdbarch_num_regs (current_gdbarch))
+  else if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return tdesc_register_name (gdbarch, rawnum);
+  else if (32 <= rawnum && rawnum < gdbarch_num_regs (gdbarch))
     {
       gdb_assert (rawnum - 32 < NUM_MIPS_PROCESSOR_REGS);
       return tdep->mips_processor_reg_names[rawnum - 32];
@@ -692,14 +660,14 @@ set_mips64_transfers_32bit_regs (char *args, int from_tty,
 /* Convert to/from a register and the corresponding memory value.  */
 
 static int
-mips_convert_register_p (int regnum, struct type *type)
-{
-  return (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
-         && register_size (current_gdbarch, regnum) == 4
-         && (regnum % gdbarch_num_regs (current_gdbarch))
-               >= mips_regnum (current_gdbarch)->fp0
-         && (regnum % gdbarch_num_regs (current_gdbarch))
-               < mips_regnum (current_gdbarch)->fp0 + 32
+mips_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type)
+{
+  return (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
+         && register_size (gdbarch, regnum) == 4
+         && (regnum % gdbarch_num_regs (gdbarch))
+               >= mips_regnum (gdbarch)->fp0
+         && (regnum % gdbarch_num_regs (gdbarch))
+               < mips_regnum (gdbarch)->fp0 + 32
          && TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8);
 }
 
@@ -1183,7 +1151,7 @@ struct upk_mips16
 
 
 /* The EXT-I, EXT-ri nad EXT-I8 instructions all have the same format
-   for the bits which make up the immediatate extension.  */
+   for the bits which make up the immediate extension.  */
 
 static CORE_ADDR
 extended_offset (unsigned int extension)
@@ -1532,6 +1500,7 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   unsigned short prev_inst = 0;        /* saved copy of previous instruction */
   unsigned inst = 0;           /* current instruction */
   unsigned entry_inst = 0;     /* the entry instruction */
+  unsigned save_inst = 0;      /* the save instruction */
   int reg, offset;
 
   int extend_bytes = 0;
@@ -1635,6 +1604,12 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
       else if ((inst & 0xf81f) == 0xe809
                && (inst & 0x700) != 0x700)     /* entry */
        entry_inst = inst;      /* save for later processing */
+      else if ((inst & 0xff80) == 0x6480)      /* save */
+       {
+         save_inst = inst;     /* save for later processing */
+         if (prev_extend_bytes)                /* extend */
+           save_inst |= prev_inst << 16;
+       }
       else if ((inst & 0xf800) == 0x1800)      /* jal(x) */
        cur_pc += MIPS_INSN16_SIZE;     /* 32-bit instruction */
       else if ((inst & 0xff1c) == 0x6704)      /* move reg,$a0-$a3 */
@@ -1693,6 +1668,101 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
        }
     }
 
+  /* The SAVE instruction is similar to ENTRY, except that defined by the
+     MIPS16e ASE of the MIPS Architecture.  Unlike with ENTRY though, the
+     size of the frame is specified as an immediate field of instruction
+     and an extended variation exists which lets additional registers and
+     frame space to be specified.  The instruction always treats registers
+     as 32-bit so its usefulness for 64-bit ABIs is questionable.  */
+  if (save_inst != 0 && mips_abi_regsize (gdbarch) == 4)
+    {
+      static int args_table[16] = {
+       0, 0, 0, 0, 1, 1, 1, 1,
+       2, 2, 2, 0, 3, 3, 4, -1,
+      };
+      static int astatic_table[16] = {
+       0, 1, 2, 3, 0, 1, 2, 3,
+       0, 1, 2, 4, 0, 1, 0, -1,
+      };
+      int aregs = (save_inst >> 16) & 0xf;
+      int xsregs = (save_inst >> 24) & 0x7;
+      int args = args_table[aregs];
+      int astatic = astatic_table[aregs];
+      long frame_size;
+
+      if (args < 0)
+       {
+         warning (_("Invalid number of argument registers encoded in SAVE."));
+         args = 0;
+       }
+      if (astatic < 0)
+       {
+         warning (_("Invalid number of static registers encoded in SAVE."));
+         astatic = 0;
+       }
+
+      /* For standard SAVE the frame size of 0 means 128.  */
+      frame_size = ((save_inst >> 16) & 0xf0) | (save_inst & 0xf);
+      if (frame_size == 0 && (save_inst >> 16) == 0)
+       frame_size = 16;
+      frame_size *= 8;
+      frame_offset += frame_size;
+
+      /* Now we can calculate what the SP must have been at the
+         start of the function prologue.  */
+      sp += frame_offset;
+
+      /* Check if A0-A3 were saved in the caller's argument save area.  */
+      for (reg = MIPS_A0_REGNUM, offset = 0; reg < args + 4; reg++)
+       {
+         set_reg_offset (this_cache, reg, sp + offset);
+         offset += mips_abi_regsize (gdbarch);
+       }
+
+      offset = -4;
+
+      /* Check if the RA register was pushed on the stack.  */
+      if (save_inst & 0x40)
+       {
+         set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
+         offset -= mips_abi_regsize (gdbarch);
+       }
+
+      /* Check if the S8 register was pushed on the stack.  */
+      if (xsregs > 6)
+       {
+         set_reg_offset (this_cache, 30, sp + offset);
+         offset -= mips_abi_regsize (gdbarch);
+         xsregs--;
+       }
+      /* Check if S2-S7 were pushed on the stack.  */
+      for (reg = 18 + xsregs - 1; reg > 18 - 1; reg--)
+       {
+         set_reg_offset (this_cache, reg, sp + offset);
+         offset -= mips_abi_regsize (gdbarch);
+       }
+
+      /* Check if the S1 register was pushed on the stack.  */
+      if (save_inst & 0x10)
+       {
+         set_reg_offset (this_cache, 17, sp + offset);
+         offset -= mips_abi_regsize (gdbarch);
+       }
+      /* Check if the S0 register was pushed on the stack.  */
+      if (save_inst & 0x20)
+       {
+         set_reg_offset (this_cache, 16, sp + offset);
+         offset -= mips_abi_regsize (gdbarch);
+       }
+
+      /* Check if A0-A3 were pushed on the stack.  */
+      for (reg = MIPS_A0_REGNUM + 3; reg > MIPS_A0_REGNUM + 3 - astatic; reg--)
+       {
+         set_reg_offset (this_cache, reg, sp + offset);
+         offset -= mips_abi_regsize (gdbarch);
+       }
+    }
+
   if (this_cache != NULL)
     {
       this_cache->base =
@@ -3114,8 +3184,21 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                 purpose register.  */
              if (argreg <= MIPS_LAST_ARG_REGNUM)
                {
-                 LONGEST regval =
-                   extract_unsigned_integer (val, partial_len);
+                 LONGEST regval;
+
+                 /* Sign extend pointers, 32-bit integers and signed
+                    16-bit and 8-bit integers; everything else is taken
+                    as is.  */
+
+                 if ((partial_len == 4
+                      && (typecode == TYPE_CODE_PTR
+                          || typecode == TYPE_CODE_INT))
+                     || (partial_len < 4
+                         && typecode == TYPE_CODE_INT
+                         && !TYPE_UNSIGNED (arg_type)))
+                   regval = extract_signed_integer (val, partial_len);
+                 else
+                   regval = extract_unsigned_integer (val, partial_len);
 
                  /* A non-floating-point argument being passed in a
                     general register.  If a struct or union, and if
@@ -4500,7 +4583,7 @@ mips_single_step_through_delay (struct gdbarch *gdbarch,
    delay slot of a non-prologue instruction).  */
 
 static CORE_ADDR
-mips_skip_prologue (CORE_ADDR pc)
+mips_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   CORE_ADDR limit_pc;
   CORE_ADDR func_addr;
@@ -4643,6 +4726,15 @@ static void
 show_mipsfpu_command (char *args, int from_tty)
 {
   char *fpu;
+
+  if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
+    {
+      printf_unfiltered
+       ("The MIPS floating-point coprocessor is unknown "
+        "because the current architecture is not MIPS.\n");
+      return;
+    }
+
   switch (MIPS_FPU_TYPE)
     {
     case MIPS_FPU_SINGLE:
@@ -4800,9 +4892,9 @@ gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
    should be inserted.  */
 
 static const gdb_byte *
-mips_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+mips_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
 {
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
     {
       if (mips_pc_is_mips16 (*pcptr))
        {
@@ -4961,23 +5053,22 @@ mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
    [1 * gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM.  */
 
 static int
-mips_stab_reg_to_regnum (int num)
+mips_stab_reg_to_regnum (struct gdbarch *gdbarch, int num)
 {
   int regnum;
   if (num >= 0 && num < 32)
     regnum = num;
   else if (num >= 38 && num < 70)
-    regnum = num + mips_regnum (current_gdbarch)->fp0 - 38;
+    regnum = num + mips_regnum (gdbarch)->fp0 - 38;
   else if (num == 70)
-    regnum = mips_regnum (current_gdbarch)->hi;
+    regnum = mips_regnum (gdbarch)->hi;
   else if (num == 71)
-    regnum = mips_regnum (current_gdbarch)->lo;
+    regnum = mips_regnum (gdbarch)->lo;
   else
     /* This will hopefully (eventually) provoke a warning.  Should
        we be calling complaint() here?  */
-    return gdbarch_num_regs (current_gdbarch)
-          + gdbarch_num_pseudo_regs (current_gdbarch);
-  return gdbarch_num_regs (current_gdbarch) + regnum;
+    return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+  return gdbarch_num_regs (gdbarch) + regnum;
 }
 
 
@@ -4985,39 +5076,36 @@ mips_stab_reg_to_regnum (int num)
    gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM.  */
 
 static int
-mips_dwarf_dwarf2_ecoff_reg_to_regnum (int num)
+mips_dwarf_dwarf2_ecoff_reg_to_regnum (struct gdbarch *gdbarch, int num)
 {
   int regnum;
   if (num >= 0 && num < 32)
     regnum = num;
   else if (num >= 32 && num < 64)
-    regnum = num + mips_regnum (current_gdbarch)->fp0 - 32;
+    regnum = num + mips_regnum (gdbarch)->fp0 - 32;
   else if (num == 64)
-    regnum = mips_regnum (current_gdbarch)->hi;
+    regnum = mips_regnum (gdbarch)->hi;
   else if (num == 65)
-    regnum = mips_regnum (current_gdbarch)->lo;
+    regnum = mips_regnum (gdbarch)->lo;
   else
     /* This will hopefully (eventually) provoke a warning.  Should we
        be calling complaint() here?  */
-    return gdbarch_num_regs (current_gdbarch)
-          + gdbarch_num_pseudo_regs (current_gdbarch);
-  return gdbarch_num_regs (current_gdbarch) + regnum;
+    return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+  return gdbarch_num_regs (gdbarch) + regnum;
 }
 
 static int
-mips_register_sim_regno (int regnum)
+mips_register_sim_regno (struct gdbarch *gdbarch, int regnum)
 {
   /* Only makes sense to supply raw registers.  */
-  gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch));
+  gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch));
   /* FIXME: cagney/2002-05-13: Need to look at the pseudo register to
      decide if it is valid.  Should instead define a standard sim/gdb
      register numbering scheme.  */
-  if (gdbarch_register_name (current_gdbarch,
-                            gdbarch_num_regs
-                              (current_gdbarch) + regnum) != NULL
-      && gdbarch_register_name (current_gdbarch,
-                               gdbarch_num_regs
-                                 (current_gdbarch) + regnum)[0] != '\0')
+  if (gdbarch_register_name (gdbarch,
+                            gdbarch_num_regs (gdbarch) + regnum) != NULL
+      && gdbarch_register_name (gdbarch,
+                               gdbarch_num_regs (gdbarch) + regnum)[0] != '\0')
     return regnum;
   else
     return LEGACY_SIM_REGNO_IGNORE;
@@ -5040,7 +5128,8 @@ mips_integer_to_address (struct gdbarch *gdbarch,
    an assertion failure.  */
 
 static void
-mips_virtual_frame_pointer (CORE_ADDR pc, int *reg, LONGEST *offset)
+mips_virtual_frame_pointer (struct gdbarch *gdbarch, 
+                           CORE_ADDR pc, int *reg, LONGEST *offset)
 {
   *reg = MIPS_SP_REGNUM;
   *offset = 0;
@@ -5584,7 +5673,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_ptr_bit (gdbarch, 32);
       set_gdbarch_long_long_bit (gdbarch, 64);
       set_gdbarch_long_double_bit (gdbarch, 128);
-      set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
       break;
     case MIPS_ABI_N64:
       set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
@@ -5596,7 +5685,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_ptr_bit (gdbarch, 64);
       set_gdbarch_long_long_bit (gdbarch, 64);
       set_gdbarch_long_double_bit (gdbarch, 128);
-      set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
       break;
     default:
       internal_error (__FILE__, __LINE__, _("unknown ABI in switch"));
This page took 0.028686 seconds and 4 git commands to generate.