2008-09-03 Angela Marie Thomas <angela@releasedominatrix.com>
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 6277407695ddd46cbf9cfc91806524fcf3fd8ffd..b6755421ee9b4346238ea12bf0d5ad4498d1a013 100644 (file)
@@ -142,16 +142,6 @@ const struct register_alias mips_register_aliases[] = {
   { "fsr", MIPS_EMBED_FP0_REGNUM + 32 }
 };
 
-/* Some MIPS boards don't support floating point while others only
-   support single-precision floating-point operations.  */
-
-enum mips_fpu_type
-{
-  MIPS_FPU_DOUBLE,             /* Full double precision floating point.  */
-  MIPS_FPU_SINGLE,             /* Single precision floating point (R4650).  */
-  MIPS_FPU_NONE                        /* No floating point.  */
-};
-
 #ifndef MIPS_DEFAULT_FPU_TYPE
 #define MIPS_DEFAULT_FPU_TYPE MIPS_FPU_DOUBLE
 #endif
@@ -168,37 +158,6 @@ static int mips_debug = 0;
 struct target_desc *mips_tdesc_gp32;
 struct target_desc *mips_tdesc_gp64;
 
-/* MIPS specific per-architecture information */
-struct gdbarch_tdep
-{
-  /* from the elf header */
-  int elf_flags;
-
-  /* mips options */
-  enum mips_abi mips_abi;
-  enum mips_abi found_abi;
-  enum mips_fpu_type mips_fpu_type;
-  int mips_last_arg_regnum;
-  int mips_last_fp_arg_regnum;
-  int default_mask_address_p;
-  /* Is the target using 64-bit raw integer registers but only
-     storing a left-aligned 32-bit value in each?  */
-  int mips64_transfers_32bit_regs_p;
-  /* Indexes for various registers.  IRIX and embedded have
-     different values.  This contains the "public" fields.  Don't
-     add any that do not need to be public.  */
-  const struct mips_regnum *regnum;
-  /* Register names table for the current register set.  */
-  const char **mips_processor_reg_names;
-
-  /* The size of register data available from the target, if known.
-     This doesn't quite obsolete the manual
-     mips64_transfers_32bit_regs_p, since that is documented to force
-     left alignment even for big endian (very strange).  */
-  int register_size_valid_p;
-  int register_size;
-};
-
 const struct mips_regnum *
 mips_regnum (struct gdbarch *gdbarch)
 {
@@ -211,14 +170,15 @@ mips_fpa0_regnum (struct gdbarch *gdbarch)
   return mips_regnum (gdbarch)->fp0 + 12;
 }
 
-#define MIPS_EABI (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI32 \
-                  || gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI64)
+#define MIPS_EABI(gdbarch) (gdbarch_tdep (gdbarch)->mips_abi \
+                    == MIPS_ABI_EABI32 \
+                  || gdbarch_tdep (gdbarch)->mips_abi == MIPS_ABI_EABI64)
 
-#define MIPS_LAST_FP_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_fp_arg_regnum)
+#define MIPS_LAST_FP_ARG_REGNUM(gdbarch) (gdbarch_tdep (gdbarch)->mips_last_fp_arg_regnum)
 
-#define MIPS_LAST_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_arg_regnum)
+#define MIPS_LAST_ARG_REGNUM(gdbarch) (gdbarch_tdep (gdbarch)->mips_last_arg_regnum)
 
-#define MIPS_FPU_TYPE (gdbarch_tdep (current_gdbarch)->mips_fpu_type)
+#define MIPS_FPU_TYPE(gdbarch) (gdbarch_tdep (gdbarch)->mips_fpu_type)
 
 /* MIPS16 function addresses are odd (bit 0 is set).  Here are some
    functions to test, set, or clear bit 0 of addresses.  */
@@ -391,7 +351,7 @@ mips2_fp_compat (struct frame_info *frame)
 
 #define VM_MIN_ADDRESS (CORE_ADDR)0x400000
 
-static CORE_ADDR heuristic_proc_start (CORE_ADDR);
+static CORE_ADDR heuristic_proc_start (struct gdbarch *, CORE_ADDR);
 
 static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *);
 
