Update email address.
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 3ef2fc0ad5d783ec70c186411ea4c545f81472b4..acd4991102416650310223164c10b64f05829fec 100644 (file)
@@ -11,7 +11,7 @@
 
    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,
@@ -20,9 +20,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., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "gdb_string.h"
@@ -167,6 +165,9 @@ static int mips_debug = 0;
 #define PROPERTY_GP32 "internal: transfers-32bit-registers"
 #define PROPERTY_GP64 "internal: transfers-64bit-registers"
 
+struct target_desc *mips_tdesc_gp32;
+struct target_desc *mips_tdesc_gp64;
+
 /* MIPS specific per-architecture information */
 struct gdbarch_tdep
 {
@@ -1198,13 +1199,11 @@ extended_offset (unsigned int extension)
 }
 
 /* Only call this function if you know that this is an extendable
-   instruction, It wont malfunction, but why make excess remote memory references?
-   If the immediate operands get sign extended or somthing, do it after
-   the extension is performed.
- */
+   instruction.  It won't malfunction, but why make excess remote memory
+   references?  If the immediate operands get sign extended or something,
+   do it after the extension is performed.  */
 /* FIXME: Every one of these cases needs to worry about sign extension
-   when the offset is to be used in relative addressing */
-
+   when the offset is to be used in relative addressing.  */
 
 static unsigned int
 fetch_mips_16 (CORE_ADDR pc)
@@ -1437,11 +1436,11 @@ mips16_next_pc (struct frame_info *frame, CORE_ADDR pc)
    target monitor or stub is not developed enough to do a single_step.
    It works by decoding the current instruction and predicting where a
    branch will go. This isnt hard because all the data is available.
-   The MIPS32 and MIPS16 variants are quite different */
+   The MIPS32 and MIPS16 variants are quite different */
 static CORE_ADDR
 mips_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
-  if (pc & 0x01)
+  if (is_mips16_addr (pc))
     return mips16_next_pc (frame, pc);
   else
     return mips32_next_pc (frame, pc);
@@ -1751,7 +1750,7 @@ mips_insn16_frame_cache (struct frame_info *next_frame, void **this_cache)
     mips16_scan_prologue (start_addr, pc, next_frame, *this_cache);
   }
   
-  /* SP_REGNUM, contains the value and not the address.  */
+  /* gdbarch_sp_regnum contains the value and not the address.  */
   trad_frame_set_value (cache->saved_regs, gdbarch_num_regs (current_gdbarch)
                                           + MIPS_SP_REGNUM, cache->base);
 
@@ -2086,7 +2085,7 @@ mips_insn32_frame_cache (struct frame_info *next_frame, void **this_cache)
     mips32_scan_prologue (start_addr, pc, next_frame, *this_cache);
   }
   
-  /* SP_REGNUM, contains the value and not the address.  */
+  /* gdbarch_sp_regnum contains the value and not the address.  */
   trad_frame_set_value (cache->saved_regs,
                        gdbarch_num_regs (current_gdbarch) + MIPS_SP_REGNUM,
                        cache->base);
@@ -2173,7 +2172,9 @@ mips_stub_frame_cache (struct frame_info *next_frame, void **this_cache)
   (*this_cache) = this_trad_cache;
 
   /* The return address is in the link register.  */
-  trad_frame_set_reg_realreg (this_trad_cache, PC_REGNUM, MIPS_RA_REGNUM);
+  trad_frame_set_reg_realreg (this_trad_cache,
+                             gdbarch_pc_regnum (current_gdbarch),
+                             MIPS_RA_REGNUM);
 
   /* Frame ID, since it's a frameless / stackless function, no stack
      space is allocated and SP on entry is the current SP.  */
@@ -2396,15 +2397,28 @@ heuristic-fence-post' command.\n", paddr_nz (pc), paddr_nz (pc));
 
        /* On MIPS16, any one of the following is likely to be the
           start of a function:
+          extend save
+          save
           entry
           addiu sp,-n
           daddiu sp,-n
           extend -n followed by 'addiu sp,+n' or 'daddiu sp,+n'  */
        inst = mips_fetch_instruction (start_pc);
-       if (((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700)      /* entry */
-           || (inst & 0xff80) == 0x6380        /* addiu sp,-n */
-           || (inst & 0xff80) == 0xfb80        /* daddiu sp,-n */
-           || ((inst & 0xf810) == 0xf010 && seen_adjsp))       /* extend -n */
+       if ((inst & 0xff80) == 0x6480)          /* save */
+         {
+           if (start_pc - instlen >= fence)
+             {
+               inst = mips_fetch_instruction (start_pc - instlen);
+               if ((inst & 0xf800) == 0xf000)  /* extend */
+                 start_pc -= instlen;
+             }
+           break;
+         }
+       else if (((inst & 0xf81f) == 0xe809
+                 && (inst & 0x700) != 0x700)   /* entry */
+                || (inst & 0xff80) == 0x6380   /* addiu sp,-n */
+                || (inst & 0xff80) == 0xfb80   /* daddiu sp,-n */
+                || ((inst & 0xf810) == 0xf010 && seen_adjsp))  /* extend -n */
          break;
        else if ((inst & 0xff00) == 0x6300      /* addiu sp */
                 || (inst & 0xff00) == 0xfb00)  /* daddiu sp */
@@ -2768,6 +2782,59 @@ mips_eabi_return_value (struct gdbarch *gdbarch,
 
 /* N32/N64 ABI stuff.  */
 
+/* Search for a naturally aligned double at OFFSET inside a struct
+   ARG_TYPE.  The N32 / N64 ABIs pass these in floating point
+   registers.  */
+
+static int
+mips_n32n64_fp_arg_chunk_p (struct type *arg_type, int offset)
+{
+  int i;
+
+  if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT)
+    return 0;
+
+  if (MIPS_FPU_TYPE != MIPS_FPU_DOUBLE)
+    return 0;
+
+  if (TYPE_LENGTH (arg_type) < offset + MIPS64_REGSIZE)
+    return 0;
+
+  for (i = 0; i < TYPE_NFIELDS (arg_type); i++)
+    {
+      int pos;
+      struct type *field_type;
+
+      /* We're only looking at normal fields.  */
+      if (TYPE_FIELD_STATIC (arg_type, i)
+         || (TYPE_FIELD_BITPOS (arg_type, i) % 8) != 0)
+       continue;
+
+      /* If we have gone past the offset, there is no double to pass.  */
+      pos = TYPE_FIELD_BITPOS (arg_type, i) / 8;
+      if (pos > offset)
+       return 0;
+
+      field_type = check_typedef (TYPE_FIELD_TYPE (arg_type, i));
+
+      /* If this field is entirely before the requested offset, go
+        on to the next one.  */
+      if (pos + TYPE_LENGTH (field_type) <= offset)
+       continue;
+
+      /* If this is our special aligned double, we can stop.  */
+      if (TYPE_CODE (field_type) == TYPE_CODE_FLT
+         && TYPE_LENGTH (field_type) == MIPS64_REGSIZE)
+       return 1;
+
+      /* This field starts at or before the requested offset, and
+        overlaps it.  If it is a structure, recurse inwards.  */
+      return mips_n32n64_fp_arg_chunk_p (field_type, offset - pos);
+    }
+
+  return 0;
+}
+
 static CORE_ADDR
 mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                             struct regcache *regcache, CORE_ADDR bp_addr,
@@ -2842,23 +2909,22 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       val = value_contents (arg);
 
       if (fp_register_arg_p (typecode, arg_type)
-         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+         && argreg <= MIPS_LAST_ARG_REGNUM)
        {
          /* This is a floating point value that fits entirely
             in a single register.  */
-         /* On 32 bit ABI's the float_argreg is further adjusted
-            above to ensure that it is even register aligned.  */
          LONGEST regval = extract_unsigned_integer (val, len);
          if (mips_debug)
            fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                float_argreg, phex (regval, len));
-         regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
+         regcache_cooked_write_unsigned (regcache, float_argreg, regval);
 
          if (mips_debug)
            fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
                                argreg, phex (regval, len));
          regcache_cooked_write_unsigned (regcache, argreg, regval);
-         argreg += 1;
+         float_argreg++;
+         argreg++;
        }
       else
        {
@@ -2883,10 +2949,12 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
                                    partial_len);
 
+             if (fp_register_arg_p (typecode, arg_type))
+               gdb_assert (argreg > MIPS_LAST_ARG_REGNUM);
+
              /* Write this portion of the argument to the stack.  */
              if (argreg > MIPS_LAST_ARG_REGNUM
-                 || odd_sized_struct
-                 || fp_register_arg_p (typecode, arg_type))
+                 || odd_sized_struct)
                {
                  /* Should shorter than int integer values be
                     promoted to int before being stored? */
@@ -2927,12 +2995,10 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                }
 
              /* Note!!! This is NOT an else clause.  Odd sized
-                structs may go thru BOTH paths.  Floating point
-                arguments will not.  */
+                structs may go thru BOTH paths.  */
              /* Write this portion of the argument to a general
                 purpose register.  */
-             if (argreg <= MIPS_LAST_ARG_REGNUM
-                 && !fp_register_arg_p (typecode, arg_type))
+             if (argreg <= MIPS_LAST_ARG_REGNUM)
                {
                  LONGEST regval =
                    extract_unsigned_integer (val, partial_len);
@@ -2958,6 +3024,19 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                                      argreg,
                                      phex (regval, MIPS64_REGSIZE));
                  regcache_cooked_write_unsigned (regcache, argreg, regval);
