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:
Luis Machado 2012-02-24 15:10:59 +00:00
parent 3788aec75a
commit b775012e84
7 changed files with 905 additions and 10 deletions

View File

@ -1,3 +1,80 @@
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.
2012-02-24 Luis Machado <lgustavo@codesourcery.com>
* remote.c (remote_state) <cond_breakpoints>: New field.

View File

@ -20,6 +20,7 @@
#define AGENTEXPR_H
#include "doublest.h" /* For DOUBLEST. */
#include "vec.h"
/* It's sometimes useful to be able to debug programs that you can't
really stop for more than a fraction of a second. To this end, the
@ -144,6 +145,12 @@ struct agent_expr
unsigned char *reg_mask;
};
/* Pointer to an agent_expr structure. */
typedef struct agent_expr *agent_expr_p;
/* Vector of pointers to agent expressions. */
DEF_VEC_P (agent_expr_p);
/* The actual values of the various bytecode operations. */
enum agent_op

View File

@ -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\

View File

@ -22,6 +22,7 @@
#include "frame.h"
#include "value.h"
#include "vec.h"
#include "ax.h"
struct value;
struct block;
@ -215,6 +216,16 @@ enum target_hw_bp_type
};
/* Status of breakpoint conditions used when synchronizing
conditions with the target. */
enum condition_status
{
condition_unchanged = 0,
condition_modified,
condition_updated
};
/* Information used by targets to insert and remove breakpoints. */
struct bp_target_info
@ -249,6 +260,10 @@ struct bp_target_info
(e.g. if a remote stub handled the details). We may still need
the size to remove the breakpoint safely. */
int placed_size;
/* Vector of conditions the target should evaluate if it supports target-side
breakpoint conditions. */
VEC(agent_expr_p) *conditions;
};
/* GDB maintains two types of information about each breakpoint (or
@ -315,6 +330,30 @@ struct bp_location
the owner breakpoint object. */
struct expression *cond;
/* Conditional expression in agent expression
bytecode form. This is used for stub-side breakpoint
condition evaluation. */
struct agent_expr *cond_bytecode;
/* Signals that the condition has changed since the last time
we updated the global location list. This means the condition
needs to be sent to the target again. This is used together
with target-side breakpoint conditions.
condition_unchanged: It means there has been no condition changes.
condition_modified: It means this location had its condition modified.
condition_updated: It means we already marked all the locations that are
duplicates of this location and thus we don't need to call
force_breakpoint_reinsertion (...) for this location. */
enum condition_status condition_changed;
/* Signals that breakpoint conditions need to be re-synched with the
target. This has no use other than target-side breakpoints. */
char needs_update;
/* This location's address is in an unloaded solib, and so this
location should not be inserted. It will be automatically
enabled when that solib is loaded. */
@ -726,6 +765,11 @@ struct watchpoint
CORE_ADDR hw_wp_mask;
};
/* Return true if BPT is either a software breakpoint or a hardware
breakpoint. */
extern int is_breakpoint (const struct breakpoint *bpt);
/* Returns true if BPT is really a watchpoint. */
extern int is_watchpoint (const struct breakpoint *bpt);

View File