@@ -818,7 +778,7 @@ static void
 show_mask_address (struct ui_file *file, int from_tty,
                   struct cmd_list_element *c, const char *value)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
 
   deprecated_show_value_hack (file, from_tty, c, value);
   switch (mask_address_var)
@@ -1017,6 +977,17 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
              /* Set PC to that address */
              pc = get_frame_register_signed (frame, rtype_rs (inst));
              break;
+           case 12:            /* SYSCALL */
+             {
+               struct gdbarch_tdep *tdep;
+
+               tdep = gdbarch_tdep (get_frame_arch (frame));
+               if (tdep->syscall_next_pc != NULL)
+                 pc = tdep->syscall_next_pc (frame);
+               else
+                 pc += 4;
+             }
+             break;
            default:
              pc += 4;
            }
@@ -1431,18 +1402,16 @@ struct mips_frame_cache
    saved registers in a frame.  */
 
 static void
-set_reg_offset (struct mips_frame_cache *this_cache, int regnum,
-               CORE_ADDR offset)
+set_reg_offset (struct gdbarch *gdbarch, struct mips_frame_cache *this_cache,
+               int regnum, CORE_ADDR offset)
 {
   if (this_cache != NULL
       && this_cache->saved_regs[regnum].addr == -1)
     {
-      this_cache->saved_regs[regnum
-                            + 0 * gdbarch_num_regs (current_gdbarch)].addr
-      = offset;
-      this_cache->saved_regs[regnum
-                            + 1 * gdbarch_num_regs (current_gdbarch)].addr
-      = offset;
+      this_cache->saved_regs[regnum + 0 * gdbarch_num_regs (gdbarch)].addr
+        = offset;
+      this_cache->saved_regs[regnum + 1 * gdbarch_num_regs (gdbarch)].addr
+        = offset;
     }
 }
 
@@ -1559,23 +1528,23 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
        {
          offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
          reg = mips16_to_32_reg[(inst & 0x700) >> 8];
-         set_reg_offset (this_cache, reg, sp + offset);
+         set_reg_offset (gdbarch, this_cache, reg, sp + offset);
        }
       else if ((inst & 0xff00) == 0xf900)      /* sd reg,n($sp) */
        {
          offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
          reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
-         set_reg_offset (this_cache, reg, sp + offset);
+         set_reg_offset (gdbarch, this_cache, reg, sp + offset);
        }
       else if ((inst & 0xff00) == 0x6200)      /* sw $ra,n($sp) */
        {
          offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
-         set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
+         set_reg_offset (gdbarch, this_cache, MIPS_RA_REGNUM, sp + offset);
        }
       else if ((inst & 0xff00) == 0xfa00)      /* sd $ra,n($sp) */
        {
          offset = mips16_get_imm (prev_inst, inst, 8, 8, 0);
-         set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
+         set_reg_offset (gdbarch, this_cache, MIPS_RA_REGNUM, sp + offset);
        }
       else if (inst == 0x673d) /* move $s1, $sp */
        {
@@ -1593,13 +1562,13 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
        {
          offset = mips16_get_imm (prev_inst, inst, 5, 4, 0);
          reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
-         set_reg_offset (this_cache, reg, frame_addr + offset);
+         set_reg_offset (gdbarch, this_cache, reg, frame_addr + offset);
        }
       else if ((inst & 0xFF00) == 0x7900)      /* sd reg,offset($s1) */
        {
          offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
          reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
-         set_reg_offset (this_cache, reg, frame_addr + offset);
+         set_reg_offset (gdbarch, this_cache, reg, frame_addr + offset);
        }
       else if ((inst & 0xf81f) == 0xe809
                && (inst & 0x700) != 0x700)     /* entry */
@@ -1648,7 +1617,7 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
       /* Check if a0-a3 were saved in the caller's argument save area.  */
       for (reg = 4, offset = 0; reg < areg_count + 4; reg++)
        {
-         set_reg_offset (this_cache, reg, sp + offset);
+         set_reg_offset (gdbarch, this_cache, reg, sp + offset);
          offset += mips_abi_regsize (gdbarch);
        }
 
@@ -1656,14 +1625,14 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
       offset = -4;
       if (entry_inst & 0x20)
        {
-         set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
+         set_reg_offset (gdbarch, this_cache, MIPS_RA_REGNUM, sp + offset);
          offset -= mips_abi_regsize (gdbarch);
        }
 
       /* Check if the s0 and s1 registers were pushed on the stack.  */
       for (reg = 16; reg < sreg_count + 16; reg++)
        {
-         set_reg_offset (this_cache, reg, sp + offset);
+         set_reg_offset (gdbarch, this_cache, reg, sp + offset);
          offset -= mips_abi_regsize (gdbarch);
        }
     }
