This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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 =


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]