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] "single step" atomic instruction sequences as a whole.


This fixes a problem noticed on ppc64-linux: automatically stepping out
of the 'puts' library function (because it had no line number
information) would cause an endless loop.  This happened because of the
following sequence of instructions:

        L1:   lwarx   r11,0,r3
              cmpw    r11,r9
              bne-    L2
              stwcx.  r0,0,r3
              bne-    L1
        L2:   isync

GDB can not single step this sequence instruction by instruction because
the 'reserve' made by the lwarx instruction will always be lost by the
the time the stwcx instruction has executed.

Other architectures may have similar instruction sequences which must
not be single stepped, one at a time.

To fix this, we must 'single step' these sequences as a whole, using the
same mechanism used by software single step.

Toward that end, I changed the existing software_single_step so that it
would return 1 if it handled the step and 0 if it did not.  All the
existing versions where changed to always return 1.

Then I added a software_single_step routine for ppc-linux.  This
platform did not previous use this function because it has a hardware
single step.  Now, this routine ('ppc_atomic_single_step') checks to see
if the instruction about to be stepped is an stwcx instruction.  If not,
it returns 0 to indicate that the single step has not been handled and
the regular hardware single step should be used.  If the instruction
about to be single stepped was an stwcx instruction, then the code is
scanned looking for the corresponding stwcx instruction, after which a
breakpoint is placed.  If a branch is detected while scanning, a
breakpoint is also placed at the target of that branch.  Then flags are
set as they where for the old software single step and 1 is returned to
indicate that the step has been handled.

I have attached two patches.  'change-software-single-step.diff' makes
the generic changes to all the existing software single step routines:
changing their type from void to int and always returning a 1.

'ppc-atomic-single-step.diff' adds the new ppc_atomic_single_step
routine to ppc-linux-tdep.c and updates the ppc_linux_init_abi routine
to use set_gdbarch_software_single_step() to plug the new routine into
the architecture vector.

You may ask "but what if an architecture needs the old
software_single_step functionality *and* has sequences of instructions
that need to be atomic?"  The answer is easy: do the test for the start
of an atomic sequence: if yes, then scan for its end as above and set
one or two breakpoints; if no, then examine the instruction to see if
it's a branch, setting a breakpoint at the target of the branch if it
is, and setting a breakpoint after the instruction if it is not or if
it's conditional.  In either event the step was handled, so return 1.

You may ask "isn't this going to take a long time, examining every
instruction before it is stepped?"  Well, a little.  But no more then an
architecture without a hardware supported single step which has to
examine every instruction to see if it's a branch.  I did some timing
analysis and the difference was minor.

This was first discussed on the gdb mailing list here:
        http://sourceware.org/ml/gdb/2006-06/msg00048.html
        
OK to commit?

-=# Paul #=- 
20006-06-22  Paul Gilliam  <pgilliam@us.ibm.com>

	* gdbarch.sh: Change the return type of software_single_step from
	void to int and reformatted some comments to <= 80 columns.
	* gdbarch.c, gdbarch.h: Regenerated.
	* alpha-tdep.c (alpha_software_single_step): Change the return type
	from void to int and always return 1.
	* alpha-tdep.h: Change the return type of alpha_software_single_step
	from void to int.
	* arm-tdep.c (arm_software_single_step): Change the return type from
	void to int and always return 1.
	* cris-tdep.c (cris_software_single_step): Change the return type
	from void to int and always return 1.
	* mips-tdep.c (mips_software_single_step): Change the return type
	from void to int and always return 1.
	* mips-tdep.h: Change the return type of mips_software_single_step
	from void to int.
	* rs6000-tdep.c (rs6000_software_single_step): Change the return type
	from void to int and always return 1.
	*rs6000-tdep.h: Change the return type of rs6000_software_single_step
	from void to int.
	* sparc-tdep.c (sparc_software_single_step): Change the return type
	from void to int and always return 1.
	* sparc-tdep.h: Change the return type of sparc_software_single_step
	from void to int.
	* wince.c (wince_software_single_step {three times}): Change the
	return type from void to int and always return 1.
	infrun.c (resume): Check the return value from SOFTWARE_SINGLE_STEP
	and act accordingly.  True means that the software_single_step
	breakpoints where inserted; false means they where not.

