Blob Blame History Raw
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=235186

2007-01-10  Daniel Jacobowitz  <dan@codesourcery.com>

	* infrun.c (singlestep_pc): New variable.
	(resume): Set singlestep_pc.
	(context_switch): Add a debugging message.  Flush the frame cache.
	(handle_inferior_event): Add debugging messages.  Handle thread
	hops when a software single step has completed.  Let context_switch
	handle flushing the frame cache.

--- ./gdb/infrun.c	9 Jan 2007 17:58:51 -0000	1.218
+++ ./gdb/infrun.c	10 Jan 2007 20:10:23 -0000	1.219
@@ -469,6 +469,9 @@ static int singlestep_breakpoints_insert
 /* The thread we inserted single-step breakpoints for.  */
 static ptid_t singlestep_ptid;
 
+/* PC when we started this single-step.  */
+static CORE_ADDR singlestep_pc;
+
 /* If another thread hit the singlestep breakpoint, we save the original
    thread here so that we can resume single-stepping it later.  */
 static ptid_t saved_singlestep_ptid;
@@ -563,6 +566,7 @@ resume (int step, enum target_signal sig
          `wait_for_inferior' */
       singlestep_breakpoints_inserted_p = 1;
       singlestep_ptid = inferior_ptid;
+      singlestep_pc = read_pc ();
     }
 
   /* If there were any forks/vforks/execs that were caught and are
@@ -1126,6 +1130,14 @@ context_switch (struct execution_control
      be lost.  This may happen as a result of the target module
      mishandling thread creation.  */
 
+  if (debug_infrun)
+    {
+      fprintf_unfiltered (gdb_stdlog, "infrun: Switching context from %s ",
+			  target_pid_to_str (inferior_ptid));
+      fprintf_unfiltered (gdb_stdlog, "to %s\n",
+			  target_pid_to_str (ecs->ptid));
+    }
+
   if (in_thread_list (inferior_ptid) && in_thread_list (ecs->ptid))
     {				/* Perform infrun state context switch: */
       /* Save infrun state for the old thread.  */
@@ -1149,6 +1161,7 @@ context_switch (struct execution_control
 			 &ecs->current_line, &ecs->current_symtab);
     }
   inferior_ptid = ecs->ptid;
+  flush_cached_frames ();
 }
 
 static void
@@ -1609,6 +1622,14 @@ handle_inferior_event (struct execution_
 	}
       else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
 	{
+	  /* We have not context switched yet, so this should be true
+	     no matter which thread hit the singlestep breakpoint.  */
+	  gdb_assert (ptid_equal (inferior_ptid, singlestep_ptid));
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog, "infrun: software single step "
+				"trap for %s\n",
+				target_pid_to_str (ecs->ptid));
+
 	  ecs->random_signal = 0;
 	  /* The call to in_thread_list is necessary because PTIDs sometimes
 	     change when we go from single-threaded to multi-threaded.  If
@@ -1617,9 +1638,46 @@ handle_inferior_event (struct execution_
 	  if (!ptid_equal (singlestep_ptid, ecs->ptid)
 	      && in_thread_list (singlestep_ptid))
 	    {
-	      thread_hop_needed = 1;
-	      stepping_past_singlestep_breakpoint = 1;
-	      saved_singlestep_ptid = singlestep_ptid;
+	      /* If the PC of the thread we were trying to single-step
+		 has changed, discard this event (which we were going
+		 to ignore anyway), and pretend we saw that thread
+		 trap.  This prevents us continuously moving the
+		 single-step breakpoint forward, one instruction at a
+		 time.  If the PC has changed, then the thread we were
+		 trying to single-step has trapped or been signalled,
+		 but the event has not been reported to GDB yet.
+
+		 There might be some cases where this loses signal
+		 information, if a signal has arrived at exactly the
+		 same time that the PC changed, but this is the best
+		 we can do with the information available.  Perhaps we
+		 should arrange to report all events for all threads
+		 when they stop, or to re-poll the remote looking for
+		 this particular thread (i.e. temporarily enable
+		 schedlock).  */
+             if (read_pc_pid (singlestep_ptid) != singlestep_pc)
+	       {
+		 if (debug_infrun)
+		   fprintf_unfiltered (gdb_stdlog, "infrun: unexpected thread,"
+				       " but expected thread advanced also\n");
+
+		 /* The current context still belongs to
+		    singlestep_ptid.  Don't swap here, since that's
+		    the context we want to use.  Just fudge our
+		    state and continue.  */
+                 ecs->ptid = singlestep_ptid;
+                 stop_pc = read_pc_pid (ecs->ptid);
+               }
+             else
+	       {
+		 if (debug_infrun)
+		   fprintf_unfiltered (gdb_stdlog,
+				       "infrun: unexpected thread\n");
+
+		 thread_hop_needed = 1;
+		 stepping_past_singlestep_breakpoint = 1;
+		 saved_singlestep_ptid = singlestep_ptid;
+	       }
 	    }
 	}
 
@@ -1702,8 +1760,6 @@ handle_inferior_event (struct execution_
 
       if (deprecated_context_hook)
 	deprecated_context_hook (pid_to_thread_id (ecs->ptid));
-
-      flush_cached_frames ();
     }
 
   if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)



2007-04-12  Luis Machado  <luisgpm@br.ibm.com>

	* gdbarch.sh (software_single_step): Change the return type
	from void to int and reformatted some comments to <= 80
	columns.
	* gdbarch.c, gdbarch.h: Regenerated.
	* alpha-tdep.c (alpha_software_single_step): Likewise.
	* alpha-tdep.h (alpha_software_single_step): Likewise.
	* arm-tdep.c (arm_software_single_step): Likewise.
	* cris-tdep.c (cris_software_single_step): Likewise.
	* mips-tdep.c (mips_software_single_step): Likewise.
	* mips-tdep.h (mips_software_single_step): Likewise.
	* rs6000-tdep.c (rs6000_software_single_step): Likewise.
	* rs6000-tdep.h (rs6000_software_single_step): Likewise.
	* sparc-tdep.c (sparc_software_single_step): Likewise.
	* sparc-tdep.h (sparc_software_single_step): Likewise.
[REMOVED]	* spu-tdep.c (spu_software_single_step): Likewise.
	* infrun.c (resume): Check the return value from SOFTWARE_SINGLE_STEP
	and act accordingly.

--- ./gdb/alpha-tdep.c	27 Feb 2007 20:17:18 -0000	1.162
+++ ./gdb/alpha-tdep.c	12 Apr 2007 14:52:19 -0000	1.163
@@ -1518,7 +1518,7 @@ alpha_next_pc (CORE_ADDR pc)
   return (pc + ALPHA_INSN_SIZE);
 }
 
-void
+int
 alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p)
 {
   static CORE_ADDR next_pc;
@@ -1536,6 +1536,7 @@ alpha_software_single_step (enum target_
       remove_single_step_breakpoints ();
       write_pc (next_pc);
     }
+  return 1;
 }
 
 
--- ./gdb/alpha-tdep.h	9 Jan 2007 17:58:49 -0000	1.27
+++ ./gdb/alpha-tdep.h	12 Apr 2007 14:52:19 -0000	1.28
@@ -107,7 +107,7 @@ struct gdbarch_tdep
 };
 
 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 *);
--- ./gdb/arm-tdep.c	30 Mar 2007 22:50:33 -0000	1.225
+++ ./gdb/arm-tdep.c	12 Apr 2007 14:52:19 -0000	1.226
@@ -1907,7 +1907,7 @@ arm_get_next_pc (CORE_ADDR pc)
    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
@@ -1922,6 +1922,8 @@ arm_software_single_step (enum target_si
     }
   else
     remove_single_step_breakpoints ();
+
+  return 1;
 }
 
 #include "bfd-in2.h"
--- ./gdb/cris-tdep.c	27 Feb 2007 20:17:18 -0000	1.138
+++ ./gdb/cris-tdep.c	12 Apr 2007 14:52:19 -0000	1.139
@@ -2119,7 +2119,7 @@ find_step_target (inst_env_type *inst_en
    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;
@@ -2152,6 +2152,8 @@ cris_software_single_step (enum target_s
     }
   else
     remove_single_step_breakpoints ();
+
+  return 1;
 }
 
 /* Calculates the prefix value for quick offset addressing mode.  */
--- ./gdb/gdbarch.c	28 Feb 2007 17:34:58 -0000	1.338
+++ ./gdb/gdbarch.c	12 Apr 2007 14:52:19 -0000	1.339
@@ -3289,14 +3289,14 @@ gdbarch_software_single_step_p (struct g
   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
--- ./gdb/gdbarch.h	8 Feb 2007 21:00:29 -0000	1.294
+++ ./gdb/gdbarch.h	12 Apr 2007 14:52:19 -0000	1.295
@@ -1144,14 +1144,19 @@ extern void set_gdbarch_smash_text_addre
 #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.
+  
+   A return value of 1 means that the software_single_step breakpoints
+   were inserted; 0 means they were not. */
 
 #if defined (SOFTWARE_SINGLE_STEP)
 /* Legacy for systems yet to multi-arch SOFTWARE_SINGLE_STEP */
@@ -1168,8 +1173,8 @@ extern int gdbarch_software_single_step_
 #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"
--- ./gdb/gdbarch.sh	28 Feb 2007 17:35:00 -0000	1.376
+++ ./gdb/gdbarch.sh	12 Apr 2007 14:52:19 -0000	1.377
@@ -614,15 +614,22 @@ f:=:CORE_ADDR:addr_bits_remove:CORE_ADDR
 # 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.
 #
-# 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
+# A return value of 1 means that the software_single_step breakpoints 
+# were inserted; 0 means they were not.
+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
--- ./gdb/infrun.c	29 Mar 2007 07:35:39 -0000	1.225
+++ ./gdb/infrun.c	12 Apr 2007 14:52:19 -0000	1.226
@@ -548,14 +548,16 @@ resume (int step, enum target_signal sig
   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;
-      singlestep_pc = read_pc ();
+      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;
+          singlestep_pc = read_pc ();
+        }
     }
 
   /* If there were any forks/vforks/execs that were caught and are
@@ -1378,7 +1380,7 @@ handle_inferior_event (struct execution_
 					   (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;
@@ -1398,7 +1400,7 @@ handle_inferior_event (struct execution_
       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;
 
@@ -1569,7 +1571,7 @@ handle_inferior_event (struct execution_
 	  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;
@@ -1678,7 +1680,7 @@ handle_inferior_event (struct execution_
 	  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;
 	    }
 
@@ -1749,7 +1751,7 @@ handle_inferior_event (struct execution_
   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;
     }
 
--- ./gdb/mips-tdep.c	30 Mar 2007 22:50:33 -0000	1.407
+++ ./gdb/mips-tdep.c	12 Apr 2007 14:52:19 -0000	1.408
@@ -2204,7 +2204,7 @@ mips_addr_bits_remove (CORE_ADDR addr)
    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;
@@ -2218,6 +2218,8 @@ mips_software_single_step (enum target_s
     }
   else
     remove_single_step_breakpoints ();
+
+  return 1;
 }
 
 /* Test whether the PC points to the return instruction at the
--- ./gdb/mips-tdep.h	30 Mar 2007 22:50:33 -0000	1.20
+++ ./gdb/mips-tdep.h	12 Apr 2007 14:52:20 -0000	1.21
@@ -100,7 +100,7 @@ enum
 };
 
 /* 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.  */
--- ./gdb/rs6000-tdep.c	10 Apr 2007 16:02:41 -0000	1.270
+++ ./gdb/rs6000-tdep.c	12 Apr 2007 14:52:20 -0000	1.271
@@ -722,7 +722,7 @@ rs6000_breakpoint_from_pc (CORE_ADDR *bp
 
 /* AIX does not support PT_STEP. Simulate it. */
 
-void
+int
 rs6000_software_single_step (enum target_signal signal,
 			     int insert_breakpoints_p)
 {
@@ -761,6 +761,7 @@ rs6000_software_single_step (enum target
 
   errno = 0;			/* FIXME, don't ignore errors! */
   /* What errors?  {read,write}_memory call error().  */
+  return 1;
 }
 
 
--- ./gdb/rs6000-tdep.h	27 Feb 2007 23:04:28 -0000	1.3
+++ ./gdb/rs6000-tdep.h	12 Apr 2007 14:52:20 -0000	1.4
@@ -21,8 +21,8 @@
 
 #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);
 
 /* Hook in rs6000-tdep.c for determining the TOC address when
    calling functions in the inferior.  */
--- ./gdb/sparc-tdep.c	11 Apr 2007 07:10:08 -0000	1.179
+++ ./gdb/sparc-tdep.c	12 Apr 2007 14:52:20 -0000	1.180
@@ -1329,7 +1329,7 @@ sparc_step_trap (unsigned long insn)
   return 0;
 }
 
-void
+int
 sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
 {
   struct gdbarch *arch = current_gdbarch;
@@ -1359,6 +1359,8 @@ sparc_software_single_step (enum target_
     }
   else
     remove_single_step_breakpoints ();
+
+  return 1;
 }
 
 static void
--- ./gdb/sparc-tdep.h	9 Jan 2007 17:58:58 -0000	1.12
+++ ./gdb/sparc-tdep.h	12 Apr 2007 14:52:20 -0000	1.13
@@ -167,8 +167,8 @@ extern struct sparc_frame_cache *
 
 
 
-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);



2007-04-14  Ulrich Weigand  <uweigand@de.ibm.com>

	* alpha-tdep.c (alpha_software_single_step): Do not call write_pc
	when removing single-step breakpoints.

--- ./gdb/alpha-tdep.c	12 Apr 2007 14:52:19 -0000	1.163
+++ ./gdb/alpha-tdep.c	14 Apr 2007 16:17:39 -0000	1.164
@@ -1521,7 +1521,7 @@ alpha_next_pc (CORE_ADDR pc)
 int
 alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p)
 {
-  static CORE_ADDR next_pc;
+  CORE_ADDR next_pc;
   CORE_ADDR pc;
 
   if (insert_breakpoints_p)
@@ -1534,7 +1534,6 @@ alpha_software_single_step (enum target_
   else
     {
       remove_single_step_breakpoints ();
-      write_pc (next_pc);
     }
   return 1;
 }



2007-04-14  Ulrich Weigand  <uweigand@de.ibm.com>

	* gdbarch.sh (software_single_step): Remove "insert_breakpoints_p" and
	"sig" arguments, add "regcache" argument.
	* gdbarch.c, gdbarch.h: Regenerate.

	* infrun.c (resume): Update SOFTWARE_SINGLE_STEP call arguments.
	(handle_inferior_event): Call remove_single_step_breakpoints directly
	instead of calling SOFTWARE_SINGLE_STEP to remove breakpoints.

	* alpha-tdep.c (alpha_software_single_step): Update argument list.
	Remove handling of !insert_breakpoints_p case.
	* arm-tdep.c (arm_software_single_step): Likewise.
	* cris-tdep.c (cris_software_single_step): Likewise.
	* mips-tdep.c (mips_software_single_step): Likewise.
	* rs6000-tdep.c (rs6000_software_single_step): Likewise.
	* sparc-tdep.c (sparc_software_single_step): Likewise.
[REMOVED]	* spu-tdep.c (spu_software_single_step): Likewise.

	* alpha-tdep.h (alpha_software_single_step): Update prototype.
	* mips-tdep.h (mips_software_single_step): Likewise.
	* rs6000-tdep.h (rs6000_software_single_step): Likewise.
	* sparc-tdep.h (sparc_software_single_step): Likewise.

--- ./gdb/alpha-tdep.c	14 Apr 2007 16:17:39 -0000	1.164
+++ ./gdb/alpha-tdep.c	14 Apr 2007 18:10:54 -0000	1.165
@@ -1391,10 +1391,7 @@ fp_register_sign_bit (LONGEST reg)
 /* alpha_software_single_step() is called just before we want to resume
    the inferior, if we want to single-step it but there is no hardware
    or kernel single-step support (NetBSD on Alpha, for example).  We find
-   the target of the coming instruction and breakpoint it.
-
-   single_step is also called just after the inferior stops.  If we had
-   set up a simulated single-step, we undo our damage.  */
+   the target of the coming instruction and breakpoint it.  */
 
 static CORE_ADDR
 alpha_next_pc (CORE_ADDR pc)
@@ -1519,22 +1516,14 @@ alpha_next_pc (CORE_ADDR pc)
 }
 
 int
-alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+alpha_software_single_step (struct regcache *regcache)
 {
-  CORE_ADDR next_pc;
-  CORE_ADDR pc;
+  CORE_ADDR pc, next_pc;
 
-  if (insert_breakpoints_p)
-    {
-      pc = read_pc ();
-      next_pc = alpha_next_pc (pc);
+  pc = read_pc ();
+  next_pc = alpha_next_pc (pc);
 
-      insert_single_step_breakpoint (next_pc);
-    }
-  else
-    {
-      remove_single_step_breakpoints ();
-    }
+  insert_single_step_breakpoint (next_pc);
   return 1;
 }
 
--- ./gdb/alpha-tdep.h	12 Apr 2007 14:52:19 -0000	1.28
+++ ./gdb/alpha-tdep.h	14 Apr 2007 18:10:54 -0000	1.29
@@ -107,7 +107,7 @@ struct gdbarch_tdep
 };
 
 extern unsigned int alpha_read_insn (CORE_ADDR pc);
-extern int alpha_software_single_step (enum target_signal, int);
+extern int alpha_software_single_step (struct regcache *regcache);
 extern CORE_ADDR alpha_after_prologue (CORE_ADDR pc);
 
 extern void alpha_mdebug_init_abi (struct gdbarch_info, struct gdbarch *);
--- ./gdb/arm-tdep.c	12 Apr 2007 14:52:19 -0000	1.226
+++ ./gdb/arm-tdep.c	14 Apr 2007 18:10:54 -0000	1.227
@@ -1902,26 +1902,17 @@ arm_get_next_pc (CORE_ADDR pc)
 /* single_step() is called just before we want to resume the inferior,
    if we want to single-step it but there is no hardware or kernel
    single-step support.  We find the target of the coming instruction
-   and breakpoint it.
-
-   single_step() is also called just after the inferior stops.  If we
-   had set up a simulated single-step, we undo our damage.  */
+   and breakpoint it.  */
 
 static int
-arm_software_single_step (enum target_signal sig, int insert_bpt)
+arm_software_single_step (struct regcache *regcache)
 {
   /* NOTE: This may insert the wrong breakpoint instruction when
      single-stepping over a mode-changing instruction, if the
      CPSR heuristics are used.  */
 
-  if (insert_bpt)
-    {
-      CORE_ADDR next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
-
-      insert_single_step_breakpoint (next_pc);
-    }
-  else
-    remove_single_step_breakpoints ();
+  CORE_ADDR next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
+  insert_single_step_breakpoint (next_pc);
 
   return 1;
 }
--- ./gdb/cris-tdep.c	12 Apr 2007 14:52:19 -0000	1.139
+++ ./gdb/cris-tdep.c	14 Apr 2007 18:10:54 -0000	1.140
@@ -2120,38 +2120,33 @@ find_step_target (inst_env_type *inst_en
    Either one ordinary target or two targets for branches may be found.  */
 
 static int
-cris_software_single_step (enum target_signal ignore, int insert_breakpoints)
+cris_software_single_step (struct regcache *regcache)
 {
   inst_env_type inst_env;
 
-  if (insert_breakpoints)
-    {
-      /* Analyse the present instruction environment and insert 
-         breakpoints.  */
-      int status = find_step_target (&inst_env);
-      if (status == -1)
-        {
-          /* Could not find a target.  Things are likely to go downhill 
-	     from here.  */
-	  warning (_("CRIS software single step could not find a step target."));
-        }
-      else
-        {
-          /* Insert at most two breakpoints.  One for the next PC content
-             and possibly another one for a branch, jump, etc.  */
-          CORE_ADDR next_pc = (CORE_ADDR) inst_env.reg[PC_REGNUM];
-          insert_single_step_breakpoint (next_pc);
-          if (inst_env.branch_found 
-              && (CORE_ADDR) inst_env.branch_break_address != next_pc)
-            {
-              CORE_ADDR branch_target_address
-                = (CORE_ADDR) inst_env.branch_break_address;
-              insert_single_step_breakpoint (branch_target_address);
-            }
-        }
+  /* Analyse the present instruction environment and insert 
+     breakpoints.  */
+  int status = find_step_target (&inst_env);
+  if (status == -1)
+    {
+      /* Could not find a target.  Things are likely to go downhill 
+	 from here.  */
+      warning (_("CRIS software single step could not find a step target."));
     }
   else
-    remove_single_step_breakpoints ();
+    {
+      /* Insert at most two breakpoints.  One for the next PC content
+         and possibly another one for a branch, jump, etc.  */
+      CORE_ADDR next_pc = (CORE_ADDR) inst_env.reg[PC_REGNUM];
+      insert_single_step_breakpoint (next_pc);
+      if (inst_env.branch_found 
+	  && (CORE_ADDR) inst_env.branch_break_address != next_pc)
+	{
+	  CORE_ADDR branch_target_address
+		= (CORE_ADDR) inst_env.branch_break_address;
+	  insert_single_step_breakpoint (branch_target_address);
+	}
+    }
 
   return 1;
 }
--- ./gdb/gdbarch.c	12 Apr 2007 14:52:19 -0000	1.339
+++ ./gdb/gdbarch.c	14 Apr 2007 18:10:54 -0000	1.340
@@ -1522,8 +1522,8 @@ gdbarch_dump (struct gdbarch *current_gd
 #ifdef SOFTWARE_SINGLE_STEP
   fprintf_unfiltered (file,
                       "gdbarch_dump: %s # %s\n",
-                      "SOFTWARE_SINGLE_STEP(sig, insert_breakpoints_p)",
-                      XSTRING (SOFTWARE_SINGLE_STEP (sig, insert_breakpoints_p)));
+                      "SOFTWARE_SINGLE_STEP(regcache)",
+                      XSTRING (SOFTWARE_SINGLE_STEP (regcache)));
 #endif
   fprintf_unfiltered (file,
                       "gdbarch_dump: software_single_step = <0x%lx>\n",
@@ -3290,13 +3290,13 @@ gdbarch_software_single_step_p (struct g
 }
 
 int
-gdbarch_software_single_step (struct gdbarch *gdbarch, enum target_signal sig, int insert_breakpoints_p)
+gdbarch_software_single_step (struct gdbarch *gdbarch, struct regcache *regcache)
 {
   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");
-  return gdbarch->software_single_step (sig, insert_breakpoints_p);
+  return gdbarch->software_single_step (regcache);
 }
 
 void
--- ./gdb/gdbarch.h	12 Apr 2007 14:52:19 -0000	1.295
+++ ./gdb/gdbarch.h	14 Apr 2007 18:10:54 -0000	1.296
@@ -1173,14 +1173,14 @@ extern int gdbarch_software_single_step_
 #define SOFTWARE_SINGLE_STEP_P() (gdbarch_software_single_step_p (current_gdbarch))
 #endif
 
-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);
+typedef int (gdbarch_software_single_step_ftype) (struct regcache *regcache);
+extern int gdbarch_software_single_step (struct gdbarch *gdbarch, struct regcache *regcache);
 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"
 #endif
 #if !defined (SOFTWARE_SINGLE_STEP)
-#define SOFTWARE_SINGLE_STEP(sig, insert_breakpoints_p) (gdbarch_software_single_step (current_gdbarch, sig, insert_breakpoints_p))
+#define SOFTWARE_SINGLE_STEP(regcache) (gdbarch_software_single_step (current_gdbarch, regcache))
 #endif
 
 /* Return non-zero if the processor is executing a delay slot and a
--- ./gdb/gdbarch.sh	12 Apr 2007 14:52:19 -0000	1.377
+++ ./gdb/gdbarch.sh	14 Apr 2007 18:10:54 -0000	1.378
@@ -628,7 +628,7 @@ f:=:CORE_ADDR:smash_text_address:CORE_AD
 #
 # A return value of 1 means that the software_single_step breakpoints 
 # were inserted; 0 means they were not.
-F:=:int:software_single_step:enum target_signal sig, int insert_breakpoints_p:sig, insert_breakpoints_p
+F:=:int:software_single_step:struct regcache *regcache:regcache
 
 # Return non-zero if the processor is executing a delay slot and a
 # further single-step is needed before the instruction finishes.
--- ./gdb/infrun.c	13 Apr 2007 13:29:42 -0000	1.227
+++ ./gdb/infrun.c	14 Apr 2007 18:10:54 -0000	1.228
@@ -548,7 +548,7 @@ resume (int step, enum target_signal sig
   if (SOFTWARE_SINGLE_STEP_P () && step)
     {
       /* Do it the hard way, w/temp breakpoints */
-      if (SOFTWARE_SINGLE_STEP (sig, 1 /*insert-breakpoints */ ))
+      if (SOFTWARE_SINGLE_STEP (current_regcache))
         {
           /* ...and don't ask hardware to do it.  */
           step = 0;
@@ -1571,7 +1571,7 @@ handle_inferior_event (struct execution_
 	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog, "infrun: stepping_past_singlestep_breakpoint\n");
 	  /* Pull the single step breakpoints out of the target.  */
-	  (void) SOFTWARE_SINGLE_STEP (0, 0);
+	  remove_single_step_breakpoints ();
 	  singlestep_breakpoints_inserted_p = 0;
 
 	  ecs->random_signal = 0;
@@ -1680,7 +1680,7 @@ handle_inferior_event (struct execution_
 	  if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
 	    {
 	      /* Pull the single step breakpoints out of the target. */
-	      (void) SOFTWARE_SINGLE_STEP (0, 0);
+	      remove_single_step_breakpoints ();
 	      singlestep_breakpoints_inserted_p = 0;
 	    }
 
@@ -1751,7 +1751,7 @@ handle_inferior_event (struct execution_
   if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
     {
       /* Pull the single step breakpoints out of the target. */
-      (void) SOFTWARE_SINGLE_STEP (0, 0);
+      remove_single_step_breakpoints ();
       singlestep_breakpoints_inserted_p = 0;
     }
 
--- ./gdb/mips-tdep.c	12 Apr 2007 14:52:19 -0000	1.408
+++ ./gdb/mips-tdep.c	14 Apr 2007 18:10:54 -0000	1.409
@@ -2199,26 +2199,17 @@ mips_addr_bits_remove (CORE_ADDR addr)
 /* mips_software_single_step() is called just before we want to resume
    the inferior, if we want to single-step it but there is no hardware
    or kernel single-step support (MIPS on GNU/Linux for example).  We find
-   the target of the coming instruction and breakpoint it.
-
-   single_step is also called just after the inferior stops.  If we had
-   set up a simulated single-step, we undo our damage.  */
+   the target of the coming instruction and breakpoint it.  */
 
 int
-mips_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+mips_software_single_step (struct regcache *regcache)
 {
   CORE_ADDR pc, next_pc;
 
-  if (insert_breakpoints_p)
-    {
-      pc = read_register (mips_regnum (current_gdbarch)->pc);
-      next_pc = mips_next_pc (pc);
-
-      insert_single_step_breakpoint (next_pc);
-    }
-  else
-    remove_single_step_breakpoints ();
+  pc = read_register (mips_regnum (current_gdbarch)->pc);
+  next_pc = mips_next_pc (pc);
 
+  insert_single_step_breakpoint (next_pc);
   return 1;
 }
 
--- ./gdb/mips-tdep.h	12 Apr 2007 14:52:20 -0000	1.21
+++ ./gdb/mips-tdep.h	14 Apr 2007 18:10:54 -0000	1.22
@@ -100,7 +100,7 @@ enum
 };
 
 /* Single step based on where the current instruction will take us.  */
-extern int mips_software_single_step (enum target_signal, int);
+extern int mips_software_single_step (struct regcache *regcache);
 
 /* Tell if the program counter value in MEMADDR is in a MIPS16
    function.  */
--- ./gdb/rs6000-tdep.c	12 Apr 2007 14:52:20 -0000	1.271
+++ ./gdb/rs6000-tdep.c	14 Apr 2007 18:10:54 -0000	1.272
@@ -723,8 +723,7 @@ rs6000_breakpoint_from_pc (CORE_ADDR *bp
 /* AIX does not support PT_STEP. Simulate it. */
 
 int
-rs6000_software_single_step (enum target_signal signal,
-			     int insert_breakpoints_p)
+rs6000_software_single_step (struct regcache *regcache)
 {
   CORE_ADDR dummy;
   int breakp_sz;
@@ -734,30 +733,25 @@ rs6000_software_single_step (enum target
   CORE_ADDR breaks[2];
   int opcode;
 
-  if (insert_breakpoints_p)
-    {
-      loc = read_pc ();
+  loc = read_pc ();
 
-      insn = read_memory_integer (loc, 4);
+  insn = read_memory_integer (loc, 4);
 
-      breaks[0] = loc + breakp_sz;
-      opcode = insn >> 26;
-      breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);
+  breaks[0] = loc + breakp_sz;
+  opcode = insn >> 26;
+  breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);
 
-      /* Don't put two breakpoints on the same address. */
-      if (breaks[1] == breaks[0])
-	breaks[1] = -1;
+  /* Don't put two breakpoints on the same address. */
+  if (breaks[1] == breaks[0])
+    breaks[1] = -1;
 
-      for (ii = 0; ii < 2; ++ii)
-	{
-	  /* ignore invalid breakpoint. */
-	  if (breaks[ii] == -1)
-	    continue;
-	  insert_single_step_breakpoint (breaks[ii]);
-	}
+  for (ii = 0; ii < 2; ++ii)
+    {
+      /* ignore invalid breakpoint. */
+      if (breaks[ii] == -1)
+	continue;
+      insert_single_step_breakpoint (breaks[ii]);
     }
-  else
-    remove_single_step_breakpoints ();
 
   errno = 0;			/* FIXME, don't ignore errors! */
   /* What errors?  {read,write}_memory call error().  */
--- ./gdb/rs6000-tdep.h	12 Apr 2007 14:52:20 -0000	1.4
+++ ./gdb/rs6000-tdep.h	14 Apr 2007 18:10:54 -0000	1.5
@@ -21,8 +21,7 @@
 
 #include "defs.h"
 
-extern int rs6000_software_single_step (enum target_signal signal,
-                                        int insert_breakpoints_p);
+extern int rs6000_software_single_step (struct regcache *regcache);
 
 /* Hook in rs6000-tdep.c for determining the TOC address when
    calling functions in the inferior.  */
--- ./gdb/sparc-tdep.c	12 Apr 2007 14:52:20 -0000	1.180
+++ ./gdb/sparc-tdep.c	14 Apr 2007 18:10:54 -0000	1.181
@@ -1330,35 +1330,30 @@ sparc_step_trap (unsigned long insn)
 }
 
 int
-sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+sparc_software_single_step (struct regcache *regcache)
 {
   struct gdbarch *arch = current_gdbarch;
   struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
   CORE_ADDR npc, nnpc;
 
-  if (insert_breakpoints_p)
-    {
-      CORE_ADDR pc, orig_npc;
+  CORE_ADDR pc, orig_npc;
 
-      pc = sparc_address_from_register (tdep->pc_regnum);
-      orig_npc = npc = sparc_address_from_register (tdep->npc_regnum);
+  pc = sparc_address_from_register (tdep->pc_regnum);
+  orig_npc = npc = sparc_address_from_register (tdep->npc_regnum);
 
-      /* Analyze the instruction at PC.  */
-      nnpc = sparc_analyze_control_transfer (arch, pc, &npc);
-      if (npc != 0)
-	insert_single_step_breakpoint (npc);
-
-      if (nnpc != 0)
-	insert_single_step_breakpoint (nnpc);
-
-      /* Assert that we have set at least one breakpoint, and that
-	 they're not set at the same spot - unless we're going
-	 from here straight to NULL, i.e. a call or jump to 0.  */
-      gdb_assert (npc != 0 || nnpc != 0 || orig_npc == 0);
-      gdb_assert (nnpc != npc || orig_npc == 0);
-    }
-  else
-    remove_single_step_breakpoints ();
+  /* Analyze the instruction at PC.  */
+  nnpc = sparc_analyze_control_transfer (arch, pc, &npc);
+  if (npc != 0)
+    insert_single_step_breakpoint (npc);
+
+  if (nnpc != 0)
+    insert_single_step_breakpoint (nnpc);
+
+  /* Assert that we have set at least one breakpoint, and that
+     they're not set at the same spot - unless we're going
+     from here straight to NULL, i.e. a call or jump to 0.  */
+  gdb_assert (npc != 0 || nnpc != 0 || orig_npc == 0);
+  gdb_assert (nnpc != npc || orig_npc == 0);
 
   return 1;
 }
--- ./gdb/sparc-tdep.h	12 Apr 2007 14:52:20 -0000	1.13
+++ ./gdb/sparc-tdep.h	14 Apr 2007 18:10:54 -0000	1.14
@@ -167,8 +167,7 @@ extern struct sparc_frame_cache *
 
 
 
-extern int sparc_software_single_step (enum target_signal sig,
-                                       int insert_breakpoints_p);
+extern int sparc_software_single_step (struct regcache *regcache);
 
 extern void sparc_supply_rwindow (struct regcache *regcache,
 				  CORE_ADDR sp, int regnum);



2007-05-11  Ulrich Weigand  <uweigand@de.ibm.com>

	* breakpoint.c (single_step_breakpoint_inserted_here_p): New function.
	(breakpoint_inserted_here_p): Call it.
	(software_breakpoint_inserted_here_p): Likewise.

--- ./gdb/breakpoint.c	3 May 2007 17:42:25 -0000	1.247
+++ ./gdb/breakpoint.c	11 May 2007 12:44:34 -0000	1.248
@@ -202,6 +202,8 @@ static void tcatch_command (char *arg, i
 
 static void ep_skip_leading_whitespace (char **s);
 
+static int single_step_breakpoint_inserted_here_p (CORE_ADDR pc);
+
 /* Prototypes for exported functions. */
 
 /* If FALSE, gdb will not use hardware support for watchpoints, even
@@ -1841,6 +1843,10 @@ breakpoint_inserted_here_p (CORE_ADDR pc
 	}
     }
 
+  /* Also check for software single-step breakpoints.  */
+  if (single_step_breakpoint_inserted_here_p (pc))
+    return 1;
+
   return 0;
 }
 
@@ -1872,6 +1878,10 @@ software_breakpoint_inserted_here_p (COR
 	}
     }
 
+  /* Also check for software single-step breakpoints.  */
+  if (single_step_breakpoint_inserted_here_p (pc))
+    return 1;
+
   return 0;
 }
 
@@ -7951,6 +7961,23 @@ remove_single_step_breakpoints (void)
     }
 }
 
+/* Check whether a software single-step breakpoint is inserted at PC.  */
+
+static int
+single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
+{
+  int i;
+
+  for (i = 0; i < 2; i++)
+    {
+      struct bp_target_info *bp_tgt = single_step_breakpoints[i];
+      if (bp_tgt && bp_tgt->placed_address == pc)
+	return 1;
+    }
+
+  return 0;
+}
+
 
 /* This help string is used for the break, hbreak, tbreak and thbreak commands.
    It is defined as a macro to prevent duplication.



2007-05-08  Paul Gilliam  <pgilliam@us.ibm.com>
	    Luis Machado  <luisgpm@br.ibm.com>

	* rs6000-tdep.c: (LWARX_MASK, LWARX_INSTRUCTION, LDARX_INSTRUCTION,
	STWCX_MASK, STWCX_INSTRUCTION, STDCX_INSTRUCTION, BC_MASK,
	BC_INSTRUCTION): Define.
	(deal_with_atomic_sequence): New function.
	(rs6000_software_single_step): Call deal_with_atomic_sequence.
	(rs6000_gdbarch_init): Install deal_with_atomic_sequence as
	gdbarch_software_single_step routine.

--- ./gdb/rs6000-tdep.c	7 May 2007 01:25:07 -0000	1.274
+++ ./gdb/rs6000-tdep.c	8 May 2007 12:49:12 -0000	1.275
@@ -707,7 +707,95 @@ rs6000_breakpoint_from_pc (CORE_ADDR *bp
 }
 
 
-/* AIX does not support PT_STEP. Simulate it. */
+/* Instruction masks used during single-stepping of atomic sequences.  */
+#define LWARX_MASK 0xfc0007fe
+#define LWARX_INSTRUCTION 0x7c000028
+#define LDARX_INSTRUCTION 0x7c0000A8
+#define STWCX_MASK 0xfc0007ff
+#define STWCX_INSTRUCTION 0x7c00012d
+#define STDCX_INSTRUCTION 0x7c0001ad
+#define BC_MASK 0xfc000000
+#define BC_INSTRUCTION 0x40000000
+
+/* Checks for an atomic sequence of instructions beginning with a LWARX/LDARX
+   instruction and ending with a STWCX/STDCX instruction.  If such a sequence
+   is found, attempt to step through it.  A breakpoint is placed at the end of 
+   the sequence.  */
+
+static int 
+deal_with_atomic_sequence (struct regcache *regcache)
+{
+  CORE_ADDR pc = read_pc ();
+  CORE_ADDR breaks[2] = {-1, -1};
+  CORE_ADDR loc = pc;
+  CORE_ADDR branch_bp; /* Breakpoint at branch instruction's destination.  */
+  int insn = read_memory_integer (loc, PPC_INSN_SIZE);
+  int insn_count;
+  int index;
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */  
+  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+  const int opcode = BC_INSTRUCTION; /* Branch instruction's OPcode.  */
+  int bc_insn_count = 0; /* Conditional branch instruction count.  */
+
+  /* Assume all atomic sequences start with a lwarx/ldarx instruction.  */
+  if ((insn & LWARX_MASK) != LWARX_INSTRUCTION
+      && (insn & LWARX_MASK) != LDARX_INSTRUCTION)
+    return 0;
+
+  /* Assume that no atomic sequence is longer than "atomic_sequence_length" 
+     instructions.  */
+  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+    {
+      loc += PPC_INSN_SIZE;
+      insn = read_memory_integer (loc, PPC_INSN_SIZE);
+
+      /* Assume that there is at most one conditional branch in the atomic
+         sequence.  If a conditional branch is found, put a breakpoint in 
+         its destination address.  */
+      if ((insn & BC_MASK) == BC_INSTRUCTION)
+        {
+          if (bc_insn_count >= 1)
+            return 0; /* More than one conditional branch found, fallback 
+                         to the standard single-step code.  */
+          
+          branch_bp = branch_dest (opcode, insn, pc, breaks[0]);
+          
+          if (branch_bp != -1)
+            {
+              breaks[1] = branch_bp;
+              bc_insn_count++;
+              last_breakpoint++;
+            }
+        }
+
+      if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
+          || (insn & STWCX_MASK) == STDCX_INSTRUCTION)
+        break;
+    }
+
+  /* Assume that the atomic sequence ends with a stwcx/stdcx instruction.  */
+  if ((insn & STWCX_MASK) != STWCX_INSTRUCTION
+      && (insn & STWCX_MASK) != STDCX_INSTRUCTION)
+    return 0;
+
+  loc += PPC_INSN_SIZE;
+  insn = read_memory_integer (loc, PPC_INSN_SIZE);
+
+  /* Insert a breakpoint right after the end of the atomic sequence.  */
+  breaks[0] = loc;
+
+  /* Check for duplicated breakpoints.  */
+  if (last_breakpoint && (breaks[1] == breaks[0]))
+    last_breakpoint = 0;
+
+  /* Effectively inserts the breakpoints.  */
+  for (index = 0; index <= last_breakpoint; index++)
+    insert_single_step_breakpoint (breaks[index]);
+
+  return 1;
+}
+
+/* AIX does not support PT_STEP.  Simulate it.  */
 
 int
 rs6000_software_single_step (struct regcache *regcache)
@@ -724,6 +812,9 @@ rs6000_software_single_step (struct regc
 
   insn = read_memory_integer (loc, 4);
 
+  if (deal_with_atomic_sequence (regcache))
+    return 1;
+  
   breaks[0] = loc + breakp_sz;
   opcode = insn >> 26;
   breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);
@@ -3448,6 +3539,9 @@ rs6000_gdbarch_init (struct gdbarch_info
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);
 
+  /* Handles single stepping of atomic sequences.  */
+  set_gdbarch_software_single_step (gdbarch, deal_with_atomic_sequence);
+  
   /* Handle the 64-bit SVR4 minimal-symbol convention of using "FN"
      for the descriptor and ".FN" for the entry-point -- a user
      specifying "break FN" will unexpectedly end up with a breakpoint