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]

[RFC ARM] Backport Thumb2 debug fixes to gdb 7.0 branch ?


Hi, 

      A colleague at work noticed that gdb7.0 didn't support Thumb2
debugging and it appears as though the Thumb2 debugging fixes were
committed after the 7.0 release branch was created.

The current state of the art with Thumb2 debugging in the 7.0 release
branch is that basic debug like single step doesn't work. By doesn't
work I mean that I get an error such as the following on single stepping
in a simple hello world program because next_pc doesn't know how to
disassemble Thumb2 instructions.


Could not insert single-step breakpoint at 0x249ca2

  	I've backported the patches here to the 7.0 release branch 

http://sourceware.org/ml/gdb-patches/2009-07/msg00683.html
http://sourceware.org/ml/gdb-patches/2009-10/msg00679.html

and tested this by building a native arm-linux-gnueabi gdb and testing
specifically by running the testsuite for Thumb2 debug using a native
gcc 4.4 compiler on my babbage board. The test results look very similar
to the results on trunk as of yesterday. 

A full testsuite run is on for ARM state as well to see nothing is
broken by this patch.

Ok to backport ? 

cheers
Ramana

2009-11-13  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>

        Backport from mainline.
        2009-07-28  Daniel Jacobowitz  <dan@codesourcery.com>

        * arm-tdep.c (arm_push_dummy_call): Set the low bit of LR for
        a Thumb entry point.
        (thumb_get_next_pc): Handle Thumb-2 and ARM v6 instructions.
Refuse to single step into IT blocks.

        2009-10-28  Daniel Jacobowitz  <dan@codesourcery.com>

        Reported by Antti Hatala <ahatala@nvidia.com>.

        * arm-tdep.c (thumb_get_next_pc): Limit check to IT instructions
        correctly.



-- 
Ramana Radhakrishnan
GNU Tools
ARM Ltd.
Index: arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.288
diff -a -u -r1.288 arm-tdep.c
--- arm-tdep.c	11 Sep 2009 18:51:31 -0000	1.288
+++ arm-tdep.c	13 Nov 2009 14:10:02 -0000
@@ -1627,7 +1627,8 @@
 
   /* Set the return address.  For the ARM, the return breakpoint is
      always at BP_ADDR.  */
-  /* XXX Fix for Thumb.  */
+  if (arm_pc_is_thumb (bp_addr))
+    bp_addr |= 1;
   regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
 
   /* Walk through the list of args and determine how large a temporary
@@ -2263,9 +2264,43 @@
   unsigned short inst1;
   CORE_ADDR nextpc = pc + 2;		/* default is next instruction */
   unsigned long offset;
+  ULONGEST status, it;
 
   inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
 
