This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
mips-tdep.c: Handle the MIPS16e SAVE instruction
- From: "Maciej W. Rozycki" <macro at mips dot com>
- To: gdb-patches at sourceware dot org
- Cc: David Ung <davidu at mips dot com>, "Maciej W. Rozycki" <macro at linux-mips dot org>
- Date: Tue, 20 Nov 2007 12:00:34 +0000 (GMT)
- Subject: mips-tdep.c: Handle the MIPS16e SAVE instruction
Hello,
The change below adds handling of the MIPS16e SAVE instruction, fixing
a few regressions in the GDB test suite when run for
MIPS16:
FAIL: gdb.base/nodebug.exp: backtrace from inner in nodebug.exp
FAIL: gdb.base/nodebug.exp: backtrace from middle in nodebug.exp
KFAIL: gdb.base/gdb1250.exp: backtrace from abort (PRMS: gdb/1250)
Tested for using the mipsisa32-sde-elf target, with the
mips-sim-sde32/-mips16/-EB and mips-sim-sde32/-mips16/-EL boards, fixing
the three regressions.
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.
OK to apply?
Maciej
12920.diff
Index: gdb/src/gdb/mips-tdep.c
===================================================================
--- gdb.orig/src/gdb/mips-tdep.c 2007-11-16 11:21:26.000000000 +0000
+++ gdb/src/gdb/mips-tdep.c 2007-11-20 09:57:28.000000000 +0000
@@ -1500,6 +1500,7 @@
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 @@
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 @@
}
}
+ /* 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 =