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,
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"
#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
{
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);
/* 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 */
/* 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,
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
{
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? */
}
/* 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);
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++;
}
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. */
}
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))
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)
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."),