aboutsummaryrefslogtreecommitdiff
path: root/gdb/breakpoint.c
diff options
context:
space:
mode:
authorLuis Machado <luisgpm@br.ibm.com>2012-02-24 15:10:59 +0000
committerLuis Machado <luisgpm@br.ibm.com>2012-02-24 15:10:59 +0000
commitb775012e845380ed4c7421a1b87caf7bfae39f5f (patch)
treeac2f84dfcd17de662a5608d8c8dd707c9567f8c7 /gdb/breakpoint.c
parent3788aec75a91b4b6e10255f20aaa649ddbfdf78c (diff)
downloadgdb-b775012e845380ed4c7421a1b87caf7bfae39f5f.zip
gdb-b775012e845380ed4c7421a1b87caf7bfae39f5f.tar.gz
gdb-b775012e845380ed4c7421a1b87caf7bfae39f5f.tar.bz2
2012-02-24 Luis Machado <lgustavo@codesourcery.com>
* remote.c (remote_supports_cond_breakpoints): New forward declaration. (remote_add_target_side_condition): New function. (remote_insert_breakpoint): Add target-side breakpoint conditional if supported. (remote_insert_hw_breakpoint): Likewise. (init_remote_ops): Set to_supports_evaluation_of_breakpoint_conditions hook. * target.c (update_current_target): Inherit to_supports_evaluation_of_breakpoint_conditions. Default to_supports_evaluation_of_breakpoint_conditions to return_zero. * target.h (struct target_ops) <to_supports_evaluation_of_breakpoint_conditions>: New field. (target_supports_evaluation_of_breakpoint_conditions): New #define. * breakpoint.c (get_first_locp_gte_addr): New forward declaration. (condition_evaluation_both, condition_evaluation_auto, condition_evaluation_host, condition_evaluation_target, condition_evaluation_enums, condition_evaluation_mode_1, condition_evaluation_mode): New static globals. (translate_condition_evaluation_mode): New function. (breakpoint_condition_evaluation_mode): New function. (gdb_evaluates_breakpoint_condition_p): New function. (ALL_BP_LOCATIONS_AT_ADDR): New helper macro. (mark_breakpoint_modified): New function. (mark_breakpoint_location_modified): New function. (set_condition_evaluation_mode): New function. (show_condition_evaluation_mode): New function. (bp_location_compare_addrs): New function. (get_first_location_gte_addr): New helper function. (set_breakpoint_condition): Free condition bytecode if locations has become unconditional. Call mark_breakpoint_modified (...). (condition_command): Call update_global_location_list (1) for breakpoints. (breakpoint_xfer_memory): Use is_breakpoint (...). (is_breakpoint): New function. (parse_cond_to_aexpr): New function. (build_target_condition_list): New function. (insert_bp_location): Handle target-side conditional breakpoints and call build_target_condition_list (...). (update_inserted_breakpoint_locations): New function. (insert_breakpoint_locations): Handle target-side conditional breakpoints. (bpstat_check_breakpoint_conditions): Add comment. (bp_condition_evaluator): New function. (bp_location_condition_evaluator): New function. (print_breakpoint_location): Print information on where the condition will be evaluated. (print_one_breakpoint_location): Likewise. (init_bp_location): Call mark_breakpoint_location_modified (...) for breakpoint location. (force_breakpoint_reinsertion): New functions. (update_global_location_list): Handle target-side breakpoint conditions. Reinsert locations that are already inserted if conditions have changed. (bp_location_dtor): Free agent expression bytecode. (disable_breakpoint): Call mark_breakpoint_modified (...). Call update_global_location_list (...) with parameter 1 for breakpoints. (disable_command): Call mark_breakpoint_location_modified (...). Call update_global_location_list (...) with parameter 1 for breakpoints. (enable_breakpoint_disp): Call mark_breakpoint_modified (...). (enable_command): mark_breakpoint_location_modified (...). (_initialize_breakpoint): Update documentation and add condition-evaluation breakpoint subcommand. * breakpoint.h: Include ax.h. (condition_list): New data structure. (condition_status): New enum. (bp_target_info) <cond_list>: New field. (bp_location) <condition_changed, cond_bytecode>: New fields. (is_breakpoint): New prototype.
Diffstat (limited to 'gdb/breakpoint.c')
-rw-r--r--gdb/breakpoint.c726
1 files changed, 716 insertions, 10 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index fd9dced..3303842 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -66,6 +66,7 @@
#include "skip.h"
#include "record.h"
#include "gdb_regex.h"
+#include "ax-gdb.h"
/* readline include files */
#include "readline/readline.h"
@@ -258,6 +259,8 @@ static void trace_pass_command (char *, int);
static int is_masked_watchpoint (const struct breakpoint *b);
+static struct bp_location **get_first_locp_gte_addr (CORE_ADDR address);
+
/* Return 1 if B refers to a static tracepoint set by marker ("-m"), zero
otherwise. */
@@ -406,6 +409,64 @@ breakpoints_always_inserted_mode (void)
&& !RECORD_IS_USED);
}
+static const char condition_evaluation_both[] = "host or target";
+
+/* Modes for breakpoint condition evaluation. */
+static const char condition_evaluation_auto[] = "auto";
+static const char condition_evaluation_host[] = "host";
+static const char condition_evaluation_target[] = "target";
+static const char *const condition_evaluation_enums[] = {
+ condition_evaluation_auto,
+ condition_evaluation_host,
+ condition_evaluation_target,
+ NULL
+};
+
+/* Global that holds the current mode for breakpoint condition evaluation. */
+static const char *condition_evaluation_mode_1 = condition_evaluation_auto;
+
+/* Global that we use to display information to the user (gets its value from
+ condition_evaluation_mode_1. */
+static const char *condition_evaluation_mode = condition_evaluation_auto;
+
+/* Translate a condition evaluation mode MODE into either "host"
+ or "target". This is used mostly to translate from "auto" to the
+ real setting that is being used. It returns the translated
+ evaluation mode. */
+
+static const char *
+translate_condition_evaluation_mode (const char *mode)
+{
+ if (mode == condition_evaluation_auto)
+ {
+ if (target_supports_evaluation_of_breakpoint_conditions ())
+ return condition_evaluation_target;
+ else
+ return condition_evaluation_host;
+ }
+ else
+ return mode;
+}
+
+/* Discovers what condition_evaluation_auto translates to. */
+
+static const char *
+breakpoint_condition_evaluation_mode (void)
+{
+ return translate_condition_evaluation_mode (condition_evaluation_mode);
+}
+
+/* Return true if GDB should evaluate breakpoint conditions or false
+ otherwise. */
+
+static int
+gdb_evaluates_breakpoint_condition_p (void)
+{
+ const char *mode = breakpoint_condition_evaluation_mode ();
+
+ return (mode == condition_evaluation_host);
+}
+
void _initialize_breakpoint (void);
/* Are we executing breakpoint commands? */
@@ -437,6 +498,20 @@ int target_exact_watchpoints = 0;
BP_TMP < bp_location + bp_location_count && (B = *BP_TMP); \
BP_TMP++)
+/* Iterates through locations with address ADDRESS for the currently selected
+ program space. BP_LOCP_TMP points to each object. BP_LOCP_START points
+ to where the loop should start from.
+ If BP_LOCP_START is a NULL pointer, the macro automatically seeks the
+ appropriate location to start with. */
+
+#define ALL_BP_LOCATIONS_AT_ADDR(BP_LOCP_TMP, BP_LOCP_START, ADDRESS) \
+ for (BP_LOCP_START = BP_LOCP_START == NULL ? get_first_locp_gte_addr (ADDRESS) : BP_LOCP_START, \
+ BP_LOCP_TMP = BP_LOCP_START; \
+ BP_LOCP_START \
+ && (BP_LOCP_TMP < bp_location + bp_location_count \
+ && (*BP_LOCP_TMP)->address == ADDRESS); \
+ BP_LOCP_TMP++)
+
/* Iterator for tracepoints only. */
#define ALL_TRACEPOINTS(B) \
@@ -620,6 +695,178 @@ get_breakpoint (int num)
+/* Mark locations as "conditions have changed" in case the target supports
+ evaluating conditions on its side. */
+
+static void
+mark_breakpoint_modified (struct breakpoint *b)
+{
+ struct bp_location *loc;
+
+ /* This is only meaningful if the target is
+ evaluating conditions and if the user has
+ opted for condition evaluation on the target's
+ side. */
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return;
+
+ if (!is_breakpoint (b))
+ return;
+
+ for (loc = b->loc; loc; loc = loc->next)
+ loc->condition_changed = condition_modified;
+}
+
+/* Mark location as "conditions have changed" in case the target supports
+ evaluating conditions on its side. */
+
+static void
+mark_breakpoint_location_modified (struct bp_location *loc)
+{
+ /* This is only meaningful if the target is
+ evaluating conditions and if the user has
+ opted for condition evaluation on the target's
+ side. */
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+
+ return;
+
+ if (!is_breakpoint (loc->owner))
+ return;
+
+ loc->condition_changed = condition_modified;
+}
+
+/* Sets the condition-evaluation mode using the static global
+ condition_evaluation_mode. */
+
+static void
+set_condition_evaluation_mode (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct breakpoint *b;
+ const char *old_mode, *new_mode;
+
+ if ((condition_evaluation_mode_1 == condition_evaluation_target)
+ && !target_supports_evaluation_of_breakpoint_conditions ())
+ {
+ condition_evaluation_mode_1 = condition_evaluation_mode;
+ warning (_("Target does not support breakpoint condition evaluation.\n"
+ "Using host evaluation mode instead."));
+ return;
+ }
+
+ new_mode = translate_condition_evaluation_mode (condition_evaluation_mode_1);
+ old_mode = translate_condition_evaluation_mode (condition_evaluation_mode);
+
+ /* Only update the mode if the user picked a different one. */
+ if (new_mode != old_mode)
+ {
+ struct bp_location *loc, **loc_tmp;
+ /* If the user switched to a different evaluation mode, we
+ need to synch the changes with the target as follows:
+
+ "host" -> "target": Send all (valid) conditions to the target.
+ "target" -> "host": Remove all the conditions from the target.
+ */
+
+ /* Flip the switch. */
+ condition_evaluation_mode = condition_evaluation_mode_1;
+
+ if (new_mode == condition_evaluation_target)
+ {
+ /* Mark everything modified and synch conditions with the
+ target. */
+ ALL_BP_LOCATIONS (loc, loc_tmp)
+ mark_breakpoint_location_modified (loc);
+ }
+ else
+ {
+ /* Manually mark non-duplicate locations to synch conditions
+ with the target. We do this to remove all the conditions the
+ target knows about. */
+ ALL_BP_LOCATIONS (loc, loc_tmp)
+ if (is_breakpoint (loc->owner) && loc->inserted)
+ loc->needs_update = 1;
+ }
+
+ /* Do the update. */
+ update_global_location_list (1);
+ }
+
+ return;
+}
+
+/* Shows the current mode of breakpoint condition evaluation. Explicitly shows
+ what "auto" is translating to. */
+
+static void
+show_condition_evaluation_mode (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ if (condition_evaluation_mode == condition_evaluation_auto)
+ fprintf_filtered (file,
+ _("Breakpoint condition evaluation "
+ "mode is %s (currently %s).\n"),
+ value,
+ breakpoint_condition_evaluation_mode ());
+ else
+ fprintf_filtered (file, _("Breakpoint condition evaluation mode is %s.\n"),
+ value);
+}
+
+/* A comparison function for bp_location AP and BP that is used by
+ bsearch. This comparison function only cares about addresses, unlike
+ the more general bp_location_compare function. */
+
+static int
+bp_location_compare_addrs (const void *ap, const void *bp)
+{
+ struct bp_location *a = *(void **) ap;
+ struct bp_location *b = *(void **) bp;
+
+ if (a->address == b->address)
+ return 0;
+ else
+ return ((a->address > b->address) - (a->address < b->address));
+}
+
+/* Helper function to skip all bp_locations with addresses
+ less than ADDRESS. It returns the first bp_location that
+ is greater than or equal to ADDRESS. If none is found, just
+ return NULL. */
+
+static struct bp_location **
+get_first_locp_gte_addr (CORE_ADDR address)
+{
+ struct bp_location dummy_loc;
+ struct bp_location *dummy_locp = &dummy_loc;
+ struct bp_location **locp_found = NULL;
+
+ /* Initialize the dummy location's address field. */
+ memset (&dummy_loc, 0, sizeof (struct bp_location));
+ dummy_loc.address = address;
+
+ /* Find a close match to the first location at ADDRESS. */
+ locp_found = bsearch (&dummy_locp, bp_location, bp_location_count,
+ sizeof (struct bp_location **),
+ bp_location_compare_addrs);
+
+ /* Nothing was found, nothing left to do. */
+ if (locp_found == NULL)
+ return NULL;
+
+ /* We may have found a location that is at ADDRESS but is not the first in the
+ location's list. Go backwards (if possible) and locate the first one. */
+ while ((locp_found - 1) >= bp_location
+ && (*(locp_found - 1))->address == address)
+ locp_found--;
+
+ return locp_found;
+}
+
void
set_breakpoint_condition (struct breakpoint *b, char *exp,
int from_tty)
@@ -642,6 +889,10 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
{
xfree (loc->cond);
loc->cond = NULL;
+
+ /* No need to free the condition agent expression
+ bytecode (if we have one). We will handle this
+ when we go through update_global_location_list. */
}
}
@@ -684,6 +935,8 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
}
}
}
+ mark_breakpoint_modified (b);
+
breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
@@ -717,6 +970,10 @@ condition_command (char *arg, int from_tty)
error (_("Cannot set a condition where a Python 'stop' "
"method has been defined in the breakpoint."));
set_breakpoint_condition (b, p, from_tty);
+
+ if (is_breakpoint (b))
+ update_global_location_list (1);
+
return;
}
@@ -1216,6 +1473,16 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
}
+/* Return true if BPT is either a software breakpoint or a hardware
+ breakpoint. */
+
+int
+is_breakpoint (const struct breakpoint *bpt)
+{
+ return (bpt->type == bp_breakpoint
+ || bpt->type == bp_hardware_breakpoint);
+}
+
/* Return true if BPT is of any hardware watchpoint kind. */
static int
@@ -1658,6 +1925,143 @@ unduplicated_should_be_inserted (struct bp_location *bl)
return result;
}
+/* Parses a conditional described by an expression COND into an
+ agent expression bytecode suitable for evaluation
+ by the bytecode interpreter. Return NULL if there was
+ any error during parsing. */
+
+static struct agent_expr *
+parse_cond_to_aexpr (CORE_ADDR scope, struct expression *cond)
+{
+ struct agent_expr *aexpr = NULL;
+ struct cleanup *old_chain = NULL;
+ volatile struct gdb_exception ex;
+
+ if (!cond)
+ return NULL;
+
+ /* We don't want to stop processing, so catch any errors
+ that may show up. */
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ aexpr = gen_eval_for_expr (scope, cond);
+ }
+
+ if (ex.reason < 0)
+ {
+ /* If we got here, it means the condition could not be parsed to a valid
+ bytecode expression and thus can't be evaluated on the target's side.
+ It's no use iterating through the conditions. */
+ return NULL;
+ }
+
+ /* We have a valid agent expression. */
+ return aexpr;
+}
+
+/* Based on location BL, create a list of breakpoint conditions to be
+ passed on to the target. If we have duplicated locations with different
+ conditions, we will add such conditions to the list. The idea is that the
+ target will evaluate the list of conditions and will only notify GDB when
+ one of them is true. */
+
+static void
+build_target_condition_list (struct bp_location *bl)
+{
+ struct bp_location **locp = NULL, **loc2p;
+ int null_condition_or_parse_error = 0;
+ int modified = bl->needs_update;
+ struct bp_location *loc;
+
+ /* This is only meaningful if the target is
+ evaluating conditions and if the user has
+ opted for condition evaluation on the target's
+ side. */
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return;
+
+ /* Do a first pass to check for locations with no assigned
+ conditions or conditions that fail to parse to a valid agent expression
+ bytecode. If any of these happen, then it's no use to send conditions
+ to the target since this location will always trigger and generate a
+ response back to GDB. */
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+ {
+ loc = (*loc2p);
+ if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
+ {
+ if (modified)
+ {
+ struct agent_expr *aexpr;
+
+ /* Re-parse the conditions since something changed. In that
+ case we already freed the condition bytecodes (see
+ force_breakpoint_reinsertion). We just
+ need to parse the condition to bytecodes again. */
+ aexpr = parse_cond_to_aexpr (bl->address, loc->cond);
+ loc->cond_bytecode = aexpr;
+
+ /* Check if we managed to parse the conditional expression
+ correctly. If not, we will not send this condition
+ to the target. */
+ if (aexpr)
+ continue;
+ }
+
+ /* If we have a NULL bytecode expression, it means something
+ went wrong or we have a null condition expression. */
+ if (!loc->cond_bytecode)
+ {
+ null_condition_or_parse_error = 1;
+ break;
+ }
+ }
+ }
+
+ /* If any of these happened, it means we will have to evaluate the conditions
+ for the location's address on gdb's side. It is no use keeping bytecodes
+ for all the other duplicate locations, thus we free all of them here.
+
+ This is so we have a finer control over which locations' conditions are
+ being evaluated by GDB or the remote stub. */
+ if (null_condition_or_parse_error)
+ {
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+ {
+ loc = (*loc2p);
+ if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
+ {
+ /* Only go as far as the first NULL bytecode is
+ located. */
+ if (!loc->cond_bytecode)
+ return;
+
+ free_agent_expr (loc->cond_bytecode);
+ loc->cond_bytecode = NULL;
+ }
+ }
+ }
+
+ /* No NULL conditions or failed bytecode generation. Build a condition list
+ for this location's address. */
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+ {
+ loc = (*loc2p);
+ if (loc->cond
+ && is_breakpoint (loc->owner)
+ && loc->pspace->num == bl->pspace->num
+ && loc->owner->enable_state == bp_enabled
+ && loc->enabled)
+ /* Add the condition to the vector. This will be used later to send the
+ conditions to the target. */
+ VEC_safe_push (agent_expr_p, bl->target_info.conditions,
+ loc->cond_bytecode);
+ }
+
+ return;
+}
+
/* Insert a low-level "breakpoint" of some type. BL is the breakpoint
location. Any error messages are printed to TMP_ERROR_STREAM; and
DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
@@ -1674,7 +2078,7 @@ insert_bp_location (struct bp_location *bl,
{
int val = 0;
- if (!should_be_inserted (bl) || bl->inserted)
+ if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
return 0;
/* Initialize the target-specific information. */
@@ -1683,6 +2087,18 @@ insert_bp_location (struct bp_location *bl,
bl->target_info.placed_address_space = bl->pspace->aspace;
bl->target_info.length = bl->length;
+ /* When working with target-side conditions, we must pass all the conditions
+ for the same breakpoint address down to the target since GDB will not
+ insert those locations. With a list of breakpoint conditions, the target
+ can decide when to stop and notify GDB. */
+
+ if (is_breakpoint (bl->owner))
+ {
+ build_target_condition_list (bl);
+ /* Reset the condition modification marker. */
+ bl->needs_update = 0;
+ }
+
if (bl->loc_type == bp_loc_software_breakpoint
|| bl->loc_type == bp_loc_hardware_breakpoint)
{
@@ -1991,6 +2407,66 @@ insert_breakpoints (void)
insert_breakpoint_locations ();
}
+/* This is used when we need to synch breakpoint conditions between GDB and the
+ target. It is the case with deleting and disabling of breakpoints when using
+ always-inserted mode. */
+
+static void
+update_inserted_breakpoint_locations (void)
+{
+ struct bp_location *bl, **blp_tmp;
+ int error_flag = 0;
+ int val = 0;
+ int disabled_breaks = 0;
+ int hw_breakpoint_error = 0;
+
+ struct ui_file *tmp_error_stream = mem_fileopen ();
+ struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream);
+
+ /* Explicitly mark the warning -- this will only be printed if
+ there was an error. */
+ fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+
+ save_current_space_and_thread ();
+
+ ALL_BP_LOCATIONS (bl, blp_tmp)
+ {
+ /* We only want to update software breakpoints and hardware
+ breakpoints. */
+ if (!is_breakpoint (bl->owner))
+ continue;
+
+ /* We only want to update locations that are already inserted
+ and need updating. This is to avoid unwanted insertion during
+ deletion of breakpoints. */
+ if (!bl->inserted || (bl->inserted && !bl->needs_update))
+ continue;
+
+ switch_to_program_space_and_thread (bl->pspace);
+
+ /* For targets that support global breakpoints, there's no need
+ to select an inferior to insert breakpoint to. In fact, even
+ if we aren't attached to any process yet, we should still
+ insert breakpoints. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch)
+ && ptid_equal (inferior_ptid, null_ptid))
+ continue;
+
+ val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks,
+ &hw_breakpoint_error);
+ if (val)
+ error_flag = val;
+ }
+
+ if (error_flag)
+ {
+ target_terminal_ours_for_output ();
+ error_stream (tmp_error_stream);
+ }
+
+ do_cleanups (cleanups);
+}
+
/* Used when starting or continuing the program. */
static void
@@ -2014,7 +2490,7 @@ insert_breakpoint_locations (void)
ALL_BP_LOCATIONS (bl, blp_tmp)
{
- if (!should_be_inserted (bl) || bl->inserted)
+ if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
continue;
/* There is no point inserting thread-specific breakpoints if
@@ -4092,6 +4568,10 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
b = bs->breakpoint_at;
gdb_assert (b != NULL);
+ /* Even if the target evaluated the condition on its end and notified GDB, we
+ need to do so again since GDB does not know if we stopped due to a
+ breakpoint or a single step breakpoint. */
+
if (frame_id_p (b->frame_id)
&& !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ())))
bs->stop = 0;
@@ -4669,6 +5149,66 @@ wrap_indent_at_field (struct ui_out *uiout, const char *col_name)
return NULL;
}
+/* Determine if the locations of this breakpoint will have their conditions
+ evaluated by the target, host or a mix of both. Returns the following:
+
+ "host": Host evals condition.
+ "host or target": Host or Target evals condition.
+ "target": Target evals condition.
+*/
+
+static const char *
+bp_condition_evaluator (struct breakpoint *b)
+{
+ struct bp_location *bl;
+ char host_evals = 0;
+ char target_evals = 0;
+
+ if (!b)
+ return NULL;
+
+ if (!is_breakpoint (b))
+ return NULL;
+
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return condition_evaluation_host;
+
+ for (bl = b->loc; bl; bl = bl->next)
+ {
+ if (bl->cond_bytecode)
+ target_evals++;
+ else
+ host_evals++;
+ }
+
+ if (host_evals && target_evals)
+ return condition_evaluation_both;
+ else if (target_evals)
+ return condition_evaluation_target;
+ else
+ return condition_evaluation_host;
+}
+
+/* Determine the breakpoint location's condition evaluator. This is
+ similar to bp_condition_evaluator, but for locations. */
+
+static const char *
+bp_location_condition_evaluator (struct bp_location *bl)
+{
+ if (bl && !is_breakpoint (bl->owner))
+ return NULL;
+
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return condition_evaluation_host;
+
+ if (bl && bl->cond_bytecode)
+ return condition_evaluation_target;
+ else
+ return condition_evaluation_host;
+}
+
/* Print the LOC location out of the list of B->LOC locations. */
static void
@@ -4727,6 +5267,16 @@ print_breakpoint_location (struct breakpoint *b,
else
ui_out_field_string (uiout, "pending", b->addr_string);
+ if (loc && is_breakpoint (b)
+ && breakpoint_condition_evaluation_mode () == condition_evaluation_target
+ && bp_condition_evaluator (b) == condition_evaluation_both)
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "evaluated-by",
+ bp_location_condition_evaluator (loc));
+ ui_out_text (uiout, ")");
+ }
+
do_cleanups (old_chain);
}
@@ -5002,6 +5552,18 @@ print_one_breakpoint_location (struct breakpoint *b,
else
ui_out_text (uiout, "\tstop only if ");
ui_out_field_string (uiout, "cond", b->cond_string);
+
+ /* Print whether the target is doing the breakpoint's condition
+ evaluation. If GDB is doing the evaluation, don't print anything. */
+ if (is_breakpoint (b)
+ && breakpoint_condition_evaluation_mode ()
+ == condition_evaluation_target)
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "evaluated-by",
+ bp_condition_evaluator (b));
+ ui_out_text (uiout, " evals)");
+ }
ui_out_text (uiout, "\n");
}
@@ -5731,6 +6293,7 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
loc->ops = ops;
loc->owner = owner;
loc->cond = NULL;
+ loc->cond_bytecode = NULL;
loc->shlib_disabled = 0;
loc->enabled = 1;
@@ -5758,9 +6321,11 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
case bp_gnu_ifunc_resolver:
case bp_gnu_ifunc_resolver_return:
loc->loc_type = bp_loc_software_breakpoint;
+ mark_breakpoint_location_modified (loc);
break;
case bp_hardware_breakpoint:
loc->loc_type = bp_loc_hardware_breakpoint;
+ mark_breakpoint_location_modified (loc);
break;
case bp_hardware_watchpoint:
case bp_read_watchpoint:
@@ -10718,6 +11283,7 @@ swap_insertion (struct bp_location *left, struct bp_location *right)
{
const int left_inserted = left->inserted;
const int left_duplicate = left->duplicate;
+ const int left_needs_update = left->needs_update;
const struct bp_target_info left_target_info = left->target_info;
/* Locations of tracepoints can never be duplicated. */
@@ -10728,12 +11294,67 @@ swap_insertion (struct bp_location *left, struct bp_location *right)
left->inserted = right->inserted;
left->duplicate = right->duplicate;
+ left->needs_update = right->needs_update;
left->target_info = right->target_info;
right->inserted = left_inserted;
right->duplicate = left_duplicate;
+ right->needs_update = left_needs_update;
right->target_info = left_target_info;
}
+/* Force the re-insertion of the locations at ADDRESS. This is called
+ once a new/deleted/modified duplicate location is found and we are evaluating
+ conditions on the target's side. Such conditions need to be updated on
+ the target. */
+
+static void
+force_breakpoint_reinsertion (struct bp_location *bl)
+{
+ struct bp_location **locp = NULL, **loc2p;
+ struct bp_location *loc;
+ CORE_ADDR address = 0;
+ int pspace_num;
+
+ address = bl->address;
+ pspace_num = bl->pspace->num;
+
+ /* This is only meaningful if the target is
+ evaluating conditions and if the user has
+ opted for condition evaluation on the target's
+ side. */
+ if (gdb_evaluates_breakpoint_condition_p ()
+ || !target_supports_evaluation_of_breakpoint_conditions ())
+ return;
+
+ /* Flag all breakpoint locations with this address and
+ the same program space as the location
+ as "its condition has changed". We need to
+ update the conditions on the target's side. */
+ ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, address)
+ {
+ loc = *loc2p;
+
+ if (!is_breakpoint (loc->owner)
+ || pspace_num != loc->pspace->num)
+ continue;
+
+ /* Flag the location appropriately. We use a different state to
+ let everyone know that we already updated the set of locations
+ with addr bl->address and program space bl->pspace. This is so
+ we don't have to keep calling these functions just to mark locations
+ that have already been marked. */
+ loc->condition_changed = condition_updated;
+
+ /* Free the agent expression bytecode as well. We will compute
+ it later on. */
+ if (loc->cond_bytecode)
+ {
+ free_agent_expr (loc->cond_bytecode);
+ loc->cond_bytecode = NULL;
+ }
+ }
+}
+
/* If SHOULD_INSERT is false, do not insert any breakpoint locations
into the inferior, only remove already-inserted locations that no
longer should be inserted. Functions that delete a breakpoint or
@@ -10755,6 +11376,10 @@ update_global_location_list (int should_insert)
struct breakpoint *b;
struct bp_location **locp, *loc;
struct cleanup *cleanups;
+ /* Last breakpoint location address that was marked for update. */
+ CORE_ADDR last_addr = 0;
+ /* Last breakpoint location program space that was marked for update. */
+ int last_pspace_num = -1;
/* Used in the duplicates detection below. When iterating over all
bp_locations, points to the first bp_location of a given address.
@@ -10827,13 +11452,30 @@ update_global_location_list (int should_insert)
&& (*loc2p)->address == old_loc->address);
loc2p++)
{
- if (*loc2p == old_loc)
+ /* Check if this is a new/duplicated location or a duplicated
+ location that had its condition modified. If so, we want to send
+ its condition to the target if evaluation of conditions is taking
+ place there. */
+ if ((*loc2p)->condition_changed == condition_modified
+ && (last_addr != old_loc->address
+ || last_pspace_num != old_loc->pspace->num))
{
- found_object = 1;
- break;
+ force_breakpoint_reinsertion (*loc2p);
+ last_pspace_num = old_loc->pspace->num;
}
+
+ if (*loc2p == old_loc)
+ found_object = 1;
}
+ /* We have already handled this address, update it so that we don't
+ have to go through updates again. */
+ last_addr = old_loc->address;
+
+ /* Target-side condition evaluation: Handle deleted locations. */
+ if (!found_object)
+ force_breakpoint_reinsertion (old_loc);
+
/* If this location is no longer present, and inserted, look if
there's maybe a new location at the same address. If so,
mark that one inserted, and don't remove this one. This is
@@ -10853,6 +11495,10 @@ update_global_location_list (int should_insert)
}
else
{
+ /* This location still exists, but it won't be kept in the
+ target since it may have been disabled. We proceed to
+ remove its target-side condition. */
+
/* The location is either no longer present, or got
disabled. See if there's another location at the
same address, in which case we don't need to remove
@@ -11005,7 +11651,11 @@ update_global_location_list (int should_insert)
never duplicated. See the comments in field `duplicate' of
`struct bp_location'. */
|| is_tracepoint (b))
- continue;
+ {
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+ continue;
+ }
/* Permanent breakpoint should always be inserted. */
if (b->enable_state == bp_permanent && ! loc->inserted)
@@ -11028,6 +11678,13 @@ update_global_location_list (int should_insert)
{
*loc_first_p = loc;
loc->duplicate = 0;
+
+ if (is_breakpoint (loc->owner) && loc->condition_changed)
+ {
+ loc->needs_update = 1;
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+ }
continue;
}
@@ -11039,6 +11696,9 @@ update_global_location_list (int should_insert)
swap_insertion (loc, *loc_first_p);
loc->duplicate = 1;
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+
if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted
&& b->enable_state != bp_permanent)
internal_error (__FILE__, __LINE__,
@@ -11046,10 +11706,21 @@ update_global_location_list (int should_insert)
"a permanent breakpoint"));
}
- if (breakpoints_always_inserted_mode () && should_insert
+ if (breakpoints_always_inserted_mode ()
&& (have_live_inferiors ()
|| (gdbarch_has_global_breakpoints (target_gdbarch))))
- insert_breakpoint_locations ();
+ {
+ if (should_insert)
+ insert_breakpoint_locations ();
+ else
+ {
+ /* Though should_insert is false, we may need to update conditions
+ on the target's side if it is evaluating such conditions. We
+ only update conditions for locations that are marked
+ "needs_update". */
+ update_inserted_breakpoint_locations ();
+ }
+ }
if (should_insert)
download_tracepoint_locations ();
@@ -11163,6 +11834,8 @@ static void
bp_location_dtor (struct bp_location *self)
{
xfree (self->cond);
+ if (self->cond_bytecode)
+ free_agent_expr (self->cond_bytecode);
xfree (self->function_name);
xfree (self->source_file);
}
@@ -12856,6 +13529,9 @@ disable_breakpoint (struct breakpoint *bpt)
bpt->enable_state = bp_disabled;
+ /* Mark breakpoint locations modified. */
+ mark_breakpoint_modified (bpt);
+
if (target_supports_enable_disable_tracepoint ()
&& current_trace_status ()->running && is_tracepoint (bpt))
{
@@ -12903,7 +13579,11 @@ disable_command (char *args, int from_tty)
struct bp_location *loc = find_location_by_number (args);
if (loc)
{
- loc->enabled = 0;
+ if (loc->enabled)
+ {
+ loc->enabled = 0;
+ mark_breakpoint_location_modified (loc);
+ }
if (target_supports_enable_disable_tracepoint ()
&& current_trace_status ()->running && loc->owner
&& is_tracepoint (loc->owner))
@@ -12960,6 +13640,11 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition,
if (bpt->enable_state != bp_permanent)
bpt->enable_state = bp_enabled;
+ bpt->enable_state = bp_enabled;
+
+ /* Mark breakpoint locations modified. */
+ mark_breakpoint_modified (bpt);
+
if (target_supports_enable_disable_tracepoint ()
&& current_trace_status ()->running && is_tracepoint (bpt))
{
@@ -13019,7 +13704,11 @@ enable_command (char *args, int from_tty)
struct bp_location *loc = find_location_by_number (args);
if (loc)
{
- loc->enabled = 1;
+ if (!loc->enabled)
+ {
+ loc->enabled = 1;
+ mark_breakpoint_location_modified (loc);
+ }
if (target_supports_enable_disable_tracepoint ()
&& current_trace_status ()->running && loc->owner
&& is_tracepoint (loc->owner))
@@ -14794,6 +15483,23 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
+ add_setshow_enum_cmd ("condition-evaluation", class_breakpoint,
+ condition_evaluation_enums,
+ &condition_evaluation_mode_1, _("\
+Set mode of breakpoint condition evaluation."), _("\
+Show mode of breakpoint condition evaluation."), _("\
+When this is set to \"gdb\", breakpoint conditions will be\n\
+evaluated on the host's side by GDB. When it is set to \"target\",\n\
+breakpoint conditions will be downloaded to the target (if the target\n\
+supports such feature) and conditions will be evaluated on the target's side.\n\
+If this is set to \"auto\" (default), this will be automatically set to\n\
+\"target\" if it supports condition evaluation, otherwise it will\n\
+be set to \"gdb\""),
+ &set_condition_evaluation_mode,
+ &show_condition_evaluation_mode,
+ &breakpoint_set_cmdlist,
+ &breakpoint_show_cmdlist);
+
add_com ("break-range", class_breakpoint, break_range_command, _("\
Set a breakpoint for an address range.\n\
break-range START-LOCATION, END-LOCATION\n\