diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f8bb86afc3..e50e86d5a8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2004-10-31 Orjan Friberg + Andrew Cagney + + * gdbarch.sh (single_step_through_delay): Add. + * gdbarch.h, gdbarch.c: Re-generate. + * config/mips/tm-mips.h (STEP_SKIPS_DELAY_P, STEP_SKIPS_DELAY) + (mips_step_skips_delay): Delete. + * mips-tdep.c (mips_single_step_through_delay): Replace + mips_step_skips_delay. + (mips_gdbarch_init): Set single_step_through_delay. + (mips_dump_tdep): Do not print STEP_SKIPS_DELAY. + 2004-10-31 Mark Kettenis * tramp-frame.c (tramp_frame_prepend_unwinder): Set unwinder type diff --git a/gdb/config/mips/tm-mips.h b/gdb/config/mips/tm-mips.h index 0830342965..09af61d303 100644 --- a/gdb/config/mips/tm-mips.h +++ b/gdb/config/mips/tm-mips.h @@ -33,12 +33,6 @@ struct symbol; struct type; struct value; -/* Return non-zero if PC points to an instruction which will cause a step - to execute both the instruction at PC and an instruction at PC+4. */ -extern int mips_step_skips_delay (CORE_ADDR); -#define STEP_SKIPS_DELAY_P (1) -#define STEP_SKIPS_DELAY(pc) (mips_step_skips_delay (pc)) - /* Special symbol found in blocks associated with routines. We can hang mdebug_extra_func_info's off of this. */ diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 7eb4aeb14b..e822fa6866 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -211,6 +211,7 @@ struct gdbarch gdbarch_addr_bits_remove_ftype *addr_bits_remove; gdbarch_smash_text_address_ftype *smash_text_address; gdbarch_software_single_step_ftype *software_single_step; + gdbarch_single_step_through_delay_ftype *single_step_through_delay; gdbarch_print_insn_ftype *print_insn; gdbarch_skip_trampoline_code_ftype *skip_trampoline_code; gdbarch_skip_solib_resolver_ftype *skip_solib_resolver; @@ -337,6 +338,7 @@ struct gdbarch startup_gdbarch = 0, /* addr_bits_remove */ 0, /* smash_text_address */ 0, /* software_single_step */ + 0, /* single_step_through_delay */ 0, /* print_insn */ 0, /* skip_trampoline_code */ generic_skip_solib_resolver, /* skip_solib_resolver */ @@ -591,6 +593,7 @@ verify_gdbarch (struct gdbarch *current_gdbarch) /* Skip verify of addr_bits_remove, invalid_p == 0 */ /* Skip verify of smash_text_address, invalid_p == 0 */ /* Skip verify of software_single_step, has predicate */ + /* Skip verify of single_step_through_delay, has predicate */ if (current_gdbarch->print_insn == 0) fprintf_unfiltered (log, "\n\tprint_insn"); /* Skip verify of skip_trampoline_code, invalid_p == 0 */ @@ -1516,6 +1519,12 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: short_bit = %s\n", paddr_d (current_gdbarch->short_bit)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_single_step_through_delay_p() = %d\n", + gdbarch_single_step_through_delay_p (current_gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: single_step_through_delay = <0x%lx>\n", + (long) current_gdbarch->single_step_through_delay); #ifdef SKIP_PROLOGUE fprintf_unfiltered (file, "gdbarch_dump: %s # %s\n", @@ -3345,6 +3354,30 @@ set_gdbarch_software_single_step (struct gdbarch *gdbarch, gdbarch->software_single_step = software_single_step; } +int +gdbarch_single_step_through_delay_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->single_step_through_delay != NULL; +} + +int +gdbarch_single_step_through_delay (struct gdbarch *gdbarch, struct frame_info *frame) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->single_step_through_delay != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_single_step_through_delay called\n"); + return gdbarch->single_step_through_delay (gdbarch, frame); +} + +void +set_gdbarch_single_step_through_delay (struct gdbarch *gdbarch, + gdbarch_single_step_through_delay_ftype single_step_through_delay) +{ + gdbarch->single_step_through_delay = single_step_through_delay; +} + int gdbarch_print_insn (struct gdbarch *gdbarch, bfd_vma vma, struct disassemble_info *info) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 78b27ba4ef..8ff296c071 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -1218,6 +1218,15 @@ extern void set_gdbarch_software_single_step (struct gdbarch *gdbarch, gdbarch_s #define SOFTWARE_SINGLE_STEP(sig, insert_breakpoints_p) (gdbarch_software_single_step (current_gdbarch, sig, insert_breakpoints_p)) #endif +/* Return non-zero if the processor is executing a delay slot and a + further single-step is needed before the instruction finishes. */ + +extern int gdbarch_single_step_through_delay_p (struct gdbarch *gdbarch); + +typedef int (gdbarch_single_step_through_delay_ftype) (struct gdbarch *gdbarch, struct frame_info *frame); +extern int gdbarch_single_step_through_delay (struct gdbarch *gdbarch, struct frame_info *frame); +extern void set_gdbarch_single_step_through_delay (struct gdbarch *gdbarch, gdbarch_single_step_through_delay_ftype *single_step_through_delay); + /* FIXME: cagney/2003-08-28: Need to find a better way of selecting the disassembler. Perhaps objdump can handle it? */ diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 3ffb85e24d..fec4c7a12f 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -611,6 +611,9 @@ f:=:CORE_ADDR:smash_text_address:CORE_ADDR addr:addr::core_addr_identity::0 # 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 +# 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 # FIXME: cagney/2003-08-28: Need to find a better way of selecting the # disassembler. Perhaps objdump can handle it? f:TARGET_PRINT_INSN:int:print_insn:bfd_vma vma, struct disassemble_info *info:vma, info::0: diff --git a/gdb/infrun.c b/gdb/infrun.c index d35ecde14e..396a61647f 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -714,24 +714,17 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) if (addr == (CORE_ADDR) -1) { - /* If there is a breakpoint at the address we will resume at, - step one instruction before inserting breakpoints - so that we do not stop right away (and report a second - hit at this breakpoint). */ - if (read_pc () == stop_pc && breakpoint_here_p (read_pc ())) + /* There is a breakpoint at the address we will resume at, + step one instruction before inserting breakpoints so that + we do not stop right away (and report a second hit at this + breakpoint). */ oneproc = 1; - -#ifndef STEP_SKIPS_DELAY -#define STEP_SKIPS_DELAY(pc) (0) -#define STEP_SKIPS_DELAY_P (0) -#endif - /* Check breakpoint_here_p first, because breakpoint_here_p is fast - (it just checks internal GDB data structures) and STEP_SKIPS_DELAY - is slow (it needs to read memory from the target). */ - if (STEP_SKIPS_DELAY_P - && breakpoint_here_p (read_pc () + 4) - && STEP_SKIPS_DELAY (read_pc ())) + else if (gdbarch_single_step_through_delay_p (current_gdbarch) + && gdbarch_single_step_through_delay (current_gdbarch, + get_current_frame ())) + /* We stepped onto an instruction that needs to be stepped + again before re-inserting the breakpoint, do so. */ oneproc = 1; } else @@ -1781,6 +1774,39 @@ handle_inferior_event (struct execution_control_state *ecs) stopped_by_random_signal = 0; breakpoints_failed = 0; + if (stop_signal == TARGET_SIGNAL_TRAP + && trap_expected + && gdbarch_single_step_through_delay_p (current_gdbarch) + && currently_stepping (ecs)) + { + /* We're trying to step of a breakpoint. Turns out that we're + also on an instruction that needs to be stepped multiple + times before it's been fully executing. E.g., architectures + with a delay slot. It needs to be stepped twice, once for + the instruction and once for the delay slot. */ + int step_through_delay + = gdbarch_single_step_through_delay (current_gdbarch, + get_current_frame ()); + if (step_range_end == 0 && step_through_delay) + { + /* The user issued a continue when stopped at a breakpoint. + Set up for another trap and get out of here. */ + ecs->another_trap = 1; + keep_going (ecs); + return; + } + else if (step_through_delay) + { + /* The user issued a step when stopped at a breakpoint. + Maybe we should stop, maybe we should not - the delay + slot *might* correspond to a line of source. In any + case, don't decide that here, just set ecs->another_trap, + making sure we single-step again before breakpoints are + re-inserted. */ + ecs->another_trap = 1; + } + } + /* Look at the cause of the stop, and decide what to do. The alternatives are: 1) break; to really stop and return to the debugger, diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 047abe5d3a..686b8b1c4f 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -4142,16 +4142,19 @@ is_delayed (unsigned long insn) } int -mips_step_skips_delay (CORE_ADDR pc) +mips_single_step_through_delay (struct gdbarch *gdbarch, + struct frame_info *frame) { + CORE_ADDR pc = get_frame_pc (frame); char buf[MIPS_INSN32_SIZE]; /* There is no branch delay slot on MIPS16. */ if (mips_pc_is_mips16 (pc)) return 0; - if (target_read_memory (pc, buf, sizeof buf) != 0) - /* If error reading memory, guess that it is not a delayed branch. */ + if (!safe_frame_unwind_memory (frame, pc, buf, sizeof buf)) + /* If error reading memory, guess that it is not a delayed + branch. */ return 0; return is_delayed (extract_unsigned_integer (buf, sizeof buf)); } @@ -5097,6 +5100,8 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_in_solib_return_trampoline (gdbarch, mips_in_solib_return_trampoline); } + set_gdbarch_single_step_through_delay (gdbarch, mips_single_step_through_delay); + /* Hook in OS ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); @@ -5304,9 +5309,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) fprintf_unfiltered (file, "mips_dump_tdep: STEP_SKIPS_DELAY # %s\n", XSTRING (STEP_SKIPS_DELAY (PC))); - fprintf_unfiltered (file, - "mips_dump_tdep: STEP_SKIPS_DELAY_P = %d\n", - STEP_SKIPS_DELAY_P); fprintf_unfiltered (file, "mips_dump_tdep: STOPPED_BY_WATCHPOINT # %s\n", XSTRING (STOPPED_BY_WATCHPOINT (WS)));