From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3112 invoked by alias); 15 Mar 2008 10:13:14 -0000 Received: (qmail 3087 invoked by uid 22791); 15 Mar 2008 10:13:09 -0000 X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (65.74.133.4) by sourceware.org (qpsmtpd/0.31) with ESMTP; Sat, 15 Mar 2008 10:12:30 +0000 Received: (qmail 5408 invoked from network); 15 Mar 2008 10:12:26 -0000 Received: from unknown (HELO localhost) (vladimir@127.0.0.2) by mail.codesourcery.com with ESMTPA; 15 Mar 2008 10:12:26 -0000 From: Vladimir Prus To: Daniel Jacobowitz Subject: Re: [RFA] Keep breakpoints always inserted. Date: Sat, 15 Mar 2008 10:13:00 -0000 User-Agent: KMail/1.9.6 (enterprise 0.20070907.709405) Cc: gdb-patches@sources.redhat.com References: <200802281717.14766.vladimir@codesourcery.com> <20080310210844.GB14908@caradoc.them.org> In-Reply-To: <20080310210844.GB14908@caradoc.them.org> MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_/D62HHPoedildla" Message-Id: <200803151312.15051.vladimir@codesourcery.com> Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-03/txt/msg00213.txt.bz2 --Boundary-00=_/D62HHPoedildla Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline Content-length: 2081 On Tuesday 11 March 2008 00:08:44 Daniel Jacobowitz wrote: > On Thu, Feb 28, 2008 at 05:17:13PM +0300, Vladimir Prus wrote: > > > > This is hopefully final revision of my patch to keep > > breakpoints always inserted, which is needed to support > > non-stop mode. A new variable 'breakpoint always-inserted' > > is introduced that enables this mode. When enabled, > > breakpoints are inserted into target immediately when created, > > and they are not removed when we stop. > > > > Compared to the previous version of this patch: > > - The always-inserted mode is actually configurable > > - In always-inserted mode, breakpoints are removed > > from target on detach/disconnect. > > > > OK? > > This patch is OK, if you will add the missing pieces: a NEWS entry and > documentation for the new command, and a testcase that enables > always-inserted and verifies that it isn't a brick. I've added NEW and documentation. I'm still not sure how to test this adequately. > > @@ -1350,10 +1358,6 @@ handle_inferior_event (struct execution_control_state *ecs) > > established. */ > > if (stop_soon == NO_STOP_QUIETLY) > > { > > - /* Remove breakpoints, SOLIB_ADD might adjust > > - breakpoint addresses via breakpoint_re_set. */ > > - remove_breakpoints (); > > - > > /* Check for any newly added shared libraries if we're > > supposed to be adding them automatically. Switch > > terminal for any messages produced by > > @@ -1393,9 +1397,6 @@ handle_inferior_event (struct execution_control_state *ecs) > > > > /* NOTE drow/2007-05-11: This might be a good place to check > > for "catch load". */ > > - > > - /* Reinsert breakpoints and continue. */ > > - insert_breakpoints (); > > } > > > > /* If we are skipping through a shell, or through shared library > > This does the right thing even with breakpoints not always inserted, > right? I'm afraid no. On this code path, we call 'resume' immediately, which does not insert breakpoints. I've fixed this. Does does this one look? - Volodya --Boundary-00=_/D62HHPoedildla Content-Type: text/x-diff; charset="iso-8859-1"; name="0001-Keep-breakpoints-always-inserted.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="0001-Keep-breakpoints-always-inserted.patch" Content-length: 37529 =46rom 79766b2a4096b2c27847c3737232184581ead9ed Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Nov 2007 21:35:52 +0300 Subject: [RFA] Keep breakpoints always inserted. To: gdb-patches@sources.redhat.com X-KMail-Transport: CodeSourcery X-KMail-Identity: 901867920 * breakpoint.h (bp_location_p): New typedef. Register a vector of bp_location_p. * breakpoint.c (always_inserted_mode) (show_always_inserted_mode): New. (unlink_locations_from_global_list): Remove. (update_global_location_list) (update_global_location_list_nothrow): New. (update_watchpoint): Don't free locations. (should_insert_location): New. (insert_bp_location): Use should_insert_location. (insert_breakpoint_locations): Copied from insert_breakpoints. (insert_breakpoint): Use insert_breakpoint_locations. (bpstat_stop_status): Call update_global_location_list when disabling breakpoint. (allocate_bp_location): Don't add to bp_location_chain. (set_raw_breakpoint) (create_longjmp_breakpoint, enable_longjmp_breakpoint) (disable_longjmp_breakpoint, create_overlay_event_breakpoint) (enable_overlay_breakpoints, disable_overlay_breakpoints) (set_longjmp_resume_breakpoint) (enable_watchpoints_after_interactive_call_stop) (disable_watchpoints_before_interactive_call_start) (create_internal_breakpoint) (create_fork_vfork_event_catchpoint) (create_exec_event_catchpoint, set_momentary_breakpoint) (create_breakpoints, break_command_1, watch_command_1) (create_exception_catchpoint) (handle_gnu_v3_exceptions) (disable_breakpoint, breakpoint_re_set_one) (create_thread_event_breakpoint, create_solib_event_breakpoint) (create_ada_exception_breakpoint): : Don't call check_duplicates. Call update_global_location_list. (delete_breakpoint): Don't remove locations and don't try to reinsert them. Call update_global_location_list. (update_breakpoint_locations): Likewise. (restore_always_inserted_mode): New. (update_breakpoints_after_exec): Temporary disable always inserted mode. * Makefile.in: Update dependencies. * infrun.c (proceed): Remove breakpoints while stepping over breakpoint. (handle_inferior_event): Don't remove or insert breakpoints. * linux-fork.c (checkpoint_command): Remove breakpoints before fork and insert after. (linux_fork_context): Remove breakpoints before switch and insert after. * target.c (target_disconnect, target_detach): Remove breakpoints from target. --- gdb/Makefile.in | 3 +- gdb/NEWS | 4 + gdb/breakpoint.c | 422 +++++++++++++++++++++++++++++------------------= ---- gdb/breakpoint.h | 5 + gdb/doc/gdb.texinfo | 21 +++ gdb/infrun.c | 57 ++++---- gdb/linux-fork.c | 7 + gdb/target.c | 8 + 8 files changed, 319 insertions(+), 208 deletions(-) diff --git a/gdb/Makefile.in b/gdb/Makefile.in index a3e73b9..eb4c6a5 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1951,7 +1951,8 @@ breakpoint.o: breakpoint.c $(defs_h) $(symtab_h) $(fr= ame_h) $(breakpoint_h) \ $(objfiles_h) $(source_h) $(linespec_h) $(completer_h) $(gdb_h) \ $(ui_out_h) $(cli_script_h) $(gdb_assert_h) $(block_h) $(solib_h) \ $(solist_h) $(observer_h) $(exceptions_h) $(gdb_events_h) \ - $(mi_common_h) $(memattr_h) $(ada_lang_h) $(top_h) $(hashtab_h) + $(mi_common_h) $(memattr_h) $(ada_lang_h) $(top_h) $(hashtab_h) \ + $(gdb_stdint_h) bsd-kvm.o: bsd-kvm.c $(defs_h) $(cli_cmds_h) $(command_h) $(frame_h) \ $(regcache_h) $(target_h) $(value_h) $(gdbcore_h) $(gdb_assert_h) \ $(readline_h) $(bsd_kvm_h) diff --git a/gdb/NEWS b/gdb/NEWS index 4aba328..173e3c1 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -22,6 +22,10 @@ show exec-wrapper unset exec-wrapper Use a wrapper program to launch programs for debugging. =20 +set breakpoint always-inserted +show breakpoint always-inserted + Keep breakpoints always inserted in the target. + *** Changes in GDB 6.8 =20 * New native configurations diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 6830efe..73a30df 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -60,6 +60,8 @@ #include "gdb-events.h" #include "mi/mi-common.h" =20 +#include "gdb_stdint.h" + /* Prototypes for local functions. */ =20 static void until_break_command_continuation (struct continuation_arg *arg= ); @@ -205,11 +207,13 @@ static void mark_breakpoints_out (void); static struct bp_location * allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type); =20 -static void -unlink_locations_from_global_list (struct breakpoint *bpt); +static void update_global_location_list (void); =20 -static int -is_hardware_watchpoint (struct breakpoint *bpt); +static void update_global_location_list_nothrow (void); + +static int is_hardware_watchpoint (struct breakpoint *bpt); + +static void insert_breakpoint_locations (void); =20 /* Prototypes for exported functions. */ =20 @@ -257,6 +261,18 @@ Automatic usage of hardware breakpoints is %s.\n"), value); } =20 +/* If 1, gdb will keep breakpoints inserted even as inferior is stopped,=20 + and immediately insert any new breakpoints. If 0, gdb will insert=20 + breakpoints into inferior only when resuming it, and will remove=20 + breakpoints upon stop. */ +static int always_inserted_mode =3D 0; +static void=20 +show_always_inserted_mode (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Always inserted breakpoint mode is %s.\n"), v= alue); +} + =20 void _initialize_breakpoint (void); =20 @@ -867,14 +883,10 @@ update_watchpoint (struct breakpoint *b, int reparse) struct bp_location *loc; bpstat bs; =20 - unlink_locations_from_global_list (b); - for (loc =3D b->loc; loc;) - { - struct bp_location *loc_next =3D loc->next; - remove_breakpoint (loc, mark_uninserted); - xfree (loc); - loc =3D loc_next; - } + /* We don't free locations. They are stored in + bp_location_chain and update_global_locations will + eventually delete them and remove breakpoints if + needed. */ b->loc =3D NULL; =20 if (b->disposition =3D=3D disp_del_at_next_stop) @@ -1013,6 +1025,20 @@ in which its expression is valid.\n"), } =20 =20 +/* Returns 1 iff breakpoint location should be + inserted in the inferior. */ +static int +should_insert_location (struct bp_location *bpt) +{ + if (!breakpoint_enabled (bpt->owner)) + return 0; + + if (!bpt->enabled || bpt->shlib_disabled || bpt->inserted || bpt->duplic= ate) + return 0; + + return 1; +} + /* Insert a low-level "breakpoint" of some type. BPT is the breakpoint. Any error messages are printed to TMP_ERROR_STREAM; and DISABLED_BREAKS, PROCESS_WARNING, and HW_BREAKPOINT_ERROR are used to report problems. @@ -1027,10 +1053,7 @@ insert_bp_location (struct bp_location *bpt, { int val =3D 0; =20 - if (!breakpoint_enabled (bpt->owner)) - return 0; - - if (!bpt->enabled || bpt->shlib_disabled || bpt->inserted || bpt->duplic= ate) + if (!should_insert_location (bpt)) return 0; =20 /* Initialize the target-specific information. */ @@ -1231,13 +1254,35 @@ Note: automatically using hardware breakpoints for = read-only addresses.\n")); return 0; } =20 +/* Make sure all breakpoints are inserted in inferior. + Throws exception on any error. + A breakpoint that is already inserted won't be inserted + again, so calling this function twice is safe. */ +void +insert_breakpoints (void) +{ + struct breakpoint *bpt; + + ALL_BREAKPOINTS (bpt) + if (is_hardware_watchpoint (bpt)) + update_watchpoint (bpt, 0 /* don't reparse. */); + + update_global_location_list (); + + if (!always_inserted_mode && target_has_execution) + /* update_global_location_list does not insert breakpoints + when always_inserted_mode is not enabled. Explicitly + insert them now. */ + insert_breakpoint_locations (); +} + /* insert_breakpoints is used when starting or continuing the program. remove_breakpoints is used when the program stops. Both return zero if successful, or an `errno' value if could not write the inferior. */ =20 -void -insert_breakpoints (void) +static void +insert_breakpoint_locations (void) { struct breakpoint *bpt; struct bp_location *b, *temp; @@ -1249,14 +1294,10 @@ insert_breakpoints (void) =20 struct ui_file *tmp_error_stream =3D mem_fileopen (); make_cleanup_ui_file_delete (tmp_error_stream); - +=20=20 /* Explicitly mark the warning -- this will only be printed if there was an error. */ fprintf_unfiltered (tmp_error_stream, "Warning:\n"); - - ALL_BREAKPOINTS (bpt) - if (is_hardware_watchpoint (bpt)) - update_watchpoint (bpt, 0 /* don't reparse */);=20=20=20=20=20=20 =20=09 ALL_BP_LOCATIONS_SAFE (b, temp) { @@ -1395,17 +1436,31 @@ reattach_breakpoints (int pid) return 0; } =20 +static void +restore_always_inserted_mode (void *p) +{ + always_inserted_mode =3D (uintptr_t) p; +} + void update_breakpoints_after_exec (void) { struct breakpoint *b; struct breakpoint *temp; + struct cleanup *cleanup; =20 /* Doing this first prevents the badness of having delete_breakpoint() write a breakpoint's current "shadow contents" to lift the bp. That shadow is NOT valid after an exec()! */ mark_breakpoints_out (); =20 + /* The binary we used to debug is now gone, and we're updating + breakpoints for the new binary. Until we're done, we should not + try to insert breakpoints. */ + cleanup =3D make_cleanup (restore_always_inserted_mode,=20 + (void *) (uintptr_t) always_inserted_mode); + always_inserted_mode =3D 0; + ALL_BREAKPOINTS_SAFE (b, temp) { /* Solib breakpoints must be explicitly reset after an exec(). */ @@ -1487,6 +1542,7 @@ update_breakpoints_after_exec (void) } /* FIXME what about longjmp breakpoints? Re-create them here? */ create_overlay_event_breakpoint ("_ovly_debug_event"); + do_cleanups (cleanup); } =20 int @@ -1526,9 +1582,9 @@ remove_breakpoint (struct bp_location *b, insertion_s= tate_t is) /* Permanent breakpoints cannot be inserted or removed. */ return 0; =20 - if (b->owner->type =3D=3D bp_none) - warning (_("attempted to remove apparently deleted breakpoint #%d?"),= =20 - b->owner->number); + /* The type of none suggests that owner is actually deleted. + This should not ever happen. */ + gdb_assert (b->owner->type !=3D bp_none); =20 if (b->loc_type =3D=3D bp_loc_software_breakpoint || b->loc_type =3D=3D bp_loc_hardware_breakpoint) @@ -2953,7 +3009,10 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid) { /* We will stop here */ if (b->disposition =3D=3D disp_disable) - b->enable_state =3D bp_disabled; + { + b->enable_state =3D bp_disabled; + update_global_location_list (); + } if (b->silent) bs->print =3D 0; bs->commands =3D b->commands; @@ -4181,18 +4240,6 @@ allocate_bp_location (struct breakpoint *bpt, enum b= ptype bp_type) internal_error (__FILE__, __LINE__, _("unknown breakpoint type")); } =20 - /* Add this breakpoint to the end of the chain. */ - - loc_p =3D bp_location_chain; - if (loc_p =3D=3D 0) - bp_location_chain =3D loc; - else - { - while (loc_p->global_next) - loc_p =3D loc_p->global_next; - loc_p->global_next =3D loc; - } - return loc; } =20 @@ -4200,6 +4247,10 @@ static void free_bp_location (struct bp_location *lo= c) { if (loc->cond) xfree (loc->cond); + + if (loc->function_name) + xfree (loc->function_name); +=20=20 xfree (loc); } =20 @@ -4304,7 +4355,6 @@ set_raw_breakpoint (struct symtab_and_line sal, enum = bptype bptype) =20 set_breakpoint_location_function (b->loc); =20 - check_duplicates (b); breakpoints_changed (); =20 return b; @@ -4368,6 +4418,7 @@ create_longjmp_breakpoint (char *func_name) b->silent =3D 1; if (func_name) b->addr_string =3D xstrdup (func_name); + update_global_location_list (); } =20 /* Call this routine when stepping and nexting to enable a breakpoint @@ -4383,7 +4434,7 @@ enable_longjmp_breakpoint (void) if (b->type =3D=3D bp_longjmp) { b->enable_state =3D bp_enabled; - check_duplicates (b); + update_global_location_list (); } } =20 @@ -4397,7 +4448,7 @@ disable_longjmp_breakpoint (void) || b->type =3D=3D bp_longjmp_resume) { b->enable_state =3D bp_disabled; - check_duplicates (b); + update_global_location_list (); } } =20 @@ -4424,6 +4475,7 @@ create_overlay_event_breakpoint (char *func_name) b->enable_state =3D bp_disabled; overlay_events_enabled =3D 0; } + update_global_location_list (); } =20 void @@ -4435,7 +4487,7 @@ enable_overlay_breakpoints (void) if (b->type =3D=3D bp_overlay_event) { b->enable_state =3D bp_enabled; - check_duplicates (b); + update_global_location_list (); overlay_events_enabled =3D 1; } } @@ -4449,7 +4501,7 @@ disable_overlay_breakpoints (void) if (b->type =3D=3D bp_overlay_event) { b->enable_state =3D bp_disabled; - check_duplicates (b); + update_global_location_list (); overlay_events_enabled =3D 0; } } @@ -4465,6 +4517,8 @@ create_thread_event_breakpoint (CORE_ADDR address) /* addr_string has to be used or breakpoint_re_set will delete me. */ b->addr_string =3D xstrprintf ("*0x%s", paddr (b->loc->address)); =20 + update_global_location_list_nothrow (); + return b; } =20 @@ -4509,6 +4563,7 @@ create_solib_event_breakpoint (CORE_ADDR address) struct breakpoint *b; =20 b =3D create_internal_breakpoint (address, bp_shlib_event); + update_global_location_list_nothrow (); return b; } =20 @@ -4606,6 +4661,8 @@ create_fork_vfork_event_catchpoint (int tempflag, cha= r *cond_string, b->enable_state =3D bp_enabled; b->disposition =3D tempflag ? disp_del : disp_donttouch; b->forked_inferior_pid =3D 0; + update_global_location_list (); + =20 mention (b); } @@ -4643,6 +4700,7 @@ create_exec_event_catchpoint (int tempflag, char *con= d_string) b->addr_string =3D NULL; b->enable_state =3D bp_enabled; b->disposition =3D tempflag ? disp_del : disp_donttouch; + update_global_location_list (); =20 mention (b); } @@ -4703,7 +4761,7 @@ set_longjmp_resume_breakpoint (CORE_ADDR pc, struct f= rame_id frame_id) b->type); b->enable_state =3D bp_enabled; b->frame_id =3D frame_id; - check_duplicates (b); + update_global_location_list (); return; } } @@ -4722,7 +4780,7 @@ disable_watchpoints_before_interactive_call_start (vo= id) && breakpoint_enabled (b)) { b->enable_state =3D bp_call_disabled; - check_duplicates (b); + update_global_location_list (); } } } @@ -4741,7 +4799,7 @@ enable_watchpoints_after_interactive_call_stop (void) && (b->enable_state =3D=3D bp_call_disabled)) { b->enable_state =3D bp_enabled; - check_duplicates (b); + update_global_location_list (); } } } @@ -4767,6 +4825,8 @@ set_momentary_breakpoint (struct symtab_and_line sal,= struct frame_id frame_id, if (in_thread_list (inferior_ptid)) b->thread =3D pid_to_thread_id (inferior_ptid); =20 + update_global_location_list_nothrow (); + return b; } =0C @@ -5166,6 +5226,8 @@ create_breakpoints (struct symtabs_and_lines sals, ch= ar **addr_string, cond_string, type, disposition, thread, ignore_count, from_tty); } + + update_global_location_list (); } =20 /* Parse ARG which is assumed to be a SAL specification possibly @@ -5483,6 +5545,8 @@ break_command_really (char *arg, char *cond_string, i= nt thread, b->ignore_count =3D ignore_count; b->disposition =3D tempflag ? disp_del : disp_donttouch; b->condition_not_parsed =3D 1; + + update_global_location_list (); mention (b); } =20=20=20 @@ -5909,6 +5973,7 @@ watch_command_1 (char *arg, int accessflag, int from_= tty) =20 value_free_to_mark (mark); mention (b); + update_global_location_list (); } =20 /* Return count of locations need to be watched and can be handled @@ -6467,6 +6532,7 @@ handle_gnu_v3_exceptions (int tempflag, char *cond_st= ring, =20 xfree (sals.sals); mention (b); + update_global_location_list (); return 1; } =20 @@ -6539,6 +6605,7 @@ create_ada_exception_breakpoint (struct symtab_and_li= ne sal, b->ops =3D ops; =20 mention (b); + update_global_location_list (); } =20 /* Implement the "catch exception" command. */ @@ -6860,33 +6927,109 @@ breakpoint_auto_delete (bpstat bs) } } =20 -/* Remove locations of breakpoint BPT from - the global list of breakpoint locations. */ - static void -unlink_locations_from_global_list (struct breakpoint *bpt) +update_global_location_list (void) { - /* This code assumes that the locations - of a breakpoint are found in the global list - in the same order, but not necessary adjacent. */ - struct bp_location **tmp =3D &bp_location_chain; - struct bp_location *here =3D bpt->loc; - - if (here =3D=3D NULL) - return; + struct breakpoint *b; + struct bp_location **next =3D &bp_location_chain; + struct bp_location *loc; + struct bp_location *loc2; + struct gdb_exception e; + VEC(bp_location_p) *old_locations =3D NULL; + int ret; + int ix; +=20=20 + /* Store old locations for future reference. */ + for (loc =3D bp_location_chain; loc; loc =3D loc->global_next) + VEC_safe_push (bp_location_p, old_locations, loc); =20 - for (; *tmp && here;) + bp_location_chain =3D NULL; + ALL_BREAKPOINTS (b) { - if (*tmp =3D=3D here) + for (loc =3D b->loc; loc; loc =3D loc->next) { - *tmp =3D here->global_next; - here =3D here->next; + *next =3D loc; + next =3D &(loc->global_next); + *next =3D NULL; } - else + } + + /* Identify bp_location instances that are no longer present in the new + list, and therefore should be freed. Note that it's not necessary th= at + those locations should be removed from inferior -- if there's another + location at the same address (previously marked as duplicate), + we don't need to remove/insert the location. */ + for (ix =3D 0; VEC_iterate(bp_location_p, old_locations, ix, loc); ++ix) + { + int found_object =3D 0; + int found_address =3D 0; + for (loc2 =3D bp_location_chain; loc2; loc2 =3D loc2->global_next) + if (loc2 =3D=3D loc) + { + found_object =3D 1; + break; + } + + /* If this location is no longer present, and inserted, look if ther= e's + maybe a new location at the same address. If so, mark that one=20 + inserted, and don't remove this one. This is needed so that we=20 + don't have a time window where a breakpoint at certain location is not + inserted. */ + if (!found_object && loc->inserted) { - tmp =3D &((*tmp)->global_next); + /* See if there's another location at the same address, in which=20 + case we don't need to remove this one. */ + if (breakpoint_address_is_meaningful (loc->owner)) + for (loc2 =3D bp_location_chain; loc2; loc2 =3D loc2->global_next) + { + /* For the sake of should_insert_location. The + call to check_duplicates will fix up this later. */ + loc2->duplicate =3D 0; + if (should_insert_location (loc2) + && loc2 !=3D loc && loc2->address =3D=3D loc->address) + {=09=09=20=20 + loc2->inserted =3D 1; + loc2->target_info =3D loc->target_info; + found_address =3D 1; + break; + } + } } + + if (loc->inserted && !found_object && !found_address) + if (remove_breakpoint (loc, mark_uninserted)) + { + /* This is just about all we can do. We could keep this + location on the global list, and try to remove it next + time, but there's no particular reason why we will + succeed next time.=20=20 + + Note that at this point, loc->owner is still valid, + as delete_breakpoint frees the breakpoint only + after calling us. */ + printf_filtered (_("warning: Error removing breakpoint %d\n"),=20 + loc->owner->number); + } + + if (!found_object) + free_bp_location (loc); + } +=20=20=20=20 + ALL_BREAKPOINTS (b) + { + check_duplicates (b); } + + if (always_inserted_mode && target_has_execution) + insert_breakpoint_locations (); +} + +static void +update_global_location_list_nothrow (void) +{ + struct gdb_exception e; + TRY_CATCH (e, RETURN_MASK_ERROR) + update_global_location_list (); } =20 /* Delete a breakpoint and clean up all traces of it in the data @@ -6897,7 +7040,7 @@ delete_breakpoint (struct breakpoint *bpt) { struct breakpoint *b; bpstat bs; - struct bp_location *loc; + struct bp_location *loc, *next; =20 gdb_assert (bpt !=3D NULL); =20 @@ -6921,18 +7064,6 @@ delete_breakpoint (struct breakpoint *bpt) deprecated_delete_breakpoint_hook (bpt); breakpoint_delete_event (bpt->number); =20 - for (loc =3D bpt->loc; loc; loc =3D loc->next) - { - if (loc->inserted) - remove_breakpoint (loc, mark_inserted); -=20=20=20=20=20=20 - if (loc->cond) - xfree (loc->cond); - - if (loc->function_name) - xfree (loc->function_name); - } - if (breakpoint_chain =3D=3D bpt) breakpoint_chain =3D bpt->next; =20 @@ -6943,85 +7074,6 @@ delete_breakpoint (struct breakpoint *bpt) break; } =20 - unlink_locations_from_global_list (bpt); - - check_duplicates (bpt); - - if (bpt->type !=3D bp_hardware_watchpoint - && bpt->type !=3D bp_read_watchpoint - && bpt->type !=3D bp_access_watchpoint - && bpt->type !=3D bp_catch_fork - && bpt->type !=3D bp_catch_vfork - && bpt->type !=3D bp_catch_exec) - for (loc =3D bpt->loc; loc; loc =3D loc->next) - { - /* If this breakpoint location was inserted, and there is=20 - another breakpoint at the same address, we need to=20 - insert the other breakpoint. */ - if (loc->inserted) - { - struct bp_location *loc2; - ALL_BP_LOCATIONS (loc2) - if (loc2->address =3D=3D loc->address - && loc2->section =3D=3D loc->section - && !loc->duplicate - && loc2->owner->enable_state !=3D bp_disabled - && loc2->enabled=20 - && !loc2->shlib_disabled - && loc2->owner->enable_state !=3D bp_call_disabled) - { - int val; - - /* We should never reach this point if there is a permanent - breakpoint at the same address as the one being deleted. - If there is a permanent breakpoint somewhere, it should - always be the only one inserted. */ - if (loc2->owner->enable_state =3D=3D bp_permanent) - internal_error (__FILE__, __LINE__, - _("another breakpoint was inserted on top of " - "a permanent breakpoint")); - - memset (&loc2->target_info, 0, sizeof (loc2->target_info)); - loc2->target_info.placed_address =3D loc2->address; - if (b->type =3D=3D bp_hardware_breakpoint) - val =3D target_insert_hw_breakpoint (&loc2->target_info); - else - val =3D target_insert_breakpoint (&loc2->target_info); - - /* If there was an error in the insert, print a message, then stop exe= cution. */ - if (val !=3D 0) - { - struct ui_file *tmp_error_stream =3D mem_fileopen (); - make_cleanup_ui_file_delete (tmp_error_stream); -=09=09=20=20=20=20=20=20 -=09=09=20=20=20=20=20=20 - if (b->type =3D=3D bp_hardware_breakpoint) - { - fprintf_unfiltered (tmp_error_stream,=20 - "Cannot insert hardware breakpoint %d.\n" - "You may have requested too many hardware breakpoints.\n", - b->number); - } - else - { - fprintf_unfiltered (tmp_error_stream, "Cannot insert breakpoint %d.\n= ", b->number); - fprintf_filtered (tmp_error_stream, "Error accessing memory address "= ); - fputs_filtered (paddress (loc2->address), - tmp_error_stream); - fprintf_filtered (tmp_error_stream, ": %s.\n", - safe_strerror (val)); - } -=09=09=20=20=20=20=20=20 - fprintf_unfiltered (tmp_error_stream,"The same program may be runn= ing in another process."); - target_terminal_ours_for_output (); - error_stream(tmp_error_stream);=20 - } - else - loc2->inserted =3D 1; - } - } - } - free_command_lines (&bpt->commands); if (bpt->cond_string !=3D NULL) xfree (bpt->cond_string); @@ -7058,16 +7110,22 @@ delete_breakpoint (struct breakpoint *bpt) bs->old_val =3D NULL; /* bs->commands will be freed later. */ } + + /* Now that breakpoint is removed from breakpoint + list, update the global location list. This + will remove locations that used to belong to + this breakpoint. Do this before freeing + the breakpoint itself, since remove_breakpoint + looks at location's owner. It might be better + design to have location completely self-contained, + but it's not the case now. */ + update_global_location_list (); + + /* On the chance that someone will soon try again to delete this same bp, we mark it as deleted before freeing its storage. */ bpt->type =3D bp_none; =20 - for (loc =3D bpt->loc; loc;) - { - struct bp_location *loc_next =3D loc->next; - xfree (loc); - loc =3D loc_next; - } xfree (bpt); } =20 @@ -7199,7 +7257,6 @@ update_breakpoint_locations (struct breakpoint *b, if (all_locations_are_pending (existing_locations) && sals.nelts =3D=3D = 0) return; =20 - unlink_locations_from_global_list (b); b->loc =3D NULL; =20 for (i =3D 0; i < sals.nelts; ++i) @@ -7278,12 +7335,7 @@ update_breakpoint_locations (struct breakpoint *b, } } =20 - while (existing_locations) - { - struct bp_location *next =3D existing_locations->next; - free_bp_location (existing_locations); - existing_locations =3D next; - } + update_global_location_list (); } =20 =20 @@ -7379,10 +7431,6 @@ breakpoint_re_set_one (void *bint) expanded =3D expand_line_sal_maybe (sals.sals[0]); update_breakpoint_locations (b, expanded); =20 - /* Now that this is re-enabled, check_duplicates - can be used. */ - check_duplicates (b); - xfree (sals.sals); break; =20 @@ -7682,7 +7730,7 @@ disable_breakpoint (struct breakpoint *bpt) =20 bpt->enable_state =3D bp_disabled; =20 - check_duplicates (bpt); + update_global_location_list (); =20 if (deprecated_modify_breakpoint_hook) deprecated_modify_breakpoint_hook (bpt); @@ -7721,7 +7769,7 @@ disable_command (char *args, int from_tty) struct bp_location *loc =3D find_location_by_number (args); if (loc) loc->enabled =3D 0; - check_duplicates (loc->owner); + update_global_location_list (); } else map_breakpoint_numbers (args, disable_breakpoint); @@ -7806,7 +7854,7 @@ have been allocated for other watchpoints.\n"), bpt->= number); if (bpt->enable_state !=3D bp_permanent) bpt->enable_state =3D bp_enabled; bpt->disposition =3D disposition; - check_duplicates (bpt); + update_global_location_list (); breakpoints_changed (); =20=20=20 if (deprecated_modify_breakpoint_hook) @@ -7857,7 +7905,7 @@ enable_command (char *args, int from_tty) struct bp_location *loc =3D find_location_by_number (args); if (loc) loc->enabled =3D 1; - check_duplicates (loc->owner); + update_global_location_list (); } else map_breakpoint_numbers (args, enable_breakpoint); @@ -8025,6 +8073,11 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc) return 0; } =20 +int breakpoints_always_inserted_mode (void) +{ + return always_inserted_mode; +} + =0C /* This help string is used for the break, hbreak, tbreak and thbreak comm= ands. It is defined as a macro to prevent duplication. @@ -8426,6 +8479,19 @@ a warning will be emitted for such breakpoints."), show_automatic_hardware_breakpoints, &breakpoint_set_cmdlist, &breakpoint_show_cmdlist); + + add_setshow_boolean_cmd ("always-inserted", class_support, + &always_inserted_mode, _("\ +Set mode for inserting breakpoints."), _("\ +Show mode for inserting breakpoints."), _("\ +When this mode is off (which is the default), breakpoints are inserted in\= n\ +inferior when it is resumed, and removed when execution stops. When this\= n\ +mode is on, breakpoints are inserted immediately and removed only when\n\ +the user deletes the breakpoint."), + NULL, + &show_always_inserted_mode, + &breakpoint_set_cmdlist, + &breakpoint_show_cmdlist); =20=20=20 automatic_hardware_breakpoints =3D 1; } diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 5376455..ed76f30 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -331,6 +331,9 @@ enum watchpoint_triggered watch_triggered_yes=20=20 }; =20 +typedef struct bp_location *bp_location_p; +DEF_VEC_P(bp_location_p); + /* Note that the ->silent field is not currently used by any commands (though the code is in there if it was to be, and set_raw_breakpoint does set it to 0). I implemented it because I thought it would be @@ -864,4 +867,6 @@ int watchpoints_triggered (struct target_waitstatus *); void breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr,=20 LONGEST len); =20 +extern int breakpoints_always_inserted_mode (void); + #endif /* !defined (BREAKPOINT_H) */ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index dbc9efc..78f8363 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3205,6 +3205,27 @@ type. If the target provides a memory map, @value{G= DBN} will warn when trying to set software breakpoint at a read-only address. @end table =20 +By default, @value{GDBN} inserts breakpoints in the target only when +resuming the target, and removes breakpoints whenever the target stop. +This behaviour guards against leaving breakpoints inserted in the +target should gdb abrubptly disconnect, which is possible with remote +targets. This bevaious can be controlled with the following +commands:: + +@kindex set breakpoint always-inserted +@kindex show breakpoint always-inserted +@table @code +@item set breakpoint always-inserted off +This is the default behaviour. All breakpoints, including newly added +by the user, are inserted in the target only when the target is +resumed. All breakpoints are removed from the target when it stops. + +@item set breakpoint always-inserted on +Causes all breakpoints to be inserted in the target at all times. If +the user adds a new breakpoint, or changes an existing breakpoint, the +breakpoints in the target are updated immediately. A breakpoint is +removed from the target only when breakpoint itself is removed. +@end table =20 @cindex negative breakpoint numbers @cindex internal @value{GDBN} breakpoints diff --git a/gdb/infrun.c b/gdb/infrun.c index c863736..43e59a7 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -616,19 +616,18 @@ a command like `return' or `jump' to continue executi= on.")); } =20 if ((step || singlestep_breakpoints_inserted_p) - && breakpoint_here_p (read_pc ()) - && !breakpoint_inserted_here_p (read_pc ())) + && stepping_over_breakpoint) { - /* We're stepping, have breakpoint at PC, and it's=20 - not inserted. Most likely, proceed has noticed that - we have breakpoint and tries to single-step over it, - so that it's not hit. In which case, we need to - single-step only this thread, and keep others stopped, - as they can miss this breakpoint if allowed to run.=20=20 - - The current code either has all breakpoints inserted,=20 - or all removed, so if we let other threads run, - we can actually miss any breakpoint, not the one at PC. */ + /* We're allowing a thread to run past a breakpoint it has + hit, by single-stepping the thread with the breakpoint + removed. In which case, we need to single-step only this + thread, and keep others stopped, as they can miss this + breakpoint if allowed to run. + + The current code actually removes all breakpoints when + doing this, not just the one being stepped over, so if we + let other threads run, we can actually miss any + breakpoint, not just the one at PC. */ resume_ptid =3D inferior_ptid; } =20 @@ -789,9 +788,17 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, i= nt step) oneproc =3D 1; =20 if (oneproc) - /* We will get a trace trap after one instruction. - Continue it automatically and insert breakpoints then. */ - stepping_over_breakpoint =3D 1; + { + /* We will get a trace trap after one instruction. + Continue it automatically and insert breakpoints then. */ + stepping_over_breakpoint =3D 1; + /* FIXME: if breakpoints are always inserted, we'll trap + if trying to single-step over breakpoint. Disable + all breakpoints. In future, we'd need to invent some + smart way of stepping over breakpoint instruction without + hitting breakpoint. */ + remove_breakpoints (); + } else insert_breakpoints (); =20 @@ -1350,10 +1357,6 @@ handle_inferior_event (struct execution_control_stat= e *ecs) established. */ if (stop_soon =3D=3D NO_STOP_QUIETLY) { - /* Remove breakpoints, SOLIB_ADD might adjust - breakpoint addresses via breakpoint_re_set. */ - remove_breakpoints (); - /* Check for any newly added shared libraries if we're supposed to be adding them automatically. Switch terminal for any messages produced by @@ -1393,9 +1396,6 @@ handle_inferior_event (struct execution_control_state= *ecs) =20 /* NOTE drow/2007-05-11: This might be a good place to check for "catch load". */ - - /* Reinsert breakpoints and continue. */ - insert_breakpoints (); } =20 /* If we are skipping through a shell, or through shared library @@ -1404,6 +1404,10 @@ handle_inferior_event (struct execution_control_stat= e *ecs) we're attaching or setting up a remote connection. */ if (stop_soon =3D=3D STOP_QUIETLY || stop_soon =3D=3D NO_STOP_QUIETL= Y) { + /* Loading of shared libraries might have changed breakpoint + addresses. Make sure new breakpoints are inserted. */ + if (!breakpoints_always_inserted_mode ()) + insert_breakpoints (); resume (0, TARGET_SIGNAL_0); prepare_to_wait (ecs); return; @@ -2058,8 +2062,7 @@ process_event_stop_test: stop_signal =3D TARGET_SIGNAL_0; =20 if (prev_pc =3D=3D read_pc () - && breakpoint_here_p (read_pc ()) - && !breakpoint_inserted_here_p (read_pc ()) + && stepping_over_breakpoint && step_resume_breakpoint =3D=3D NULL) { /* We were just starting a new sequence, attempting to @@ -2235,10 +2238,6 @@ process_event_stop_test: { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_SHLIBS\n"); - /* Remove breakpoints, we eventually want to step over the - shlib event breakpoint, and SOLIB_ADD might adjust - breakpoint addresses via breakpoint_re_set. */ - remove_breakpoints (); =20 /* Check for any newly added shared libraries if we're supposed to be adding them automatically. Switch @@ -3139,7 +3138,7 @@ normal_stop (void) gdbarch_decr_pc_after_break needs to just go away. */ deprecated_update_frame_pc_hack (get_current_frame (), read_pc ()); =20 - if (target_has_execution) + if (!breakpoints_always_inserted_mode () && target_has_execution) { if (remove_breakpoints ()) { diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c index 8c29827..a9f5fae 100644 --- a/gdb/linux-fork.c +++ b/gdb/linux-fork.c @@ -536,6 +536,10 @@ checkpoint_command (char *args, int from_tty) /* Make this temp var static, 'cause it's used in the error context. */ static int temp_detach_fork; =20 + /* Remove breakpoints, so that they are not inserted + in the forked process. */ + remove_breakpoints (); + /* Make the inferior fork, record its (and gdb's) state. */ =20 if (lookup_minimal_symbol ("fork", NULL, NULL) !=3D NULL) @@ -576,6 +580,7 @@ checkpoint_command (char *args, int from_tty) if (!fp) error (_("Failed to find new fork")); fork_save_infrun_state (fp, 1); + insert_breakpoints (); } =20 static void @@ -593,7 +598,9 @@ linux_fork_context (struct fork_info *newfp, int from_t= ty) oldfp =3D add_fork (ptid_get_pid (inferior_ptid)); =20 fork_save_infrun_state (oldfp, 1); + remove_breakpoints (); fork_load_infrun_state (newfp); + insert_breakpoints (); =20 printf_filtered (_("Switching to %s\n"),=20 target_pid_to_str (inferior_ptid)); diff --git a/gdb/target.c b/gdb/target.c index 9d2f1fd..b5c3cd3 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -1677,6 +1677,10 @@ target_preopen (int from_tty) void target_detach (char *args, int from_tty) { + /* If we're in breakpoints-always-inserted mode, have to + remove them before detaching. */ + remove_breakpoints (); + (current_target.to_detach) (args, from_tty); } =20 @@ -1685,6 +1689,10 @@ target_disconnect (char *args, int from_tty) { struct target_ops *t; =20 + /* If we're in breakpoints-always-inserted mode, have to + remove them before disconnecting. */=20=20 + remove_breakpoints (); + for (t =3D current_target.beneath; t !=3D NULL; t =3D t->beneath) if (t->to_disconnect !=3D NULL) { --=20 1.5.3.5 --Boundary-00=_/D62HHPoedildla--