@@ -1715,7 +1684,7 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
       /* 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);
+         set_reg_offset (gdbarch, this_cache, reg, sp + offset);
          offset += mips_abi_regsize (gdbarch);
        }
 
@@ -1724,41 +1693,41 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
       /* Check if the RA register was pushed on the stack.  */
       if (save_inst & 0x40)
        {
-         set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
+         set_reg_offset (gdbarch, 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);
+         set_reg_offset (gdbarch, 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);
+         set_reg_offset (gdbarch, 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);
+         set_reg_offset (gdbarch, 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);
+         set_reg_offset (gdbarch, 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);
+         set_reg_offset (gdbarch, this_cache, reg, sp + offset);
          offset -= mips_abi_regsize (gdbarch);
        }
     }
@@ -1808,7 +1777,7 @@ mips_insn16_frame_cache (struct frame_info *this_frame, void **this_cache)
 
     find_pc_partial_function (pc, NULL, &start_addr, NULL);
     if (start_addr == 0)
-      start_addr = heuristic_proc_start (pc);
+      start_addr = heuristic_proc_start (get_frame_arch (this_frame), pc);
     /* We can't analyze the prologue if we couldn't find the begining
        of the function.  */
     if (start_addr == 0)
@@ -1893,14 +1862,14 @@ mips_insn16_frame_base_sniffer (struct frame_info *this_frame)
 /* Mark all the registers as unset in the saved_regs array
    of THIS_CACHE.  Do nothing if THIS_CACHE is null.  */
 
-void
-reset_saved_regs (struct mips_frame_cache *this_cache)
+static void
+reset_saved_regs (struct gdbarch *gdbarch, struct mips_frame_cache *this_cache)
 {
   if (this_cache == NULL || this_cache->saved_regs == NULL)
     return;
 
   {
-    const int num_regs = gdbarch_num_regs (current_gdbarch);
+    const int num_regs = gdbarch_num_regs (gdbarch);
     int i;
 
     for (i = 0; i < num_regs; i++)
@@ -1975,13 +1944,13 @@ restart:
       else if (((high_word & 0xFFE0) == 0xafa0) /* sw reg,offset($sp) */
                && !regsize_is_64_bits)
        {
-         set_reg_offset (this_cache, reg, sp + low_word);
+         set_reg_offset (gdbarch, this_cache, reg, sp + low_word);
        }
       else if (((high_word & 0xFFE0) == 0xffa0)        /* sd reg,offset($sp) */
                && regsize_is_64_bits)
        {
          /* Irix 6.2 N32 ABI uses sd instructions for saving $gp and $ra.  */
-         set_reg_offset (this_cache, reg, sp + low_word);
+         set_reg_offset (gdbarch, this_cache, reg, sp + low_word);
        }
       else if (high_word == 0x27be)    /* addiu $30,$sp,size */
        {
@@ -2007,7 +1976,7 @@ restart:
                      we will hit a guard that prevents the new address
                      for each register to be recomputed during the second
                      pass.  */
-                  reset_saved_regs (this_cache);
+                  reset_saved_regs (gdbarch, this_cache);
                  goto restart;
                }
            }
@@ -2037,7 +2006,7 @@ restart:
                      we will hit a guard that prevents the new address
                      for each register to be recomputed during the second
                      pass.  */
-                  reset_saved_regs (this_cache);
+                  reset_saved_regs (gdbarch, this_cache);
                  goto restart;
                }
            }
