[commit] Improve arm-linux single step

Daniel Jacobowitz drow@false.org
Thu Sep 27 18:51:00 GMT 2007


This fixes two problems in ARM software single stepping.  One, there
are some magic routines at 0xffff0xxx that we can't step through for
numerous reasons; so skip them.  Two, the "pld" instruction was being
mistakenly parsed as an invalid PC load.

There's another atomic sequence that we ought to single-step too; the
ARMv6 ll and sc instructions.  But I don't have a system that
generates those yet, so I left it alone for now.

Tested on arm-linux and checked in.

-- 
Daniel Jacobowitz
CodeSourcery

2007-09-27  Daniel Jacobowitz  <dan@codesourcery.com>

	* arm-linux-tdep.c (arm_linux_software_single_step): New.
	(arm_linux_init_abi): Use it.
	* arm-tdep.c (arm_get_next_pc): Make global.  Handle all-ones
	condition correctly.
	* arm-tdep.h (arm_get_next_pc): Declare.
	* Makefile.in (arm-linux-tdep.o): Update.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.938
diff -u -p -r1.938 Makefile.in
--- Makefile.in	17 Sep 2007 19:32:53 -0000	1.938
+++ Makefile.in	27 Sep 2007 15:36:35 -0000
@@ -1805,7 +1805,7 @@ arm-linux-nat.o: arm-linux-nat.c $(defs_
 arm-linux-tdep.o: arm-linux-tdep.c $(defs_h) $(target_h) $(value_h) \
 	$(gdbtypes_h) $(floatformat_h) $(gdbcore_h) $(frame_h) $(regcache_h) \
 	$(doublest_h) $(solib_svr4_h) $(osabi_h) $(arm_tdep_h) \
-	$(regset_h) $(arm_linux_tdep_h) \
+	$(regset_h) $(arm_linux_tdep_h) $(breakpoint_h) \
 	$(glibc_tdep_h) $(trad_frame_h) $(tramp_frame_h) $(gdb_string_h)
 armnbsd-nat.o: armnbsd-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) \
 	$(regcache_h) $(target_h) $(gdb_string_h) $(arm_tdep_h) $(inf_ptrace_h)
Index: arm-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-tdep.c,v
retrieving revision 1.59
diff -u -p -r1.59 arm-linux-tdep.c
--- arm-linux-tdep.c	23 Aug 2007 18:08:26 -0000	1.59
+++ arm-linux-tdep.c	27 Sep 2007 15:36:35 -0000
@@ -32,6 +32,7 @@
 #include "regset.h"
 #include "trad-frame.h"
 #include "tramp-frame.h"
+#include "breakpoint.h"
 
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
@@ -568,6 +569,26 @@ arm_linux_regset_from_core_section (stru
   return NULL;
 }
 
+/* Insert a single step breakpoint at the next executed instruction.  */
+
+int
+arm_linux_software_single_step (struct frame_info *frame)
+{
+  CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
+
+  /* The Linux kernel offers some user-mode helpers in a high page.  We can
+     not read this page (as of 2.6.23), and even if we could then we couldn't
+     set breakpoints in it, and even if we could then the atomic operations
+     would fail when interrupted.  They are all called as functions and return
+     to the address in LR, so step to there instead.  */
+  if (next_pc > 0xffff0000)
+    next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+
+  insert_single_step_breakpoint (next_pc);
+
+  return 1;
+}
+
 static void
 arm_linux_init_abi (struct gdbarch_info info,
 		    struct gdbarch *gdbarch)
@@ -604,7 +625,7 @@ arm_linux_init_abi (struct gdbarch_info 
     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
 
   /* Single stepping.  */
-  set_gdbarch_software_single_step (gdbarch, arm_software_single_step);
+  set_gdbarch_software_single_step (gdbarch, arm_linux_software_single_step);
 
   /* Shared library handling.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
Index: arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.242
diff -u -p -r1.242 arm-tdep.c
--- arm-tdep.c	7 Sep 2007 12:13:45 -0000	1.242
+++ arm-tdep.c	27 Sep 2007 15:36:35 -0000
@@ -1664,7 +1664,7 @@ thumb_get_next_pc (struct frame_info *fr
   return nextpc;
 }
 
-static CORE_ADDR
+CORE_ADDR
 arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
   unsigned long pc_val;
@@ -1680,7 +1680,30 @@ arm_get_next_pc (struct frame_info *fram
   status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
   nextpc = (CORE_ADDR) (pc_val + 4);	/* Default case */
 
-  if (condition_true (bits (this_instr, 28, 31), status))
+  if (bits (this_instr, 28, 31) == INST_NV)
+    switch (bits (this_instr, 24, 27))
+      {
+      case 0xa:
+      case 0xb:
+	{
+	  /* Branch with Link and change to Thumb.  */
+	  nextpc = BranchDest (pc, this_instr);
+	  nextpc |= bit (this_instr, 24) << 1;
+
+	  nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+	  if (nextpc == pc)
+	    error (_("Infinite loop detected"));
+	  break;
+	}
+      case 0xc:
+      case 0xd:
+      case 0xe:
+	/* Coprocessor register transfer.  */
+        if (bits (this_instr, 12, 15) == 15)
+	  error (_("Invalid update to pc in instruction"));
+	break;
+      }
+  else if (condition_true (bits (this_instr, 28, 31), status))
     {
       switch (bits (this_instr, 24, 27))
 	{
@@ -1886,10 +1909,6 @@ arm_get_next_pc (struct frame_info *fram
 	  {
 	    nextpc = BranchDest (pc, this_instr);
 
-	    /* BLX */
-	    if (bits (this_instr, 28, 31) == INST_NV)
-	      nextpc |= bit (this_instr, 24) << 1;
-
 	    nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
 	    if (nextpc == pc)
 	      error (_("Infinite loop detected"));
Index: arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.26
diff -u -p -r1.26 arm-tdep.h
--- arm-tdep.h	3 Sep 2007 22:24:24 -0000	1.26
+++ arm-tdep.h	27 Sep 2007 15:36:35 -0000
@@ -181,6 +181,7 @@ struct gdbarch_tdep
 #endif
 
 CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
+CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);
 int arm_software_single_step (struct frame_info *);
 
 /* Functions exported from armbsd-tdep.h.  */



More information about the Gdb-patches mailing list