* mips-tdep.c (mips16_scan_prologue): Handle the MIPS16e SAVE

instruction.
This commit is contained in:
Maciej W. Rozycki 2007-11-20 13:47:42 +00:00
parent cd76b0b7c4
commit 2207132da4
2 changed files with 108 additions and 0 deletions

View File

@ -1,3 +1,9 @@
2007-11-20 David Ung <davidu@mips.com>
Maciej W. Rozycki <macro@mips.com>
* mips-tdep.c (mips16_scan_prologue): Handle the MIPS16e SAVE
instruction.
2007-11-20 Vladimir Prus <vladimir@codesourcery.com>
* infrun.c (resume): Clarify logic that

View File

@ -1500,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;
@ -1603,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 */
@ -1661,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 =