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]

[PATCH] Fix ARM machine state testcase failures


Hi,

When running GDB's reverse debugging testsuite against a few ARM multilibs, i noticed failures in the machinestate* testcases.

Further investigation showed that push and pop instruction encodings A1 and A2 were not being handled properly, thus we missed saving important contents from registers and memory. When going backwards, such contents were not restored and thus we ended up with a corrupted state that did not correspond to the real values we had at a particular point in time.

Attached is a patch that fixes around 36 failures for both gdb.reverse/machinestate.exp and gdb.reverse/machinestate-precsave.exp testcases, making them fully pass. This is for both armv7 and armv4. I still see failures for armv4 thumb though, so it needs a bit more investigation.

I see no regressions due to this patch for armv7, armv7 thumb, armv4 and armv4 thumb.

Ok for trunk?

Regards,
Luis
2014-10-16  Luis Machado  <lgustavo@codesourcery.com>

	* arm-tdep.c (POP_A2, PUSH_A2): New #defines.
	(arm_record_ld_st_imm_offset): Handle single-register ARM
	mode push and pop instructions.
	(POP_A1, PUSH_A1, PUSH_POP_SP_REG_MASK): New #defines.
	(arm_record_ld_st_multiple): Handle multi-register ARM
	mode push and pop instructions.

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index e2559ec..c488906 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -11473,6 +11473,10 @@ arm_record_data_proc_imm (insn_decode_record *arm_insn_r)
   return 0;
 }
 
+/* Masks for PUSH and POP instructions that take a single register.  */
+#define POP_A2	0x049d0004 /* POP<c> <registers> */
+#define PUSH_A2 0x052d0004 /* PUSH<c> <registers> */
+
 /* Handling opcode 010 insns.  */
 
 static int
@@ -11489,7 +11493,39 @@ arm_record_ld_st_imm_offset (insn_decode_record *arm_insn_r)
   arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
   arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
 
-  if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+  if ((arm_insn_r->arm_insn & POP_A2) == POP_A2)
+    {
+      /* Handle single-register pop.  */
+      int regno = bits (arm_insn_r->arm_insn, 12, 15);
+
+      record_buf[0] = regno;
+      arm_insn_r->reg_rec_count = 1;
+
+      /* The stack pointer register is always modified.  Check if we have
+	 already saved it though.  */
+      if (regno != ARM_SP_REGNUM)
+	{
+	  record_buf[1] = ARM_SP_REGNUM;
+	  arm_insn_r->reg_rec_count = 2;
+	}
+    }
+  else if ((arm_insn_r->arm_insn & PUSH_A2) == PUSH_A2)
+    {
+      /* Handle single-register push.  */
+
+      /* The stack pointer register is always updated.  */
+      record_buf[0] = ARM_SP_REGNUM;
+      arm_insn_r->reg_rec_count = 1;
+
+      /* The pushed register goes into the stack, so we need to record that
+	 chunk of memory as well.  */
+      regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval);
+      tgt_mem_addr = (uint32_t) u_regval;
+      record_buf_mem[0] = INT_REGISTER_SIZE;
+      record_buf_mem[1] = tgt_mem_addr - INT_REGISTER_SIZE;
+      arm_insn_r->mem_rec_count = 1;
+    }
+  else if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
     {
       reg_dest = bits (arm_insn_r->arm_insn, 12, 15);
       /* LDR insn has a capability to do branching, if
@@ -11847,6 +11883,11 @@ arm_record_ld_st_reg_offset (insn_decode_record *arm_insn_r)
   return 0;
 }
 
+/* Masks for PUSH and POP instructions that take multiple registers.  */
+#define POP_A1	0x08bd0000 /* POP<c> <registers> */
+#define PUSH_A1 0x092d0000 /* PUSH<c> <registers> */
+#define PUSH_POP_SP_REG_MASK 0x00002000
+
 /* Handling opcode 100 insns.  */
 
 static int
@@ -11861,12 +11902,66 @@ arm_record_ld_st_multiple (insn_decode_record *arm_insn_r)
 
   ULONGEST u_regval[2] = {0};
 
+  if ((arm_insn_r->arm_insn & POP_A1) == POP_A1)
+    {
+      /* Handle multi-register pop.  */
+      int regno = 0;
+
+      register_bits = bits (arm_insn_r->arm_insn, 0, 15);
+
+      /* Record which registers are going to be modified.  */
+      while (register_bits)
+	{
+	  if (register_bits & 0x00000001)
+	    record_buf[arm_insn_r->reg_rec_count++] = regno;
+	  register_bits = register_bits >> 1;
+	  regno++;
+	}
+
+      /* The stack pointer register is always modified.  Check if we have
+	 already saved it though.  */
+      if ((bits (arm_insn_r->arm_insn, 0, 15) & PUSH_POP_SP_REG_MASK) == 0)
+	{
+	  record_buf[arm_insn_r->reg_rec_count] = ARM_SP_REGNUM;
+	  arm_insn_r->reg_rec_count++;
+	}
+    }
+  else if ((arm_insn_r->arm_insn & PUSH_A1) == PUSH_A1)
+    {
+      /* Handle multi-register push.  */
+      int mem_chunks = 0;
+      uint32_t sp_addr;
+      ULONGEST u_regval;
+
+      register_bits = bits (arm_insn_r->arm_insn, 0, 15);
+      regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval);
+      sp_addr = (uint32_t) u_regval;
+
+      /* The stack pointer register is always modified.  */
+      record_buf[0] = ARM_SP_REGNUM;
+      arm_insn_r->reg_rec_count = 1;
+
+      /* The pushed registers go into the stack, so we need to record those
+	 chunks of memory as well.  Count how many registers are going to be
+	 saved.  */
+      while (register_bits)
+	{
+	  if (register_bits & 0x00000001)
+	    mem_chunks++;
+
+	  register_bits = register_bits >> 1;
+	}
+
+      /* Record the chunks in one continuous block.  */
+      record_buf_mem[0] = mem_chunks * INT_REGISTER_SIZE;
+      record_buf_mem[1] = sp_addr - mem_chunks * INT_REGISTER_SIZE;
+      arm_insn_r->mem_rec_count = 1;
+    }
   /* This mode is exclusively for load and store multiple.  */
   /* Handle incremenrt after/before and decrment after.before mode;
      Rn is changing depending on W bit, but as of now we store Rn too
      without optimization.  */
-
-  if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+  else if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
     {
       /* LDM  (1,2,3) where LDM  (3) changes CPSR too.  */
 

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