Index: alpha-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/alpha-tdep.c,v
retrieving revision 1.154
diff -a -u -r1.154 alpha-tdep.c
--- alpha-tdep.c	18 Apr 2006 19:20:05 -0000	1.154
+++ alpha-tdep.c	22 Jun 2006 17:49:27 -0000
@@ -1489,7 +1489,7 @@
   return (pc + 4);
 }
 
-void
+int
 alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p)
 {
   static CORE_ADDR next_pc;
@@ -1507,6 +1507,7 @@
       remove_single_step_breakpoints ();
       write_pc (next_pc);
     }
+  return 1;
 }
 
 
Index: alpha-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/alpha-tdep.h,v
retrieving revision 1.23
diff -a -u -r1.23 alpha-tdep.h
--- alpha-tdep.h	17 Dec 2005 22:33:59 -0000	1.23
+++ alpha-tdep.h	22 Jun 2006 17:49:27 -0000
@@ -100,7 +100,7 @@
 };
 
 extern unsigned int alpha_read_insn (CORE_ADDR pc);
-extern void alpha_software_single_step (enum target_signal, int);
+extern int alpha_software_single_step (enum target_signal, int);
 extern CORE_ADDR alpha_after_prologue (CORE_ADDR pc);
 
 extern void alpha_mdebug_init_abi (struct gdbarch_info, struct gdbarch *);
Index: arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.209
diff -a -u -r1.209 arm-tdep.c
--- arm-tdep.c	17 May 2006 14:40:39 -0000	1.209
+++ arm-tdep.c	22 Jun 2006 17:49:27 -0000
@@ -1846,7 +1846,7 @@
    single_step() is also called just after the inferior stops.  If we
    had set up a simulated single-step, we undo our damage.  */
 
-static void
+static int
 arm_software_single_step (enum target_signal sig, int insert_bpt)
 {
   /* NOTE: This may insert the wrong breakpoint instruction when
@@ -1861,6 +1861,8 @@
     }
   else
     remove_single_step_breakpoints ();
+
+  return 1
 }
 
 #include "bfd-in2.h"
Index: cris-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/cris-tdep.c,v
retrieving revision 1.136
diff -a -u -r1.136 cris-tdep.c
--- cris-tdep.c	18 Apr 2006 19:20:06 -0000	1.136
+++ cris-tdep.c	22 Jun 2006 17:49:28 -0000
@@ -2117,7 +2117,7 @@
    digs through the opcodes in order to find all possible targets. 
    Either one ordinary target or two targets for branches may be found.  */
 
-static void
+static int
 cris_software_single_step (enum target_signal ignore, int insert_breakpoints)
 {
   inst_env_type inst_env;
@@ -2150,6 +2150,8 @@
     }
   else
     remove_single_step_breakpoints ();
+
+  return 1;
 }
 
 /* Calculates the prefix value for quick offset addressing mode.  */
Index: gdbarch.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.c,v
retrieving revision 1.329
diff -a -u -r1.329 gdbarch.c
--- gdbarch.c	18 Apr 2006 19:20:06 -0000	1.329
+++ gdbarch.c	22 Jun 2006 17:49:28 -0000
@@ -3318,14 +3318,14 @@
   return gdbarch->software_single_step != NULL;
 }
 
-void
+int
 gdbarch_software_single_step (struct gdbarch *gdbarch, enum target_signal sig, int insert_breakpoints_p)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->software_single_step != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_software_single_step called\n");
-  gdbarch->software_single_step (sig, insert_breakpoints_p);
+  return gdbarch->software_single_step (sig, insert_breakpoints_p);
 }
 
 void
Index: gdbarch.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.h,v
retrieving revision 1.285
diff -a -u -r1.285 gdbarch.h
--- gdbarch.h	18 Apr 2006 19:20:06 -0000	1.285
+++ gdbarch.h	22 Jun 2006 17:49:28 -0000
@@ -1165,14 +1165,16 @@
 #define SMASH_TEXT_ADDRESS(addr) (gdbarch_smash_text_address (current_gdbarch, addr))
 #endif
 
