From 2207132da48e8347055233edd8cc6b8abffdd0a0 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 20 Nov 2007 13:47:42 +0000 Subject: [PATCH] * mips-tdep.c (mips16_scan_prologue): Handle the MIPS16e SAVE instruction. --- gdb/ChangeLog | 6 ++++ gdb/mips-tdep.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4b21d6e..341f666 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2007-11-20 David Ung + Maciej W. Rozycki + + * mips-tdep.c (mips16_scan_prologue): Handle the MIPS16e SAVE + instruction. + 2007-11-20 Vladimir Prus * infrun.c (resume): Clarify logic that diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 6df6c61..8be42fe 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -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 = -- 2.7.4