https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=235186 2007-01-10 Daniel Jacobowitz * 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 * 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 * 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 * 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 * 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 Luis Machado * 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