+  /* Thumb-2 conditional execution support.  There are eight bits in
+     the CPSR which describe conditional execution state.  Once
+     reconstructed (they're in a funny order), the low five bits
+     describe the low bit of the condition for each instruction and
+     how many instructions remain.  The high three bits describe the
+     base condition.  One of the low four bits will be set if an IT
+     block is active.  These bits read as zero on earlier
+     processors.  */
+  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
+  it = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
+
+  /* On GNU/Linux, where this routine is used, we use an undefined
+     instruction as a breakpoint.  Unlike BKPT, IT can disable execution
+     of the undefined instruction.  So we might miss the breakpoint!  */
+  if (((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0) || (it & 0x0f))
+    error (_("Stepping through Thumb-2 IT blocks is not yet supported"));
+
+  if (it & 0x0f)
+    {
+      /* We are in a conditional block.  Check the condition.  */
+      int cond = it >> 4;
+
+      if (! condition_true (cond, status))
+	{
+	  /* Advance to the next instruction.  All the 32-bit
+	     instructions share a common prefix.  */
+	  if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
+	    return pc + 4;
+	  else
+	    return pc + 2;
+	}
+    }
+
   if ((inst1 & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
     {
       CORE_ADDR sp;
@@ -2281,7 +2316,6 @@
     }
   else if ((inst1 & 0xf000) == 0xd000)	/* conditional branch */
     {
-      unsigned long status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
       unsigned long cond = bits (inst1, 8, 11);
       if (cond != 0x0f && condition_true (cond, status))    /* 0x0f = SWI */
 	nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
@@ -2290,15 +2324,166 @@
     {
       nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
     }
-  else if ((inst1 & 0xf800) == 0xf000)	/* long branch with link, and blx */
+  else if ((inst1 & 0xe000) == 0xe000) /* 32-bit instruction */
     {
       unsigned short inst2;
       inst2 = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code);
-      offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
-      nextpc = pc_val + offset;
-      /* For BLX make sure to clear the low bits.  */
-      if (bits (inst2, 11, 12) == 1)
-	nextpc = nextpc & 0xfffffffc;
+
+      /* Default to the next instruction.  */
+      nextpc = pc + 4;
+
+      if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
+	{
+	  /* Branches and miscellaneous control instructions.  */
+
+	  if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
+	    {
+	      /* B, BL, BLX.  */
+	      int j1, j2, imm1, imm2;
+
+	      imm1 = sbits (inst1, 0, 10);
+	      imm2 = bits (inst2, 0, 10);
+	      j1 = bit (inst2, 13);
+	      j2 = bit (inst2, 11);
+
+	      offset = ((imm1 << 12) + (imm2 << 1));
+	      offset ^= ((!j2) << 22) | ((!j1) << 23);
+
+	      nextpc = pc_val + offset;
+	      /* For BLX make sure to clear the low bits.  */
+	      if (bit (inst2, 12) == 0)
+		nextpc = nextpc & 0xfffffffc;
+	    }
+	  else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
+	    {
+	      /* SUBS PC, LR, #imm8.  */
+	      nextpc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+	      nextpc -= inst2 & 0x00ff;
+	    }
+	  else if ((inst2 & 0xd000) == 0xc000 && (inst1 & 0x0380) != 0x0380)
+	    {
+	      /* Conditional branch.  */
+	      if (condition_true (bits (inst1, 6, 9), status))
+		{
+		  int sign, j1, j2, imm1, imm2;
+
+		  sign = sbits (inst1, 10, 10);
+		  imm1 = bits (inst1, 0, 5);
+		  imm2 = bits (inst2, 0, 10);
+		  j1 = bit (inst2, 13);
+		  j2 = bit (inst2, 11);
+
+		  offset = (sign << 20) + (j2 << 19) + (j1 << 18);
+		  offset += (imm1 << 12) + (imm2 << 1);
+
+		  nextpc = pc_val + offset;
+		}
+	    }
+	}
+      else if ((inst1 & 0xfe50) == 0xe810)
+	{
+	  /* Load multiple or RFE.  */
+	  int rn, offset, load_pc = 1;
+
+	  rn = bits (inst1, 0, 3);
+	  if (bit (inst1, 7) && !bit (inst1, 8))
+	    {
+	      /* LDMIA or POP */
+	      if (!bit (inst2, 15))
+		load_pc = 0;
+	      offset = bitcount (inst2) * 4 - 4;
+	    }
+	  else if (!bit (inst1, 7) && bit (inst1, 8))
+	    {
+	      /* LDMDB */
+	      if (!bit (inst2, 15))
+		load_pc = 0;
+	      offset = -4;
+	    }
+	  else if (bit (inst1, 7) && bit (inst1, 8))
+	    {
+	      /* RFEIA */
+	      offset = 0;
+	    }
+	  else if (!bit (inst1, 7) && !bit (inst1, 8))
+	    {
+	      /* RFEDB */
+	      offset = -8;
+	    }
+	  else
+	    load_pc = 0;
+
+	  if (load_pc)
+	    {
+	      CORE_ADDR addr = get_frame_register_unsigned (frame, rn);
+	      nextpc = get_frame_memory_unsigned (frame, addr + offset, 4);
+	    }
+	}
+      else if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
+	{
+	  /* MOV PC or MOVS PC.  */
+	  nextpc = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
+	}
+      else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
+	{
+	  /* LDR PC.  */
+	  CORE_ADDR base;
+	  int rn, load_pc = 1;
+
+	  rn = bits (inst1, 0, 3);
+	  base = get_frame_register_unsigned (frame, rn);
+	  if (rn == 15)
+	    {
+	      base = (base + 4) & ~(CORE_ADDR) 0x3;
+	      if (bit (inst1, 7))
+		base += bits (inst2, 0, 11);
+	      else
+		base -= bits (inst2, 0, 11);
+	    }
+	  else if (bit (inst1, 7))
+	    base += bits (inst2, 0, 11);
+	  else if (bit (inst2, 11))
+	    {
+	      if (bit (inst2, 10))
+		{
+		  if (bit (inst2, 9))
+		    base += bits (inst2, 0, 7);
+		  else
+		    base -= bits (inst2, 0, 7);
+		}
+	    }
+	  else if ((inst2 & 0x0fc0) == 0x0000)
+	    {
+	      int shift = bits (inst2, 4, 5), rm = bits (inst2, 0, 3);
+	      base += get_frame_register_unsigned (frame, rm) << shift;
+	    }
+	  else
+	    /* Reserved.  */
+	    load_pc = 0;
+
+	  if (load_pc)
+	    nextpc = get_frame_memory_unsigned (frame, base, 4);
+	}
+      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+	{
+	  /* TBB.  */
+	  CORE_ADDR table, offset, length;
+
+	  table = get_frame_register_unsigned (frame, bits (inst1, 0, 3));
+	  offset = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
+	  length = 2 * get_frame_memory_unsigned (frame, table + offset, 1);
+	  nextpc = pc_val + length;
+	}
+      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+	{
+	  /* TBH.  */
+	  CORE_ADDR table, offset, length;
+
+	  table = get_frame_register_unsigned (frame, bits (inst1, 0, 3));
+	  offset = 2 * get_frame_register_unsigned (frame, bits (inst2, 0, 3));
+	  length = 2 * get_frame_memory_unsigned (frame, table + offset, 2);
+	  nextpc = pc_val + length;
+	}
     }
   else if ((inst1 & 0xff00) == 0x4700)	/* bx REG, blx REG */
     {
@@ -2311,6 +2496,17 @@
       if (nextpc == pc)
 	error (_("Infinite loop detected"));
     }
+  else if ((inst1 & 0xf500) == 0xb100)
+    {
+      /* CBNZ or CBZ.  */
+      int imm = (bit (inst1, 9) << 6) + (bits (inst1, 3, 7) << 1);
+      ULONGEST reg = get_frame_register_unsigned (frame, bits (inst1, 0, 2));
+
+      if (bit (inst1, 11) && reg != 0)
+	nextpc = pc_val + imm;
+      else if (!bit (inst1, 11) && reg == 0)
+	nextpc = pc_val + imm;
+    }
 
   return nextpc;
 }

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