-/* FIXME/cagney/2001-01-18: This should be split in two.  A target method that indicates if
-   the target needs software single step.  An ISA method to implement it.
+/* FIXME/cagney/2001-01-18: This should be split in two.  A target method that
+   indicates if the target needs software single step.  An ISA method to
+   implement it.
   
-   FIXME/cagney/2001-01-18: This should be replaced with something that inserts breakpoints
-   using the breakpoint system instead of blatting memory directly (as with rs6000).
+   FIXME/cagney/2001-01-18: This should be replaced with something that inserts
+   breakpoints using the breakpoint system instead of blatting memory directly
+   (as with rs6000).
   
-   FIXME/cagney/2001-01-18: The logic is backwards.  It should be asking if the target can
-   single step.  If not, then implement single step using breakpoints. */
+   FIXME/cagney/2001-01-18: The logic is backwards.  It should be asking if the
+   target can single step.  If not, then implement single step using breakpoints. */
 
 #if defined (SOFTWARE_SINGLE_STEP)
 /* Legacy for systems yet to multi-arch SOFTWARE_SINGLE_STEP */
@@ -1189,8 +1191,8 @@
 #define SOFTWARE_SINGLE_STEP_P() (gdbarch_software_single_step_p (current_gdbarch))
 #endif
 
-typedef void (gdbarch_software_single_step_ftype) (enum target_signal sig, int insert_breakpoints_p);
-extern void gdbarch_software_single_step (struct gdbarch *gdbarch, enum target_signal sig, int insert_breakpoints_p);
+typedef int (gdbarch_software_single_step_ftype) (enum target_signal sig, int insert_breakpoints_p);
+extern int gdbarch_software_single_step (struct gdbarch *gdbarch, enum target_signal sig, int insert_breakpoints_p);
 extern void set_gdbarch_software_single_step (struct gdbarch *gdbarch, gdbarch_software_single_step_ftype *software_single_step);
 #if !defined (GDB_TM_FILE) && defined (SOFTWARE_SINGLE_STEP)
 #error "Non multi-arch definition of SOFTWARE_SINGLE_STEP"
Index: gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.364
diff -a -u -r1.364 gdbarch.sh
--- gdbarch.sh	18 Apr 2006 19:20:06 -0000	1.364
+++ gdbarch.sh	22 Jun 2006 17:49:28 -0000
@@ -602,15 +602,19 @@
 # It is not at all clear why SMASH_TEXT_ADDRESS is not folded into
 # ADDR_BITS_REMOVE.
 f:=:CORE_ADDR:smash_text_address:CORE_ADDR addr:addr::core_addr_identity::0
-# FIXME/cagney/2001-01-18: This should be split in two.  A target method that indicates if
-# the target needs software single step.  An ISA method to implement it.
+
+# FIXME/cagney/2001-01-18: This should be split in two.  A target method that
+# indicates if the target needs software single step.  An ISA method to
+# implement it.
 #
-# FIXME/cagney/2001-01-18: This should be replaced with something that inserts breakpoints
-# using the breakpoint system instead of blatting memory directly (as with rs6000).
+# FIXME/cagney/2001-01-18: This should be replaced with something that inserts
+# breakpoints using the breakpoint system instead of blatting memory directly
+# (as with rs6000).
 #
-# FIXME/cagney/2001-01-18: The logic is backwards.  It should be asking if the target can
-# single step.  If not, then implement single step using breakpoints.
-F:=:void:software_single_step:enum target_signal sig, int insert_breakpoints_p:sig, insert_breakpoints_p
+# FIXME/cagney/2001-01-18: The logic is backwards.  It should be asking if the
+# target can single step.  If not, then implement single step using breakpoints.
+F:=:int:software_single_step:enum target_signal sig, int insert_breakpoints_p:sig, insert_breakpoints_p
+
 # Return non-zero if the processor is executing a delay slot and a
 # further single-step is needed before the instruction finishes.
 M::int:single_step_through_delay:struct frame_info *frame:frame
Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.211
diff -a -u -r1.211 infrun.c
--- infrun.c	16 Jun 2006 01:12:58 -0000	1.211
+++ infrun.c	22 Jun 2006 17:49:28 -0000
@@ -556,13 +556,15 @@
   if (SOFTWARE_SINGLE_STEP_P () && step)
     {
       /* Do it the hard way, w/temp breakpoints */
-      SOFTWARE_SINGLE_STEP (sig, 1 /*insert-breakpoints */ );
-      /* ...and don't ask hardware to do it.  */
-      step = 0;
-      /* and do not pull these breakpoints until after a `wait' in
-         `wait_for_inferior' */
-      singlestep_breakpoints_inserted_p = 1;
-      singlestep_ptid = inferior_ptid;
+      if (SOFTWARE_SINGLE_STEP (sig, 1 /*insert-breakpoints */ ))
+	{
+	  /* ...and don't ask hardware to do it.  */
+	  step = 0;
+	  /* and do not pull these breakpoints until after a `wait' in
+	  `wait_for_inferior' */
+	  singlestep_breakpoints_inserted_p = 1;
+	  singlestep_ptid = inferior_ptid;
+	}
     }
 
   /* If there were any forks/vforks/execs that were caught and are
@@ -1375,7 +1377,7 @@
 					   (LONGEST) ecs->ws.value.integer));
       gdb_flush (gdb_stdout);
       target_mourn_inferior ();
-      singlestep_breakpoints_inserted_p = 0;	/*SOFTWARE_SINGLE_STEP_P() */
+      singlestep_breakpoints_inserted_p = 0;	/* SOFTWARE_SINGLE_STEP_P() */
       stop_print_frame = 0;
       stop_stepping (ecs);
       return;
