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:
parent
3788aec75a
commit
b775012e84
7 changed files with 905 additions and 10 deletions
|
@ -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.
|
||||
|
|
7
gdb/ax.h
7
gdb/ax.h
|
@ -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
|
||||
|
|
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\
|
||||
|
|
|
@ -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);
|
||||
|
|
47
gdb/remote.c
47
gdb/remote.c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
10
gdb/target.h
10
gdb/target.h
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue