mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-27 09:38:57 +00:00
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.
This commit is contained in:
726
gdb/breakpoint.c
726
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\
|
||||
|
||||
Reference in New Issue
Block a user