@@ -1395,7 +1397,7 @@
       target_mourn_inferior ();
 
       print_stop_reason (SIGNAL_EXITED, stop_signal);
-      singlestep_breakpoints_inserted_p = 0;	/*SOFTWARE_SINGLE_STEP_P() */
+      singlestep_breakpoints_inserted_p = 0;	/* SOFTWARE_SINGLE_STEP_P() */
       stop_stepping (ecs);
       return;
 
@@ -1557,7 +1559,7 @@
 	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog, "infrun: stepping_past_singlestep_breakpoint\n");
 	  /* Pull the single step breakpoints out of the target.  */
-	  SOFTWARE_SINGLE_STEP (0, 0);
+	  (void) SOFTWARE_SINGLE_STEP (0, 0);
 	  singlestep_breakpoints_inserted_p = 0;
 
 	  ecs->random_signal = 0;
@@ -1621,7 +1623,7 @@
 	  if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
 	    {
 	      /* Pull the single step breakpoints out of the target. */
-	      SOFTWARE_SINGLE_STEP (0, 0);
+	      (void) SOFTWARE_SINGLE_STEP (0, 0);
 	      singlestep_breakpoints_inserted_p = 0;
 	    }
 
@@ -1694,7 +1696,7 @@
   if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
     {
       /* Pull the single step breakpoints out of the target. */
-      SOFTWARE_SINGLE_STEP (0, 0);
+      (void) SOFTWARE_SINGLE_STEP (0, 0);
       singlestep_breakpoints_inserted_p = 0;
     }
 
Index: mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.396
diff -a -u -r1.396 mips-tdep.c
--- mips-tdep.c	19 Jun 2006 18:50:09 -0000	1.396
+++ mips-tdep.c	22 Jun 2006 17:49:29 -0000
@@ -2185,7 +2185,7 @@
    single_step is also called just after the inferior stops.  If we had
    set up a simulated single-step, we undo our damage.  */
 
-void
+int
 mips_software_single_step (enum target_signal sig, int insert_breakpoints_p)
 {
   CORE_ADDR pc, next_pc;
@@ -2199,6 +2199,8 @@
     }
   else
     remove_single_step_breakpoints ();
+
+  return 1;
 }
 
 /* Test whether the PC points to the return instruction at the
Index: mips-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.h,v
retrieving revision 1.18
diff -a -u -r1.18 mips-tdep.h
--- mips-tdep.h	17 Dec 2005 22:34:01 -0000	1.18
+++ mips-tdep.h	22 Jun 2006 17:49:29 -0000
@@ -103,7 +103,7 @@
 };
 
 /* Single step based on where the current instruction will take us.  */
-extern void mips_software_single_step (enum target_signal, int);
+extern int mips_software_single_step (enum target_signal, int);
 
 /* Tell if the program counter value in MEMADDR is in a MIPS16
    function.  */
Index: rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.258
diff -a -u -r1.258 rs6000-tdep.c
--- rs6000-tdep.c	23 Apr 2006 14:15:01 -0000	1.258
+++ rs6000-tdep.c	22 Jun 2006 17:49:29 -0000
@@ -704,7 +704,7 @@
 
 /* AIX does not support PT_STEP. Simulate it. */
 