+
+                 if (mips_n32n64_fp_arg_chunk_p (arg_type,
+                                                 TYPE_LENGTH (arg_type) - len))
+                   {
+                     if (mips_debug)
+                       fprintf_filtered (gdb_stdlog, " - fpreg=%d val=%s",
+                                         float_argreg,
+                                         phex (regval, MIPS64_REGSIZE));
+                     regcache_cooked_write_unsigned (regcache, float_argreg,
+                                                     regval);
+                   }
+
+                 float_argreg++;
                  argreg++;
                }
 
@@ -4790,30 +4869,16 @@ global_mips_abi (void)
 static void
 mips_register_g_packet_guesses (struct gdbarch *gdbarch)
 {
-  static struct target_desc *tdesc_gp32, *tdesc_gp64;
-
-  if (tdesc_gp32 == NULL)
-    {
-      /* Create feature sets with the appropriate properties.  The values
-        are not important.  */
-
-      tdesc_gp32 = allocate_target_description ();
-      set_tdesc_property (tdesc_gp32, PROPERTY_GP32, "");
-
-      tdesc_gp64 = allocate_target_description ();
-      set_tdesc_property (tdesc_gp64, PROPERTY_GP64, "");
-    }
-
   /* If the size matches the set of 32-bit or 64-bit integer registers,
      assume that's what we've got.  */
-  register_remote_g_packet_guess (gdbarch, 38 * 4, tdesc_gp32);
-  register_remote_g_packet_guess (gdbarch, 38 * 8, tdesc_gp64);
+  register_remote_g_packet_guess (gdbarch, 38 * 4, mips_tdesc_gp32);
+  register_remote_g_packet_guess (gdbarch, 38 * 8, mips_tdesc_gp64);
 
   /* If the size matches the full set of registers GDB traditionally
      knows about, including floating point, for either 32-bit or
      64-bit, assume that's what we've got.  */
-  register_remote_g_packet_guess (gdbarch, 90 * 4, tdesc_gp32);
-  register_remote_g_packet_guess (gdbarch, 90 * 8, tdesc_gp64);
+  register_remote_g_packet_guess (gdbarch, 90 * 4, mips_tdesc_gp32);
+  register_remote_g_packet_guess (gdbarch, 90 * 8, mips_tdesc_gp64);
 
   /* Otherwise we don't have a useful guess.  */
 }
@@ -4835,6 +4900,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   int i, num_regs;
   enum mips_fpu_type fpu_type;
   struct tdesc_arch_data *tdesc_data = NULL;
+  int elf_fpu_type = 0;
 
   /* Check any target description for validity.  */
   if (tdesc_has_registers (info.target_desc))
@@ -5042,8 +5108,32 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                        mips64_transfers_32bit_regs_p);
 
   /* Determine the MIPS FPU type.  */
+#ifdef HAVE_ELF
+  if (info.abfd
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_fpu_type = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU,
+                                            Tag_GNU_MIPS_ABI_FP);
+#endif /* HAVE_ELF */
+
   if (!mips_fpu_type_auto)
     fpu_type = mips_fpu_type;
+  else if (elf_fpu_type != 0)
+    {
+      switch (elf_fpu_type)
+       {
+       case 1:
+         fpu_type = MIPS_FPU_DOUBLE;
+         break;
+       case 2:
+         fpu_type = MIPS_FPU_SINGLE;
+         break;
+       case 3:
+       default:
+         /* Soft float or unknown.  */
+         fpu_type = MIPS_FPU_NONE;
+         break;
+       }
+    }
   else if (info.bfd_arch_info != NULL
           && info.bfd_arch_info->arch == bfd_arch_mips)
     switch (info.bfd_arch_info->mach)
@@ -5195,7 +5285,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        else
          reg_names = mips_generic_reg_names;
       }
-    /* FIXME: cagney/2003-11-15: For MIPS, hasn't PC_REGNUM been
+    /* FIXME: cagney/2003-11-15: For MIPS, hasn't gdbarch_pc_regnum been
        replaced by read_pc?  */
     set_gdbarch_pc_regnum (gdbarch, regnum->pc + num_regs);
     set_gdbarch_sp_regnum (gdbarch, MIPS_SP_REGNUM + num_regs);
@@ -5595,6 +5685,14 @@ _initialize_mips_tdep (void)
 
   mips_pdr_data = register_objfile_data ();
 
+  /* Create feature sets with the appropriate properties.  The values
+     are not important.  */
+  mips_tdesc_gp32 = allocate_target_description ();
+  set_tdesc_property (mips_tdesc_gp32, PROPERTY_GP32, "");
+
+  mips_tdesc_gp64 = allocate_target_description ();
+  set_tdesc_property (mips_tdesc_gp64, PROPERTY_GP64, "");
+
   /* Add root prefix command for all "set mips"/"show mips" commands */
   add_prefix_cmd ("mips", no_class, set_mips_command,
                  _("Various MIPS specific commands."),
This page took 0.029058 seconds and 4 git commands to generate.