@ -242,6 +242,8 @@ static int remote_read_description_p (struct target_ops *target);
static void remote_console_output (char *msg);
static int remote_supports_cond_breakpoints (void);
/* The non-stop remote protocol provisions for one pending stop reply.
This is where we keep it until it is acknowledged. */
@ -7729,6 +7731,43 @@ extended_remote_create_inferior (struct target_ops *ops,
}
/* Given a location's target info BP_TGT and the packet buffer BUF, output
the list of conditions (in agent expression bytecode format), if any, the
target needs to evaluate. The output is placed into the packet buffer
BUF. */
static int
remote_add_target_side_condition (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt, char *buf)
{
struct agent_expr *aexpr = NULL;
int i, ix;
char *pkt;
char *buf_start = buf;
if (VEC_empty (agent_expr_p, bp_tgt->conditions))
return 0;
buf += strlen (buf);
sprintf (buf, "%s", ";");
buf++;
/* Send conditions to the target and free the vector. */
for (ix = 0;
VEC_iterate (agent_expr_p, bp_tgt->conditions, ix, aexpr);
ix++)
{
sprintf (buf, "X%x,", aexpr->len);
buf += strlen (buf);
for (i = 0; i < aexpr->len; ++i)
buf = pack_hex_byte (buf, aexpr->buf[i]);
*buf = '\0';
}
VEC_free (agent_expr_p, bp_tgt->conditions);
return 0;
}
/* Insert a breakpoint. On targets that have software breakpoint
support, we ask the remote target to do the work; on targets
which don't, we insert a traditional memory breakpoint. */
@ -7748,6 +7787,7 @@ remote_insert_breakpoint (struct gdbarch *gdbarch,
struct remote_state *rs;
char *p;
int bpsize;
struct condition_list *cond = NULL;
gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
@ -7761,6 +7801,9 @@ remote_insert_breakpoint (struct gdbarch *gdbarch,
p += hexnumstr (p, addr);
sprintf (p, ",%d", bpsize);
if (remote_supports_cond_breakpoints ())
remote_add_target_side_condition (gdbarch, bp_tgt, p);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
@ -7986,6 +8029,9 @@ remote_insert_hw_breakpoint (struct gdbarch *gdbarch,
p += hexnumstr (p, (ULONGEST) addr);
sprintf (p, ",%x", bp_tgt->placed_size);
if (remote_supports_cond_breakpoints ())
remote_add_target_side_condition (gdbarch, bp_tgt, p);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
@ -10781,6 +10827,7 @@ Specify the serial device it is connected to\n\
remote_ops.to_fileio_readlink = remote_hostio_readlink;
remote_ops.to_supports_enable_disable_tracepoint = remote_supports_enable_disable_tracepoint;
remote_ops.to_supports_string_tracing = remote_supports_string_tracing;
remote_ops.to_supports_evaluation_of_breakpoint_conditions = remote_supports_cond_breakpoints;
remote_ops.to_trace_init = remote_trace_init;
remote_ops.to_download_tracepoint = remote_download_tracepoint;
remote_ops.to_can_download_tracepoint = remote_can_download_tracepoint;

View File

@ -699,6 +699,7 @@ update_current_target (void)
INHERIT (to_static_tracepoint_markers_by_strid, t);
INHERIT (to_traceframe_info, t);
INHERIT (to_magic, t);
INHERIT (to_supports_evaluation_of_breakpoint_conditions, t);
/* Do not inherit to_memory_map. */
/* Do not inherit to_flash_erase. */
/* Do not inherit to_flash_done. */
@ -925,6 +926,9 @@ update_current_target (void)
de_fault (to_traceframe_info,
(struct traceframe_info * (*) (void))
tcomplain);
de_fault (to_supports_evaluation_of_breakpoint_conditions,
(int (*) (void))
return_zero);
de_fault (to_execution_direction, default_execution_direction);
#undef de_fault

View File

@ -662,6 +662,10 @@ struct target_ops
/* Does this target support the tracenz bytecode for string collection? */
int (*to_supports_string_tracing) (void);
/* Does this target support evaluation of breakpoint conditions on its
end? */
int (*to_supports_evaluation_of_breakpoint_conditions) (void);
/* Determine current architecture of thread PTID.
The target is supposed to determine the architecture of the code where
@ -968,6 +972,12 @@ int target_supports_disable_randomization (void);
#define target_supports_string_tracing() \
(*current_target.to_supports_string_tracing) ()
/* Returns true if this target can handle breakpoint conditions
on its end. */
#define target_supports_evaluation_of_breakpoint_conditions() \
(*current_target.to_supports_evaluation_of_breakpoint_conditions) ()
/* Invalidate all target dcaches. */
extern void target_dcache_invalidate (void);