-void
+int
 rs6000_software_single_step (enum target_signal signal,
 			     int insert_breakpoints_p)
 {
@@ -743,6 +743,8 @@
 
   errno = 0;			/* FIXME, don't ignore errors! */
   /* What errors?  {read,write}_memory call error().  */
+
+  return 1;
 }
 
 
Index: rs6000-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.h,v
retrieving revision 1.1
diff -a -u -r1.1 rs6000-tdep.h
--- rs6000-tdep.h	10 Feb 2006 20:56:14 -0000	1.1
+++ rs6000-tdep.h	22 Jun 2006 17:49:29 -0000
@@ -21,6 +21,6 @@
 
 #include "defs.h"
 
-extern void rs6000_software_single_step (enum target_signal signal,
-					 int insert_breakpoints_p);
+extern int rs6000_software_single_step (enum target_signal signal,
+                                        int insert_breakpoints_p);
 
Index: sparc-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc-tdep.c,v
retrieving revision 1.172
diff -a -u -r1.172 sparc-tdep.c
--- sparc-tdep.c	18 Apr 2006 19:20:06 -0000	1.172
+++ sparc-tdep.c	22 Jun 2006 17:49:29 -0000
@@ -1131,7 +1131,7 @@
   return 0;
 }
 
-void
+int
 sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
 {
   struct gdbarch *arch = current_gdbarch;
@@ -1161,6 +1161,8 @@
     }
   else
     remove_single_step_breakpoints ();
+
+  return 1;
 }
 
 static void
Index: sparc-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/sparc-tdep.h,v
retrieving revision 1.11
diff -a -u -r1.11 sparc-tdep.h
--- sparc-tdep.h	22 Jan 2006 20:07:38 -0000	1.11
+++ sparc-tdep.h	22 Jun 2006 17:49:29 -0000
@@ -167,8 +167,8 @@
 
 
 
-extern void sparc_software_single_step (enum target_signal sig,
-					int insert_breakpoints_p);
+extern int sparc_software_single_step (enum target_signal sig,
+                                       int insert_breakpoints_p);
 
 extern void sparc_supply_rwindow (struct regcache *regcache,
 				  CORE_ADDR sp, int regnum);
Index: wince.c
===================================================================
RCS file: /cvs/src/src/gdb/wince.c,v
retrieving revision 1.45
diff -a -u -r1.45 wince.c
--- wince.c	18 Apr 2006 19:20:06 -0000	1.45
+++ wince.c	22 Jun 2006 17:49:29 -0000
@@ -838,7 +838,7 @@
     }
 }
 
-void
+int
 wince_software_single_step (enum target_signal ignore,
 			    int insert_breakpoints_p)
 {
@@ -850,14 +850,15 @@
   if (!insert_breakpoints_p)
     {
       undoSStep (th);
-      return;
+      return 1;
     }
 
   th->stepped = 1;
   pc = read_register (PC_REGNUM);
   th->step_pc = mips_next_pc (pc);
   insert_single_step_breakpoint (th->step_pc);
-  return;
+
+  return 1;
 }
 #elif SHx
 /* Renesas SH architecture instruction encoding masks */
@@ -979,7 +980,7 @@
    instruction and setting a breakpoint on the "next" instruction
    which would be executed.  This code hails from sh-stub.c.
  */
-void
+int
 wince_software_single_step (enum target_signal ignore,
 			    int insert_breakpoints_p)
 {
@@ -989,13 +990,14 @@
   if (!insert_breakpoints_p)
     {
       undoSStep (th);
-      return;
+      return 1;
     }
 
   th->stepped = 1;
   th->step_pc = sh_get_next_pc (&th->context);
   insert_single_step_breakpoint (th->step_pc);
-  return;
+
+  return 1;
 }
 #elif defined (ARM)
 #undef check_for_step
@@ -1026,7 +1028,7 @@
     }
 }
 
-void
+int
 wince_software_single_step (enum target_signal ignore,
 			    int insert_breakpoints_p)
 {
@@ -1038,14 +1040,15 @@
   if (!insert_breakpoints_p)
     {
       undoSStep (th);
-      return;
+      return 1;
     }
 
   th->stepped = 1;
   pc = read_register (PC_REGNUM);
   th->step_pc = arm_get_next_pc (pc);
   insert_single_step_breakpoint (th->step_pc);
-  return;
+
+  return 1;
 }
 #endif
 