@@ -2045,7 +2014,7 @@ restart:
       else if ((high_word & 0xFFE0) == 0xafc0  /* sw reg,offset($30) */
                && !regsize_is_64_bits)
        {
-         set_reg_offset (this_cache, reg, frame_addr + low_word);
+         set_reg_offset (gdbarch, this_cache, reg, frame_addr + low_word);
        }
       else if ((high_word & 0xFFE0) == 0xE7A0 /* swc1 freg,n($sp) */
                || (high_word & 0xF3E0) == 0xA3C0 /* sx reg,n($s8) */
@@ -2145,7 +2114,7 @@ mips_insn32_frame_cache (struct frame_info *this_frame, void **this_cache)
 
     find_pc_partial_function (pc, NULL, &start_addr, NULL);
     if (start_addr == 0)
-      start_addr = heuristic_proc_start (pc);
+      start_addr = heuristic_proc_start (get_frame_arch (this_frame), pc);
     /* We can't analyze the prologue if we couldn't find the begining
        of the function.  */
     if (start_addr == 0)
@@ -2517,14 +2486,14 @@ mips_about_to_return (CORE_ADDR pc)
    lines.  */
 
 static CORE_ADDR
-heuristic_proc_start (CORE_ADDR pc)
+heuristic_proc_start (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   CORE_ADDR start_pc;
   CORE_ADDR fence;
   int instlen;
   int seen_adjsp = 0;
 
-  pc = gdbarch_addr_bits_remove (current_gdbarch, pc);
+  pc = gdbarch_addr_bits_remove (gdbarch, pc);
   start_pc = pc;
   fence = start_pc - heuristic_fence_post;
   if (start_pc == 0)
@@ -2633,16 +2602,17 @@ struct mips_objfile_private
    arguments into integer registers. */
 
 static int
-fp_register_arg_p (enum type_code typecode, struct type *arg_type)
+fp_register_arg_p (struct gdbarch *gdbarch, enum type_code typecode,
+                  struct type *arg_type)
 {
   return ((typecode == TYPE_CODE_FLT
-          || (MIPS_EABI
+          || (MIPS_EABI (gdbarch)
               && (typecode == TYPE_CODE_STRUCT
                   || typecode == TYPE_CODE_UNION)
               && TYPE_NFIELDS (arg_type) == 1
               && TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (arg_type, 0))) 
               == TYPE_CODE_FLT))
-         && MIPS_FPU_TYPE != MIPS_FPU_NONE);
+         && MIPS_FPU_TYPE(gdbarch) != MIPS_FPU_NONE);
 }
 
 /* On o32, argument passing in GPRs depends on the alignment of the type being
@@ -2777,7 +2747,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          up before the check to see if there are any FP registers
          left.  Non MIPS_EABI targets also pass the FP in the integer
          registers so also round up normal registers.  */
