/* 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
/* 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)
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;
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 */
}
}
+ /* 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 =
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
[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;
}
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