--- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1781,8 +1781,9 @@ how to step past a permanent breakpoint a command like `return' or `jump' to continue execution.")); } - /* If enabled, step over breakpoints by executing a copy of the - instruction at a different address. + /* If enabled and this target doesn't continue over breakpoints, + step over breakpoints by executing a copy of the instruction + at a different address. We can't use displaced stepping when we have a signal to deliver; the comments for displaced_step_prepare explain why. The @@ -1792,7 +1793,8 @@ a command like `return' or `jump' to con We can't use displaced stepping when we are waiting for vfork_done event, displaced stepping breaks the vfork child similarly as single step software breakpoint. */ - if (use_displaced_stepping (gdbarch) + if (!target_can_continue_over_breakpoints () + && use_displaced_stepping (gdbarch) && (tp->control.trap_expected || (step && gdbarch_software_single_step_p (gdbarch))) && sig == GDB_SIGNAL_0 @@ -3940,10 +3942,11 @@ handle_inferior_event (struct execution_ singlestep_breakpoints_inserted_p = 0; } - /* If the arch can displace step, don't remove the - breakpoints. */ + /* If the target can continue over breakpoints transparently, + or the arch can displace step, don't remove the breakpoints. */ thread_regcache = get_thread_regcache (ecs->ptid); - if (!use_displaced_stepping (get_regcache_arch (thread_regcache))) + if (!use_displaced_stepping (get_regcache_arch (thread_regcache)) + && !target_can_continue_over_breakpoints()) remove_status = remove_breakpoints (); /* Did we fail to remove breakpoints? If so, try @@ -3957,15 +3960,26 @@ handle_inferior_event (struct execution_ error (_("Cannot step over breakpoint hit in wrong thread")); else { /* Single step */ - if (!non_stop) + if (!non_stop && !target_can_continue_over_breakpoints ()) { /* Only need to require the next event from this - thread in all-stop mode. */ + thread in all-stop mode. + Continue over breakpoints doesn't need wait a special + thread, so doesn't set it. */ waiton_ptid = ecs->ptid; infwait_state = infwait_thread_hop_state; } - ecs->event_thread->stepping_over_breakpoint = 1; + if (target_can_continue_over_breakpoints ()) + { + target_next_continue_over_breakpoints(); + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: continue over breakpoints\n"); + } + else + ecs->event_thread->stepping_over_breakpoint = 1; + keep_going (ecs); return; } --- a/gdb/remote.c +++ b/gdb/remote.c @@ -311,6 +311,10 @@ struct remote_state /* True if the stub reports support for vCont;t. */ int support_vCont_t; + /* True if the stub reports support for continue over breakpoints + transparently. */ + int can_continue_over_breakpoints; + /* True if the stub reports support for conditional tracepoints. */ int cond_tracepoints; @@ -3928,6 +3932,15 @@ remote_string_tracing_feature (const str rs->string_tracing = (support == PACKET_ENABLE); } +static void +remote_continue_over_breakpoints_feature (const struct protocol_feature *feature, + enum packet_support support, + const char *value) +{ + struct remote_state *rs = get_remote_state (); + rs->can_continue_over_breakpoints = (support == PACKET_ENABLE); +} + static struct protocol_feature remote_protocol_features[] = { { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 }, { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet, @@ -3958,6 +3971,8 @@ static struct protocol_feature remote_pr PACKET_QStartNoAckMode }, { "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 }, { "QNonStop", PACKET_DISABLE, remote_non_stop_feature, -1 }, + { "ContinueOverBreakpoints", PACKET_DISABLE, + remote_continue_over_breakpoints_feature, -1 }, { "qXfer:siginfo:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_siginfo_read }, { "qXfer:siginfo:write", PACKET_DISABLE, remote_supported_packet, @@ -4283,6 +4298,7 @@ remote_open_1 (char *name, int from_tty, rs->extended = extended_p; rs->non_stop_aware = 0; rs->waiting_for_stop_reply = 0; + rs->can_continue_over_breakpoints = 0; rs->ctrlc_pending_p = 0; general_thread = not_sent_ptid; @@ -4673,6 +4689,8 @@ remote_vcont_probe (struct remote_state the thread to be stepped and/or signalled is given in the global INFERIOR_PTID. */ +static int remote_is_cob = 0; + static char * append_resumption (char *p, char *endp, ptid_t ptid, int step, enum gdb_signal siggnal) @@ -4685,6 +4703,8 @@ append_resumption (char *p, char *endp, p += xsnprintf (p, endp - p, ";s"); else if (siggnal != GDB_SIGNAL_0) p += xsnprintf (p, endp - p, ";C%02x", siggnal); + else if (remote_is_cob) + p += xsnprintf (p, endp - p, ";cob"); else p += xsnprintf (p, endp - p, ";c"); @@ -4878,6 +4898,7 @@ remote_resume (struct target_ops *ops, putpkt (buf); done: + remote_is_cob = 0; /* We are about to start executing the inferior, let's register it with the event loop. NOTE: this is the one place where all the execution commands end up. We could alternatively do this in each @@ -11115,6 +11136,21 @@ remote_can_use_agent (void) return (remote_protocol_packets[PACKET_QAgent].support != PACKET_DISABLE); } +static int +remote_can_continue_over_breakpoints (void) +{ + struct remote_state *rs = get_remote_state (); + + return rs->can_continue_over_breakpoints; +} + +static void +remote_next_continue_over_breakpoints (void) +{ + make_cleanup_restore_integer (&remote_is_cob); + remote_is_cob = 1; +} + static void init_remote_ops (void) { @@ -11133,6 +11169,10 @@ Specify the serial device it is connecte remote_ops.to_fetch_registers = remote_fetch_registers; remote_ops.to_store_registers = remote_store_registers; remote_ops.to_prepare_to_store = remote_prepare_to_store; + remote_ops.to_can_continue_over_breakpoints = + remote_can_continue_over_breakpoints; + remote_ops.to_next_continue_over_breakpoints = + remote_next_continue_over_breakpoints; remote_ops.deprecated_xfer_memory = remote_xfer_memory; remote_ops.to_files_info = remote_files_info; remote_ops.to_insert_breakpoint = remote_insert_breakpoint; --- a/gdb/target.c +++ b/gdb/target.c @@ -596,6 +596,8 @@ update_current_target (void) /* Do not inherit to_fetch_registers. */ /* Do not inherit to_store_registers. */ INHERIT (to_prepare_to_store, t); + INHERIT (to_can_continue_over_breakpoints, t); + INHERIT (to_next_continue_over_breakpoints, t); INHERIT (deprecated_xfer_memory, t); INHERIT (to_files_info, t); INHERIT (to_insert_breakpoint, t); @@ -730,6 +732,12 @@ update_current_target (void) de_fault (to_prepare_to_store, (void (*) (struct regcache *)) noprocess); + de_fault (to_can_continue_over_breakpoints, + (int (*) (void)) + return_zero); + de_fault (to_next_continue_over_breakpoints, + (void (*) (void)) + target_ignore); de_fault (deprecated_xfer_memory, (int (*) (CORE_ADDR, gdb_byte *, int, int, struct mem_attrib *, struct target_ops *)) --- a/gdb/target.h +++ b/gdb/target.h @@ -430,6 +430,15 @@ struct target_ops void (*to_store_registers) (struct target_ops *, struct regcache *, int); void (*to_prepare_to_store) (struct regcache *); + /* Return true if GDB does not need to lift breakpoints from the + the inferior while continue over a breakpoint; the target + handles that transparently. */ + int (*to_can_continue_over_breakpoints) (void); + + /* After call this function, the continue will be changed to + continue over breakpoints. */ + void (*to_next_continue_over_breakpoints) (void); + /* Transfer LEN bytes of memory between GDB address MYADDR and target address MEMADDR. If WRITE, transfer them to the target, else transfer them from the target. TARGET is the target from which we @@ -972,6 +981,12 @@ extern void target_store_registers (stru #define target_prepare_to_store(regcache) \ (*current_target.to_prepare_to_store) (regcache) +#define target_can_continue_over_breakpoints() \ + (*current_target.to_can_continue_over_breakpoints) () + +#define target_next_continue_over_breakpoints() \ + (*current_target.to_next_continue_over_breakpoints) () + /* Determine current address space of thread PTID. */ struct address_space *target_thread_address_space (ptid_t);