-      if (regsize < 8 && fp_register_arg_p (typecode, arg_type))
+      if (regsize < 8 && fp_register_arg_p (gdbarch, typecode, arg_type))
        {
          if ((float_argreg & 1))
            float_argreg++;
@@ -2795,8 +2765,8 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       /* MIPS_EABI squeezes a struct that contains a single floating
          point value into an FP register instead of pushing it onto the
          stack.  */
-      if (fp_register_arg_p (typecode, arg_type)
-         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+      if (fp_register_arg_p (gdbarch, typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch))
        {
          /* EABI32 will pass doubles in consecutive registers, even on
             64-bit cores.  At one time, we used to check the size of
@@ -2861,9 +2831,9 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                                    partial_len);
 
              /* Write this portion of the argument to the stack.  */
-             if (argreg > MIPS_LAST_ARG_REGNUM
+             if (argreg > MIPS_LAST_ARG_REGNUM (gdbarch)
                  || odd_sized_struct
-                 || fp_register_arg_p (typecode, arg_type))
+                 || fp_register_arg_p (gdbarch, typecode, arg_type))
                {
                  /* Should shorter than int integer values be
                     promoted to int before being stored? */
@@ -2912,8 +2882,8 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                 arguments will not.  */
              /* 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 (gdbarch)
+                 && !fp_register_arg_p (gdbarch, typecode, arg_type))
                {
                  LONGEST regval =
                    extract_unsigned_integer (val, partial_len);
@@ -2956,10 +2926,59 @@ mips_eabi_return_value (struct gdbarch *gdbarch, struct type *func_type,
                        struct type *type, struct regcache *regcache,
                        gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int fp_return_type = 0;
+  int offset, regnum, xfer;
+
   if (TYPE_LENGTH (type) > 2 * mips_abi_regsize (gdbarch))
     return RETURN_VALUE_STRUCT_CONVENTION;
-  if (readbuf)
-    memset (readbuf, 0, TYPE_LENGTH (type));
+
+  /* Floating point type?  */
+  if (tdep->mips_fpu_type != MIPS_FPU_NONE)
+    {
+      if (TYPE_CODE (type) == TYPE_CODE_FLT)
+       fp_return_type = 1;
+      /* Structs with a single field of float type 
+        are returned in a floating point register.  */
+      if ((TYPE_CODE (type) == TYPE_CODE_STRUCT
+          || TYPE_CODE (type) == TYPE_CODE_UNION)
+         && TYPE_NFIELDS (type) == 1)
+       {
+         struct type *fieldtype = TYPE_FIELD_TYPE (type, 0);
+
+         if (TYPE_CODE (check_typedef (fieldtype)) == TYPE_CODE_FLT)
+           fp_return_type = 1;
+       }
+    }
+
+  if (fp_return_type)      
+    {
+      /* A floating-point value belongs in the least significant part
+        of FP0/FP1.  */
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+      regnum = mips_regnum (gdbarch)->fp0;
+    }
+  else 
+    {
+      /* An integer value goes in V0/V1.  */
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stderr, "Return scalar in $v0\n");
+      regnum = MIPS_V0_REGNUM;
+    }
+  for (offset = 0;
+       offset < TYPE_LENGTH (type);
+       offset += mips_abi_regsize (gdbarch), regnum++)
+    {
+      xfer = mips_abi_regsize (gdbarch);
+      if (offset + xfer > TYPE_LENGTH (type))
+       xfer = TYPE_LENGTH (type) - offset;
+      mips_xfer_register (gdbarch, regcache,
+                         gdbarch_num_regs (gdbarch) + regnum, xfer,
+                         gdbarch_byte_order (gdbarch), readbuf, writebuf,
+                         offset);
+    }
+
   return RETURN_VALUE_REGISTER_CONVENTION;
 }
 
@@ -2971,14 +2990,15 @@ mips_eabi_return_value (struct gdbarch *gdbarch, struct type *func_type,
    registers.  */
 
 static int
-mips_n32n64_fp_arg_chunk_p (struct type *arg_type, int offset)
+mips_n32n64_fp_arg_chunk_p (struct gdbarch *gdbarch, 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)
+  if (MIPS_FPU_TYPE (gdbarch) != MIPS_FPU_DOUBLE)
     return 0;
 
   if (TYPE_LENGTH (arg_type) < offset + MIPS64_REGSIZE)
@@ -3013,7 +3033,7 @@ mips_n32n64_fp_arg_chunk_p (struct type *arg_type, int offset)
 
       /* 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 mips_n32n64_fp_arg_chunk_p (gdbarch, field_type, offset - pos);
     }
 
   return 0;
@@ -3092,23 +3112,49 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
       val = value_contents (arg);
 
-      if (fp_register_arg_p (typecode, arg_type)
-         && argreg <= MIPS_LAST_ARG_REGNUM)
+      /* A 128-bit long double value requires an even-odd pair of
+        floating-point registers.  */
+      if (len == 16
+         && fp_register_arg_p (gdbarch, typecode, arg_type)
+         && (float_argreg & 1))
+       {
+         float_argreg++;
+         argreg++;
+       }
+
+      if (fp_register_arg_p (gdbarch, typecode, arg_type)
+         && argreg <= MIPS_LAST_ARG_REGNUM (gdbarch))
        {
          /* This is a floating point value that fits entirely
-            in a single register.  */
-         LONGEST regval = extract_unsigned_integer (val, len);
+            in a single register or a pair of registers.  */
+         int reglen = (len <= MIPS64_REGSIZE ? len : MIPS64_REGSIZE);
+         LONGEST regval = extract_unsigned_integer (val, reglen);
          if (mips_debug)
            fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
-                               float_argreg, phex (regval, len));
+                               float_argreg, phex (regval, reglen));
          regcache_cooked_write_unsigned (regcache, float_argreg, regval);
 
          if (mips_debug)
            fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
-                               argreg, phex (regval, len));
+                               argreg, phex (regval, reglen));
          regcache_cooked_write_unsigned (regcache, argreg, regval);
          float_argreg++;
          argreg++;
+         if (len == 16)
+           {
+             regval = extract_unsigned_integer (val + reglen, reglen);
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+                                   float_argreg, phex (regval, reglen));
+             regcache_cooked_write_unsigned (regcache, float_argreg, regval);
+
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+                                   argreg, phex (regval, reglen));
+             regcache_cooked_write_unsigned (regcache, argreg, regval);
+             float_argreg++;
+             argreg++;
+           }
        }
       else
        {
@@ -3135,11 +3181,11 @@ 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);
+             if (fp_register_arg_p (gdbarch, typecode, arg_type))
+               gdb_assert (argreg > MIPS_LAST_ARG_REGNUM (gdbarch));
 
              /* Write this portion of the argument to the stack.  */
-             if (argreg > MIPS_LAST_ARG_REGNUM)
+             if (argreg > MIPS_LAST_ARG_REGNUM (gdbarch))
                {
                  /* Should shorter than int integer values be
                     promoted to int before being stored? */
@@ -3149,8 +3195,7 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
                    {
                      if ((typecode == TYPE_CODE_INT
-                          || typecode == TYPE_CODE_PTR
-                          || typecode == TYPE_CODE_FLT)
+                          || typecode == TYPE_CODE_PTR)
                          && len <= 4)
                        longword_offset = MIPS64_REGSIZE - len;
                    }
@@ -3183,7 +3228,7 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                 structs may go thru BOTH paths.  */
              /* Write this portion of the argument to a general
                 purpose register.  */
-             if (argreg <= MIPS_LAST_ARG_REGNUM)
+             if (argreg <= MIPS_LAST_ARG_REGNUM (gdbarch))
                {
                  LONGEST regval;
 
@@ -3223,7 +3268,7 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                                      phex (regval, MIPS64_REGSIZE));
                  regcache_cooked_write_unsigned (regcache, argreg, regval);
 
-                 if (mips_n32n64_fp_arg_chunk_p (arg_type,
+                 if (mips_n32n64_fp_arg_chunk_p (gdbarch, arg_type,
                                                  TYPE_LENGTH (arg_type) - len))
                    {
                      if (mips_debug)
@@ -3339,15 +3384,16 @@ mips_n32n64_return_value (struct gdbarch *gdbarch, struct type *func_type,
                   && (TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, 0)))
                       == TYPE_CODE_FLT)
                   && (TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, 1)))