20006-06-22  Paul Gilliam  <pgilliam@us.ibm.com>

	* ppc-linux-tdep.c (ppc_atomic_single_step): New function.
	(ppc_linux_init_abi): Set software_single_step member of the gdbarch
	vector to the new ppc_atomic_single_step function.

Index: ppc-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-tdep.c,v
retrieving revision 1.78
diff -a -u -r1.78 ppc-linux-tdep.c
--- ppc-linux-tdep.c	18 Apr 2006 19:20:06 -0000	1.78
+++ ppc-linux-tdep.c	22 Jun 2006 18:26:16 -0000
@@ -927,6 +927,84 @@
   trad_frame_set_id (this_cache, frame_id_build (base, func));
 }
 
+#define LWARX_MASK 0xfc0007fe
+#define LWARX_INSTRUCTION 0x7C000028
+#define STWCX_MASK 0xfc0007ff
+#define STWCX_INSTRUCTION 0x7c00012d
+#define BC_MASK 0xfc000000
+#define BC_INSTRUCTION 0x40000000
+#define IMMEDIATE_PART(insn)  (((insn & ~3) << 16) >> 16)
+#define ABSOLUTE_P(insn) ((int) ((insn >> 1) & 1))
+
+static int 
+ppc_atomic_single_step (enum target_signal sig, int insert_breakpoints_p)
+{
+  if (insert_breakpoints_p)
+    {
+      CORE_ADDR pc = read_pc ();
+      CORE_ADDR breaks[2] = {-1, -1};
+      CORE_ADDR loc = pc;
+      int insn = read_insn (loc);
+      int last_break = 0;
+      int i;
+
+
+      /* Assume all atomic sequences start with an lwarx instruction. */
+      if ((insn & LWARX_MASK) != LWARX_INSTRUCTION)
+         return 0;
+
+      /* Assume that no atomic sequence is longer than 6 instructions. */
+      for (i= 1; i < 5; ++i)
+	{
+	  loc += PPC_INSN_SIZE;
+	  insn = read_insn (loc);
+
+	  /* Assume at most one conditional branch instruction between
+	     the lwarx and stwcx instructions.*/
+	  if ((insn & BC_MASK) == BC_INSTRUCTION)
+	    {
+	      last_break = 1;
+	      breaks[1] = IMMEDIATE_PART (insn);
+	      if ( ! ABSOLUTE_P(insn))
+		breaks[1] += loc;
+	      continue;
+	    }
+
+	  if ((insn & STWCX_MASK) == STWCX_INSTRUCTION)
+	    break;
+	}
+
+      /* Assume that the atomic sequence ends with a stwcx instruction
+         followed by a conditional branch instruction. */
+      if ((insn & STWCX_MASK) != STWCX_INSTRUCTION)
+	error (_("Tried to step over an atomic sequence of instructions but could not find the end of the sequence."));
+
+      loc += PPC_INSN_SIZE;
+      insn = read_insn (loc);
+
+      if ((insn & BC_MASK) != BC_INSTRUCTION)
+	error (_("Tried to step over an atomic sequence of instructions but it did not end as expected."));
+
+      breaks[0] = loc;
+
+      /* This should never happen, but make sure we don't but
+	 two breakpoints on the same address. */
+      if (last_break && breaks[1] == breaks[0])
+	last_break = 0;
+
+      for (i= 0; i < last_break; ++i)
+	insert_single_step_breakpoint (breaks[i]);
+
+      printf_unfiltered (_("Stepping over an atomic sequence of instructions beginning at %s\n"),
+			 core_addr_to_string (pc));
+      gdb_flush (gdb_stdout);
+    }
+  else
+    remove_single_step_breakpoints ();
+
+  return 1;
+}
+
 static void
 ppc32_linux_sigaction_cache_init (const struct tramp_frame *self,
 				  struct frame_info *next_frame,
@@ -1080,6 +1158,10 @@
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
                                              svr4_fetch_objfile_link_map);
+
+  /* Enable software_single_step in case someone tries to sngle step a
+     sequence of instructions that should be atomic. */
+  set_gdbarch_software_single_step (gdbarch, ppc_atomic_single_step);
 }
 
 void

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