-                      == TYPE_CODE_FLT)))
-          && tdep->mips_fpu_type != MIPS_FPU_NONE)
+                      == TYPE_CODE_FLT))))
     {
       /* A struct that contains one or two floats.  Each value is part
          in the least significant part of their floating point
-         register..  */
+         register (or GPR, for soft float).  */
       int regnum;
       int field;
-      for (field = 0, regnum = mips_regnum (gdbarch)->fp0;
+      for (field = 0, regnum = (tdep->mips_fpu_type != MIPS_FPU_NONE
+                               ? mips_regnum (gdbarch)->fp0
+                               : MIPS_V0_REGNUM);
           field < TYPE_NFIELDS (type); field++, regnum += 2)
        {
          int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
@@ -3355,11 +3401,27 @@ mips_n32n64_return_value (struct gdbarch *gdbarch, struct type *func_type,
          if (mips_debug)
            fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n",
                                offset);
-         mips_xfer_register (gdbarch, regcache,
-                             gdbarch_num_regs (gdbarch) + regnum,
-                             TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
-                             gdbarch_byte_order (gdbarch),
-                             readbuf, writebuf, offset);
+         if (TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)) == 16)
+           {
+             /* A 16-byte long double field goes in two consecutive
+                registers.  */
+             mips_xfer_register (gdbarch, regcache,
+                                 gdbarch_num_regs (gdbarch) + regnum,
+                                 8,
+                                 gdbarch_byte_order (gdbarch),
+                                 readbuf, writebuf, offset);
+             mips_xfer_register (gdbarch, regcache,
+                                 gdbarch_num_regs (gdbarch) + regnum + 1,
+                                 8,
+                                 gdbarch_byte_order (gdbarch),
+                                 readbuf, writebuf, offset + 8);
+           }
+         else
+           mips_xfer_register (gdbarch, regcache,
+                               gdbarch_num_regs (gdbarch) + regnum,
+                               TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
+                               gdbarch_byte_order (gdbarch),
+                               readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3503,7 +3565,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          up before the check to see if there are any FP registers
          left.  O32/O64 targets also pass the FP in the integer
          registers so also round up normal registers.  */
-      if (fp_register_arg_p (typecode, arg_type))
+      if (fp_register_arg_p (gdbarch, typecode, arg_type))
        {
          if ((float_argreg & 1))
            float_argreg++;
@@ -3519,8 +3581,8 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          arguments in general registers can't hurt non-MIPS16 functions
          because those registers are normally skipped.  */
 
-      if (fp_register_arg_p (typecode, arg_type)
-         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+      if (fp_register_arg_p (gdbarch, typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch))
        {
          if (register_size (gdbarch, float_argreg) < 8 && len == 8)
            {
@@ -3562,15 +3624,13 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, len));
              regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
-             /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
-                registers for each argument.  The below is (my
-                guess) to ensure that the corresponding integer
-                register has reserved the same space.  */
+             /* Although two FP registers are reserved for each
+                argument, only one corresponding integer register is
+                reserved.  */
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
                                    argreg, phex (regval, len));
-             regcache_cooked_write_unsigned (regcache, argreg, regval);
-             argreg += 2;
+             regcache_cooked_write_unsigned (regcache, argreg++, regval);
            }
          /* Reserve space for the FP register.  */
          stack_offset += align_up (len, MIPS32_REGSIZE);
@@ -3608,7 +3668,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                                    partial_len);
 
              /* Write this portion of the argument to the stack.  */
-             if (argreg > MIPS_LAST_ARG_REGNUM
+             if (argreg > MIPS_LAST_ARG_REGNUM (gdbarch)
                  || odd_sized_struct)
                {
                  /* Should shorter than int integer values be
@@ -3645,7 +3705,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                 structs may go thru BOTH paths.  */
              /* Write this portion of the argument to a general
                 purpose register.  */
-             if (argreg <= MIPS_LAST_ARG_REGNUM)
+             if (argreg <= MIPS_LAST_ARG_REGNUM (gdbarch))
                {
                  LONGEST regval = extract_signed_integer (val, partial_len);
                  /* Value may need to be sign extended, because
@@ -3692,7 +3752,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
                  /* Prevent subsequent floating point arguments from
                     being passed in floating point registers.  */
-                 float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
+                 float_argreg = MIPS_LAST_FP_ARG_REGNUM (gdbarch) + 1;
                }
 
              len -= partial_len;
@@ -3967,8 +4027,8 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          arguments in general registers can't hurt non-MIPS16 functions
          because those registers are normally skipped.  */
 
-      if (fp_register_arg_p (typecode, arg_type)
-         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+      if (fp_register_arg_p (gdbarch, typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch))
        {
          LONGEST regval = extract_unsigned_integer (val, len);
          if (mips_debug)
@@ -4005,7 +4065,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                                    partial_len);
 
              /* Write this portion of the argument to the stack.  */
-             if (argreg > MIPS_LAST_ARG_REGNUM
+             if (argreg > MIPS_LAST_ARG_REGNUM (gdbarch)
                  || odd_sized_struct)
                {
                  /* Should shorter than int integer values be
@@ -4050,7 +4110,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                 structs may go thru BOTH paths.  */
              /* Write this portion of the argument to a general
                 purpose register.  */
-             if (argreg <= MIPS_LAST_ARG_REGNUM)
+             if (argreg <= MIPS_LAST_ARG_REGNUM (gdbarch))
                {
                  LONGEST regval = extract_signed_integer (val, partial_len);
                  /* Value may need to be sign extended, because
@@ -4081,7 +4141,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
                  /* Prevent subsequent floating point arguments from
                     being passed in floating point registers.  */
-                 float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
+                 float_argreg = MIPS_LAST_FP_ARG_REGNUM (gdbarch) + 1;
                }
 
              len -= partial_len;
@@ -4119,7 +4179,7 @@ mips_o64_return_value (struct gdbarch *gdbarch, struct type *func_type,
       || TYPE_CODE (type) == TYPE_CODE_UNION
       || TYPE_CODE (type) == TYPE_CODE_ARRAY)
     return RETURN_VALUE_STRUCT_CONVENTION;
-  else if (fp_register_arg_p (TYPE_CODE (type), type))
+  else if (fp_register_arg_p (gdbarch, TYPE_CODE (type), type))
     {
       /* A floating-point value.  It fits in the least significant
          part of FP0.  */
@@ -4728,7 +4788,7 @@ show_mipsfpu_command (char *args, int from_tty)
 {
   char *fpu;
 
-  if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
+  if (gdbarch_bfd_arch_info (target_gdbarch)->arch != bfd_arch_mips)
     {
       printf_unfiltered
        ("The MIPS floating-point coprocessor is unknown "
@@ -4736,7 +4796,7 @@ show_mipsfpu_command (char *args, int from_tty)
       return;
     }
 
-  switch (MIPS_FPU_TYPE)
+  switch (MIPS_FPU_TYPE (target_gdbarch))
     {
     case MIPS_FPU_SINGLE:
       fpu = "single-precision";
@@ -5898,7 +5958,7 @@ show_mips_abi (struct ui_file *file,
               struct cmd_list_element *ignored_cmd,
               const char *ignored_value)
 {
-  if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
+  if (gdbarch_bfd_arch_info (target_gdbarch)->arch != bfd_arch_mips)
     fprintf_filtered
       (file, 
        "The MIPS ABI is unknown because the current architecture "
@@ -5906,7 +5966,7 @@ show_mips_abi (struct ui_file *file,
   else
     {
       enum mips_abi global_abi = global_mips_abi ();
-      enum mips_abi actual_abi = mips_abi (current_gdbarch);
+      enum mips_abi actual_abi = mips_abi (target_gdbarch);
       const char *actual_abi_str = mips_abi_strings[actual_abi];
 
       if (global_abi == MIPS_ABI_UNKNOWN)
@@ -5983,13 +6043,14 @@ mips_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
                       : MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_SINGLE ? "single"
                       : MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_DOUBLE ? "double"
                       : "???"));
-  fprintf_unfiltered (file, "mips_dump_tdep: MIPS_EABI = %d\n", MIPS_EABI);
+  fprintf_unfiltered (file, "mips_dump_tdep: MIPS_EABI = %d\n",
+                     MIPS_EABI (gdbarch));
   fprintf_unfiltered (file,
                      "mips_dump_tdep: MIPS_FPU_TYPE = %d (%s)\n",
-                     MIPS_FPU_TYPE,
-                     (MIPS_FPU_TYPE == MIPS_FPU_NONE ? "none"
-                      : MIPS_FPU_TYPE == MIPS_FPU_SINGLE ? "single"
-                      : MIPS_FPU_TYPE == MIPS_FPU_DOUBLE ? "double"
+                     MIPS_FPU_TYPE (gdbarch),
+                     (MIPS_FPU_TYPE (gdbarch) == MIPS_FPU_NONE ? "none"
+                      : MIPS_FPU_TYPE (gdbarch) == MIPS_FPU_SINGLE ? "single"
+                      : MIPS_FPU_TYPE (gdbarch) == MIPS_FPU_DOUBLE ? "double"
                       : "???"));
 }
 
This page took 0.036474 seconds and 4 git commands to generate.