* [rfc target-side break conditions 3/5 v2] GDB-side changes
@ 2012-01-27 20:34 Luis Gustavo
2012-02-06 20:27 ` Tom Tromey
2012-02-07 22:08 ` Stan Shebs
0 siblings, 2 replies; 16+ messages in thread
From: Luis Gustavo @ 2012-01-27 20:34 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1720 bytes --]
A few more changes on this patch. It addresses all the previous comments
and suggestions.
Multi-inferior cases are now properly handled through program space
checks, with the aid of an additional patch i posted recently:
http://sourceware.org/ml/gdb-patches/2012-01/msg00875.html.
If the user flips the condition evaluation switch in the middle of a
run, GDB takes appropriate actions to either remove the conditions from
the target or insert them.
There is also a mechanism to try and prevent delete_breakpoint (...)
from inserting new breakpoints when we're trying to remove breakpoints
to clean up for an execd.
It basically separates the user "delete" command from the internal
delete requests. There is now a function that does breakpoint deletion
with updates (passing 1 to update_global_location_list (...)) in order
to synchronize the list of breakpoint conditions with the target. Such a
function is only called via the delete_command (...) path.
I've changed the "info break" output a little. We now display "<mode>
evaluates conditions" next to the location description, and we also
output that same information via MI. Though it works, i'm not entirely
happy with the way it is displayed.
Previously i displayed such information next to the condition field, but
it doesn't work right for breakpoints with multiple locations since the
conditions are printed for the breakpoint instead of the locations.
Suggestions?
Last, i spent some time dealing with update_global_location_list (...)
in order to make the condition modification detection system a little
more robust and to avoid having to go through the location lists
unecessarily.
Tested with both GDB and GDBServer.
Luis
[-- Attachment #2: 0002-break_condition_bytecode.diff --]
[-- Type: text/x-patch, Size: 43484 bytes --]
2012-01-26 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_breakpoint_condition hook.
* target.c (update_current_target): Inherit
to_supports_breakpoint_conditions.
Default to_supports_breakpoint_conditions to return_zero.
* target.h (struct target_ops) <to_supports_breakpoint_conditions>:
New field.
(target_supports_breakpoint_conditions): New #define.
* breakpoint.c (get_first_locp_gte_addr): New forward declaration.
(condition_evaluation_auto,
condition_evaluation_gdb, condition_evaluation_stub,
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.
(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 (...).
(insert_breakpoint_locations): Handle target-side conditional
breakpoints.
(bpstat_check_breakpoint_conditions): Add comment.
(print_breakpoint_location): Print information on where the condition
will be evaluated.
(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.
(bp_location_dtor): Free agent expression bytecode.
(delete_breakpoint): Rename to delete_breakpoint_1, add new update
parameter and make it static.
(delete_breakpoint): New function.
(delete_breakpoint_with_update): New function.
(do_delete_breakpoint): Call delete_breakpoint_with_update (...) for
breakpoints.
(delete_command): Call do_delete_breakpoint (...) instead of
delete_breakpoint (...).
(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.
(bp_target_info) <cond_list>: New field.
(bp_location) <condition_changed, cond_bytecode>: New fields.
(is_breakpoint): New prototype.
Index: gdb/gdb/remote.c
===================================================================
--- gdb.orig/gdb/remote.c 2012-01-27 17:18:11.249821938 -0200
+++ gdb/gdb/remote.c 2012-01-27 17:18:12.777821938 -0200
@@ -242,6 +242,8 @@ static int remote_read_description_p (st
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. */
@@ -7720,6 +7722,47 @@ extended_remote_create_inferior (struct
}
\f
+/* 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_length (agent_expr_p, bp_tgt->conditions))
+ {
+ sprintf (buf + strlen (buf), "%s", ",conditions=");
+ }
+ else
+ return 0;
+
+ /* 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 + strlen (buf), "X%x,", aexpr->len);
+ pkt = buf + strlen (buf);
+ for (i = 0; i < aexpr->len; ++i)
+ pkt = pack_hex_byte (pkt, aexpr->buf[i]);
+ *pkt++ = ';';
+ *pkt = '\0';
+ }
+
+ pkt--;
+ *pkt = '\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. */
@@ -7739,6 +7782,7 @@ remote_insert_breakpoint (struct gdbarch
struct remote_state *rs;
char *p;
int bpsize;
+ struct condition_list *cond = NULL;
gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
@@ -7752,6 +7796,9 @@ remote_insert_breakpoint (struct 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);
@@ -7977,6 +8024,9 @@ remote_insert_hw_breakpoint (struct gdba
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);
@@ -10753,6 +10803,7 @@ Specify the serial device it is connecte
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_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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c 2012-01-27 17:16:36.909821938 -0200
+++ gdb/gdb/target.c 2012-01-27 17:18:12.777821938 -0200
@@ -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_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_breakpoint_conditions,
+ (int (*) (void))
+ return_zero);
de_fault (to_execution_direction, default_execution_direction);
#undef de_fault
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h 2012-01-27 17:16:36.881821938 -0200
+++ gdb/gdb/target.h 2012-01-27 17:18:12.781821938 -0200
@@ -662,6 +662,9 @@ struct target_ops
/* Does this target support the tracenz bytecode for string collection? */
int (*to_supports_string_tracing) (void);
+ /* Does this target support evaluation breakpoint conditions on its end? */
+ int (*to_supports_breakpoint_conditions) (void);
+
/* Determine current architecture of thread PTID.
The target is supposed to determine the architecture of the code where
@@ -968,6 +971,12 @@ int target_supports_disable_randomizatio
#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_breakpoint_conditions() \
+ (*current_target.to_supports_breakpoint_conditions) ()
+
/* Invalidate all target dcaches. */
extern void target_dcache_invalidate (void);
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c 2012-01-27 17:16:36.873821938 -0200
+++ gdb/gdb/breakpoint.c 2012-01-27 18:01:16.865821938 -0200
@@ -65,6 +65,7 @@
#include "stack.h"
#include "skip.h"
#include "record.h"
+#include "ax-gdb.h"
/* readline include files */
#include "readline/readline.h"
@@ -254,6 +255,8 @@ static void trace_pass_command (char *,
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. */
@@ -397,6 +400,62 @@ breakpoints_always_inserted_mode (void)
&& !RECORD_IS_USED);
}
+/* Modes for breakpoint condition evaluation. */
+static const char condition_evaluation_auto[] = "auto";
+static const char condition_evaluation_gdb[] = "gdb";
+static const char condition_evaluation_target[] = "target";
+static const char *condition_evaluation_enums[] = {
+ condition_evaluation_auto,
+ condition_evaluation_gdb,
+ 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 "gdb"
+ 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_breakpoint_conditions ())
+ return condition_evaluation_target;
+ else
+ return condition_evaluation_gdb;
+ }
+ 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_gdb);
+}
+
void _initialize_breakpoint (void);
/* Are we executing breakpoint commands? */
@@ -428,6 +487,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) \
+ if (!BP_LOCP_START) \
+ BP_LOCP_START = get_first_locp_gte_addr (ADDRESS); \
+ for (BP_LOCP_TMP = 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) \
@@ -611,6 +684,146 @@ get_breakpoint (int num)
\f
+/* 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_breakpoint_conditions ())
+ return;
+
+ if (!is_breakpoint (b))
+ return;
+
+ for (loc = b->loc; loc; loc = loc->next)
+ loc->condition_changed = 1;
+}
+
+/* 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_breakpoint_conditions ())
+
+ return;
+
+ if (!is_breakpoint (loc->owner))
+ return;
+
+ loc->condition_changed = 1;
+}
+
+/* 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_breakpoint_conditions ())
+ {
+ condition_evaluation_mode_1 = condition_evaluation_mode;
+ warning (_("Target does not support condition evaluation.\n"
+ "Using GDB 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:
+
+ "gdb" -> "target": Send all (valid) conditions to the target.
+ "target" -> "gdb": 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 to 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);
+}
+
+/* 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. */
+
+static struct bp_location **
+get_first_locp_gte_addr (CORE_ADDR address)
+{
+ struct bp_location **locp = bp_location;
+
+ while (locp < bp_location + bp_location_count
+ && (*locp)->address < address)
+ locp++;
+
+ return locp;
+}
+
void
set_breakpoint_condition (struct breakpoint *b, char *exp,
int from_tty)
@@ -633,6 +846,10 @@ set_breakpoint_condition (struct breakpo
{
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 (...). */
}
}
@@ -675,6 +892,8 @@ set_breakpoint_condition (struct breakpo
}
}
}
+ mark_breakpoint_modified (b);
+
breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
@@ -708,6 +927,10 @@ condition_command (char *arg, int from_t
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;
}
@@ -1207,6 +1430,16 @@ breakpoint_xfer_memory (gdb_byte *readbu
}
\f
+/* Return true if BPT is of any breakpoint kind, hardware or
+ software. */
+
+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
@@ -1649,6 +1882,143 @@ unduplicated_should_be_inserted (struct
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 parse 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_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 == bl->pspace)
+ {
+ 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 == bl->pspace)
+ {
+ /* 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 == bl->pspace
+ && 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.
@@ -1665,7 +2035,7 @@ insert_bp_location (struct bp_location *
{
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. */
@@ -1674,6 +2044,18 @@ insert_bp_location (struct bp_location *
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)
{
@@ -2005,7 +2387,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
@@ -4013,6 +4395,10 @@ bpstat_check_breakpoint_conditions (bpst
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;
@@ -4647,6 +5033,18 @@ print_breakpoint_location (struct breakp
else
ui_out_field_string (uiout, "pending", b->addr_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) && loc && loc->cond_bytecode
+ && (breakpoint_condition_evaluation_mode ()
+ != condition_evaluation_gdb))
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "evaluated-by",
+ breakpoint_condition_evaluation_mode ());
+ ui_out_text (uiout, " evaluates conditions)");
+ }
+
do_cleanups (old_chain);
}
@@ -5634,6 +6032,7 @@ init_bp_location (struct bp_location *lo
loc->ops = ops;
loc->owner = owner;
loc->cond = NULL;
+ loc->cond_bytecode = NULL;
loc->shlib_disabled = 0;
loc->enabled = 1;
@@ -5661,9 +6060,11 @@ init_bp_location (struct bp_location *lo
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:
@@ -10326,6 +10727,7 @@ swap_insertion (struct bp_location *left
{
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. */
@@ -10336,12 +10738,67 @@ swap_insertion (struct bp_location *left
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;
+ struct program_space *pspace = NULL;
+
+ address = bl->address;
+ pspace = bl->pspace;
+
+ /* 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_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 != loc->pspace)
+ continue;
+
+ /* Flag the location appropriately. We use a different number 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 this functions just to mark locations
+ that have already been marked. */
+ loc->condition_changed = 2;
+
+ /* 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
@@ -10363,6 +10820,10 @@ update_global_location_list (int should_
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 updated. */
+ struct program_space *last_pspace = NULL;
/* Used in the duplicates detection below. When iterating over all
bp_locations, points to the first bp_location of a given address.
@@ -10436,13 +10897,27 @@ update_global_location_list (int should_
&& (*loc2p)->address == old_loc->address);
loc2p++)
{
+ /* 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 == 1
+ && last_addr != old_loc->address)
+ force_breakpoint_reinsertion ((*loc2p));
+
if (*loc2p == old_loc)
- {
- found_object = 1;
- break;
- }
+ 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
@@ -10462,6 +10937,10 @@ update_global_location_list (int should_
}
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
@@ -10629,7 +11108,11 @@ update_global_location_list (int should_
are never duplicated. See the comments in field `duplicate' of
` struct bp_location'. */
|| is_tracepoint (b))
- continue;
+ {
+ /* Clear the condition modification flag. */
+ loc->condition_changed = 0;
+ continue;
+ }
/* Permanent breakpoint should always be inserted. */
if (b->enable_state == bp_permanent && ! loc->inserted)
@@ -10652,6 +11135,13 @@ update_global_location_list (int should_
{
*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 = 0;
+ }
continue;
}
@@ -10662,6 +11152,9 @@ update_global_location_list (int should_
swap_insertion (loc, *loc_first_p);
loc->duplicate = 1;
+ /* Clear the condition modification flag. */
+ loc->condition_changed = 0;
+
if ((*loc_first_p)->owner->enable_state == bp_permanent
&& loc->inserted
&& b->enable_state != bp_permanent)
@@ -10788,6 +11281,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);
}
@@ -11498,10 +11993,11 @@ strace_marker_p (struct breakpoint *b)
}
/* Delete a breakpoint and clean up all traces of it in the data
- structures. */
+ structures. If UPDATE is true, proceed to update the list of
+ locations, otherwise don't update it. */
-void
-delete_breakpoint (struct breakpoint *bpt)
+static void
+delete_breakpoint_1 (struct breakpoint *bpt, int update)
{
struct breakpoint *b;
@@ -11583,8 +12079,12 @@ delete_breakpoint (struct breakpoint *bp
belong to this breakpoint. Do this before freeing the breakpoint
itself, since remove_breakpoint looks at location's owner. It
might be better design to have location completely
- self-contained, but it's not the case now. */
- update_global_location_list (0);
+ self-contained, but it's not the case now.
+
+ If we have conditions being evaluated on the target, we will also
+ synchronize the list of conditions due to a deleted duplicate
+ breakpoint. */
+ update_global_location_list (update);
bpt->ops->dtor (bpt);
/* On the chance that someone will soon try again to delete this
@@ -11593,6 +12093,24 @@ delete_breakpoint (struct breakpoint *bp
xfree (bpt);
}
+/* Delete a breakpoint but don't update the list of locations. */
+
+void
+delete_breakpoint (struct breakpoint *bpt)
+{
+ delete_breakpoint_1 (bpt, 0);
+}
+
+/* Delete a breakpoint and update the list of locations. We use
+ this one to synchronize the list of conditions with the target
+ in case the target is responsible for evaluating them. */
+
+void
+delete_breakpoint_with_update (struct breakpoint *bpt)
+{
+ delete_breakpoint_1 (bpt, 1);
+}
+
static void
do_delete_breakpoint_cleanup (void *b)
{
@@ -11645,7 +12163,10 @@ iterate_over_related_breakpoints (struct
static void
do_delete_breakpoint (struct breakpoint *b, void *ignore)
{
- delete_breakpoint (b);
+ if (is_breakpoint (b))
+ delete_breakpoint_with_update (b);
+ else
+ delete_breakpoint (b);
}
/* A callback for map_breakpoint_numbers that calls
@@ -11684,7 +12205,7 @@ delete_command (char *arg, int from_tty)
{
ALL_BREAKPOINTS_SAFE (b, b_tmp)
if (user_breakpoint_p (b))
- delete_breakpoint (b);
+ do_delete_breakpoint (b, NULL);
}
}
else
@@ -12468,6 +12989,9 @@ disable_breakpoint (struct breakpoint *b
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))
{
@@ -12477,7 +13001,10 @@ disable_breakpoint (struct breakpoint *b
target_disable_tracepoint (location);
}
- update_global_location_list (0);
+ if (is_breakpoint (bpt))
+ update_global_location_list (1);
+ else
+ update_global_location_list (0);
observer_notify_breakpoint_modified (bpt);
}
@@ -12515,13 +13042,20 @@ disable_command (char *args, int from_tt
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))
target_disable_tracepoint (loc);
}
- update_global_location_list (0);
+ if (loc && is_breakpoint (loc->owner))
+ update_global_location_list (1);
+ else
+ update_global_location_list (0);
}
else
map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
@@ -12571,6 +13105,11 @@ enable_breakpoint_disp (struct breakpoin
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))
{
@@ -12629,7 +13168,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))
@@ -14019,8 +14562,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14036,8 +14580,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14055,8 +14600,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14075,8 +14621,9 @@ The \"Type\" column indicates one of:\n\
\tfinish - internal breakpoint used by the \"finish\" command\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14339,6 +14886,23 @@ inferior in all-stop mode, gdb behaves a
&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\
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h 2012-01-27 17:16:36.889821938 -0200
+++ gdb/gdb/breakpoint.h 2012-01-27 17:18:12.785821938 -0200
@@ -22,6 +22,7 @@
#include "frame.h"
#include "value.h"
#include "vec.h"
+#include "ax.h"
struct value;
struct block;
@@ -249,6 +250,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 +320,32 @@ 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.
+
+ This field has 3 special values:
+
+ 0: It means there has been no condition changes.
+
+ 1: It means this location had its condition modified.
+
+ 2: 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. */
+
+ char 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. */
@@ -716,6 +747,10 @@ struct watchpoint
CORE_ADDR hw_wp_mask;
};
+/* Returns true if BPT is a breakpoint of any kind. */
+
+extern int is_breakpoint (const struct breakpoint *bpt);
+
/* Returns true if BPT is really a watchpoint. */
extern int is_watchpoint (const struct breakpoint *bpt);
Index: gdb/gdb/ax.h
===================================================================
--- gdb.orig/gdb/ax.h 2012-01-27 17:16:36.893821938 -0200
+++ gdb/gdb/ax.h 2012-01-27 17:18:12.785821938 -0200
@@ -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
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-01-27 20:34 [rfc target-side break conditions 3/5 v2] GDB-side changes Luis Gustavo
@ 2012-02-06 20:27 ` Tom Tromey
2012-02-07 11:16 ` Luis Gustavo
2012-02-07 19:13 ` Pedro Alves
2012-02-07 22:08 ` Stan Shebs
1 sibling, 2 replies; 16+ messages in thread
From: Tom Tromey @ 2012-02-06 20:27 UTC (permalink / raw)
To: Gustavo, Luis; +Cc: gdb-patches
>>>>> "Luis" == Luis Gustavo <luis_gustavo@mentor.com> writes:
Luis> A few more changes on this patch. It addresses all the previous
Luis> comments and suggestions.
I have a few minor notes, nothing serious.
I think someone other than me should do the final review of this patch.
A couple other things I wanted to mention --
First, I think this is a great patch series and I like it quite a bit.
I want to see it go in.
Second, I was wondering if you have any plans to extend agent
expressions to provide more coverage for DWARF expressions. It would be
somewhat interesting, I think, to get some idea of how often GCC
generates untranslatable expressions for real code. (Like, looking at
all the DWARF expressions in the distro... or at least some big
libraries.)
Luis> +static const char *condition_evaluation_enums[] = {
After Jan's patch I think you will need another const in there.
Luis> +/* Translate a condition evaluation mode MODE into either "gdb"
Luis> + or "target. This is used mostly to translate from "auto" to the
Missing quote after "target".
Luis> + /* Signals that the condition has changed since the last time
Luis> + we updated the global location list. This means the condition
Luis> + needs to be sent to the target again. This is used together
Luis> + with target-side breakpoint conditions.
Luis> +
Luis> + This field has 3 special values:
Luis> +
Luis> + 0: It means there has been no condition changes.
Luis> +
Luis> + 1: It means this location had its condition modified.
Luis> +
Luis> + 2: It means we already marked all the locations that are duplicates
Luis> + of this location and thus we don't need to call
Luis> + force_breakpoint_reinsertion (...) for this location. */
Luis> +
Luis> + char condition_changed;
How about an enum instead of numerical constants?
Tom
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-06 20:27 ` Tom Tromey
@ 2012-02-07 11:16 ` Luis Gustavo
2012-02-08 19:33 ` Pedro Alves
2012-02-09 13:00 ` Pedro Alves
2012-02-07 19:13 ` Pedro Alves
1 sibling, 2 replies; 16+ messages in thread
From: Luis Gustavo @ 2012-02-07 11:16 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1831 bytes --]
On 02/06/2012 06:26 PM, Tom Tromey wrote:
> Second, I was wondering if you have any plans to extend agent
> expressions to provide more coverage for DWARF expressions. It would be
> somewhat interesting, I think, to get some idea of how often GCC
> generates untranslatable expressions for real code. (Like, looking at
> all the DWARF expressions in the distro... or at least some big
> libraries.)
Nothing clearly planned for now, but it should be the natural course to
expand it in order to handle more interesting expressions.
>
> Luis> +static const char *condition_evaluation_enums[] = {
>
> After Jan's patch I think you will need another const in there.
Fixed.
> Luis> +/* Translate a condition evaluation mode MODE into either "gdb"
> Luis> + or "target. This is used mostly to translate from "auto" to the
>
> Missing quote after "target".
Fixed as well.
> Luis> + /* Signals that the condition has changed since the last time
> Luis> + we updated the global location list. This means the condition
> Luis> + needs to be sent to the target again. This is used together
> Luis> + with target-side breakpoint conditions.
> Luis> +
> Luis> + This field has 3 special values:
> Luis> +
> Luis> + 0: It means there has been no condition changes.
> Luis> +
> Luis> + 1: It means this location had its condition modified.
> Luis> +
> Luis> + 2: It means we already marked all the locations that are duplicates
> Luis> + of this location and thus we don't need to call
> Luis> + force_breakpoint_reinsertion (...) for this location. */
> Luis> +
> Luis> + char condition_changed;
>
> How about an enum instead of numerical constants?
That's better. I'm using an enum now and i've updated the other usages
of condition_changed.
Thanks for the input!
Luis
[-- Attachment #2: 0002-break_condition_bytecode.diff --]
[-- Type: text/x-patch, Size: 44035 bytes --]
2012-02-07 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_breakpoint_condition hook.
* target.c (update_current_target): Inherit
to_supports_breakpoint_conditions.
Default to_supports_breakpoint_conditions to return_zero.
* target.h (struct target_ops) <to_supports_breakpoint_conditions>:
New field.
(target_supports_breakpoint_conditions): New #define.
* breakpoint.c (get_first_locp_gte_addr): New forward declaration.
(condition_evaluation_auto,
condition_evaluation_gdb, condition_evaluation_stub,
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.
(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 (...).
(insert_breakpoint_locations): Handle target-side conditional
breakpoints.
(bpstat_check_breakpoint_conditions): Add comment.
(print_breakpoint_location): Print information on where the condition
will be evaluated.
(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.
(bp_location_dtor): Free agent expression bytecode.
(delete_breakpoint): Rename to delete_breakpoint_1, add new update
parameter and make it static.
(delete_breakpoint): New function.
(delete_breakpoint_with_update): New function.
(do_delete_breakpoint): Call delete_breakpoint_with_update (...) for
breakpoints.
(delete_command): Call do_delete_breakpoint (...) instead of
delete_breakpoint (...).
(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.
Index: gdb/gdb/remote.c
===================================================================
--- gdb.orig/gdb/remote.c 2012-02-06 22:57:38.000000000 -0200
+++ gdb/gdb/remote.c 2012-02-06 22:58:04.529895001 -0200
@@ -242,6 +242,8 @@ static int remote_read_description_p (st
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. */
@@ -7720,6 +7722,47 @@ extended_remote_create_inferior (struct
}
\f
+/* 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_length (agent_expr_p, bp_tgt->conditions))
+ {
+ sprintf (buf + strlen (buf), "%s", ",conditions=");
+ }
+ else
+ return 0;
+
+ /* 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 + strlen (buf), "X%x,", aexpr->len);
+ pkt = buf + strlen (buf);
+ for (i = 0; i < aexpr->len; ++i)
+ pkt = pack_hex_byte (pkt, aexpr->buf[i]);
+ *pkt++ = ';';
+ *pkt = '\0';
+ }
+
+ pkt--;
+ *pkt = '\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. */
@@ -7739,6 +7782,7 @@ remote_insert_breakpoint (struct gdbarch
struct remote_state *rs;
char *p;
int bpsize;
+ struct condition_list *cond = NULL;
gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
@@ -7752,6 +7796,9 @@ remote_insert_breakpoint (struct 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);
@@ -7977,6 +8024,9 @@ remote_insert_hw_breakpoint (struct gdba
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);
@@ -10770,6 +10820,7 @@ Specify the serial device it is connecte
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_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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c 2012-02-06 22:54:54.000000000 -0200
+++ gdb/gdb/target.c 2012-02-06 22:58:04.533895001 -0200
@@ -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_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_breakpoint_conditions,
+ (int (*) (void))
+ return_zero);
de_fault (to_execution_direction, default_execution_direction);
#undef de_fault
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h 2012-02-06 22:54:54.000000000 -0200
+++ gdb/gdb/target.h 2012-02-06 22:58:04.533895001 -0200
@@ -662,6 +662,9 @@ struct target_ops
/* Does this target support the tracenz bytecode for string collection? */
int (*to_supports_string_tracing) (void);
+ /* Does this target support evaluation breakpoint conditions on its end? */
+ int (*to_supports_breakpoint_conditions) (void);
+
/* Determine current architecture of thread PTID.
The target is supposed to determine the architecture of the code where
@@ -968,6 +971,12 @@ int target_supports_disable_randomizatio
#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_breakpoint_conditions() \
+ (*current_target.to_supports_breakpoint_conditions) ()
+
/* Invalidate all target dcaches. */
extern void target_dcache_invalidate (void);
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c 2012-02-06 22:57:25.000000000 -0200
+++ gdb/gdb/breakpoint.c 2012-02-07 00:02:02.121895001 -0200
@@ -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"
@@ -255,6 +256,8 @@ static void trace_pass_command (char *,
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. */
@@ -403,6 +406,62 @@ breakpoints_always_inserted_mode (void)
&& !RECORD_IS_USED);
}
+/* Modes for breakpoint condition evaluation. */
+static const char condition_evaluation_auto[] = "auto";
+static const char condition_evaluation_gdb[] = "gdb";
+static const char condition_evaluation_target[] = "target";
+static const char *const condition_evaluation_enums[] = {
+ condition_evaluation_auto,
+ condition_evaluation_gdb,
+ 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 "gdb"
+ 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_breakpoint_conditions ())
+ return condition_evaluation_target;
+ else
+ return condition_evaluation_gdb;
+ }
+ 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_gdb);
+}
+
void _initialize_breakpoint (void);
/* Are we executing breakpoint commands? */
@@ -434,6 +493,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) \
+ if (!BP_LOCP_START) \
+ BP_LOCP_START = get_first_locp_gte_addr (ADDRESS); \
+ for (BP_LOCP_TMP = 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) \
@@ -617,6 +690,146 @@ get_breakpoint (int num)
\f
+/* 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_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_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_breakpoint_conditions ())
+ {
+ condition_evaluation_mode_1 = condition_evaluation_mode;
+ warning (_("Target does not support condition evaluation.\n"
+ "Using GDB 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:
+
+ "gdb" -> "target": Send all (valid) conditions to the target.
+ "target" -> "gdb": 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 to 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);
+}
+
+/* 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. */
+
+static struct bp_location **
+get_first_locp_gte_addr (CORE_ADDR address)
+{
+ struct bp_location **locp = bp_location;
+
+ while (locp < bp_location + bp_location_count
+ && (*locp)->address < address)
+ locp++;
+
+ return locp;
+}
+
void
set_breakpoint_condition (struct breakpoint *b, char *exp,
int from_tty)
@@ -639,6 +852,10 @@ set_breakpoint_condition (struct breakpo
{
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 (...). */
}
}
@@ -681,6 +898,8 @@ set_breakpoint_condition (struct breakpo
}
}
}
+ mark_breakpoint_modified (b);
+
breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
@@ -714,6 +933,10 @@ condition_command (char *arg, int from_t
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;
}
@@ -1213,6 +1436,16 @@ breakpoint_xfer_memory (gdb_byte *readbu
}
\f
+/* Return true if BPT is of any breakpoint kind, hardware or
+ software. */
+
+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
@@ -1655,6 +1888,143 @@ unduplicated_should_be_inserted (struct
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 parse 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_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 == bl->pspace)
+ {
+ 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 == bl->pspace)
+ {
+ /* 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 == bl->pspace
+ && 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.
@@ -1671,7 +2041,7 @@ insert_bp_location (struct bp_location *
{
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. */
@@ -1680,6 +2050,18 @@ insert_bp_location (struct bp_location *
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)
{
@@ -2011,7 +2393,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
@@ -4089,6 +4471,10 @@ bpstat_check_breakpoint_conditions (bpst
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;
@@ -4722,6 +5108,18 @@ print_breakpoint_location (struct breakp
else
ui_out_field_string (uiout, "pending", b->addr_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) && loc && loc->cond_bytecode
+ && (breakpoint_condition_evaluation_mode ()
+ != condition_evaluation_gdb))
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "evaluated-by",
+ breakpoint_condition_evaluation_mode ());
+ ui_out_text (uiout, " evaluates conditions)");
+ }
+
do_cleanups (old_chain);
}
@@ -5709,6 +6107,7 @@ init_bp_location (struct bp_location *lo
loc->ops = ops;
loc->owner = owner;
loc->cond = NULL;
+ loc->cond_bytecode = NULL;
loc->shlib_disabled = 0;
loc->enabled = 1;
@@ -5736,9 +6135,11 @@ init_bp_location (struct bp_location *lo
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:
@@ -10685,6 +11086,7 @@ swap_insertion (struct bp_location *left
{
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. */
@@ -10695,12 +11097,67 @@ swap_insertion (struct bp_location *left
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;
+ struct program_space *pspace = NULL;
+
+ address = bl->address;
+ pspace = bl->pspace;
+
+ /* 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_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 != loc->pspace)
+ continue;
+
+ /* Flag the location appropriately. We use a different number 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 this 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
@@ -10722,6 +11179,10 @@ update_global_location_list (int should_
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 updated. */
+ struct program_space *last_pspace = NULL;
/* Used in the duplicates detection below. When iterating over all
bp_locations, points to the first bp_location of a given address.
@@ -10795,13 +11256,27 @@ update_global_location_list (int should_
&& (*loc2p)->address == old_loc->address);
loc2p++)
{
+ /* 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)
+ force_breakpoint_reinsertion ((*loc2p));
+
if (*loc2p == old_loc)
- {
- found_object = 1;
- break;
- }
+ 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
@@ -10821,6 +11296,10 @@ update_global_location_list (int should_
}
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
@@ -10988,7 +11467,11 @@ update_global_location_list (int should_
are 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)
@@ -11011,6 +11494,13 @@ update_global_location_list (int should_
{
*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;
}
@@ -11021,6 +11511,9 @@ update_global_location_list (int should_
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)
@@ -11147,6 +11640,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);
}
@@ -11870,10 +12365,11 @@ strace_marker_p (struct breakpoint *b)
}
/* Delete a breakpoint and clean up all traces of it in the data
- structures. */
+ structures. If UPDATE is true, proceed to update the list of
+ locations, otherwise don't update it. */
-void
-delete_breakpoint (struct breakpoint *bpt)
+static void
+delete_breakpoint_1 (struct breakpoint *bpt, int update)
{
struct breakpoint *b;
@@ -11955,8 +12451,12 @@ delete_breakpoint (struct breakpoint *bp
belong to this breakpoint. Do this before freeing the breakpoint
itself, since remove_breakpoint looks at location's owner. It
might be better design to have location completely
- self-contained, but it's not the case now. */
- update_global_location_list (0);
+ self-contained, but it's not the case now.
+
+ If we have conditions being evaluated on the target, we will also
+ synchronize the list of conditions due to a deleted duplicate
+ breakpoint. */
+ update_global_location_list (update);
bpt->ops->dtor (bpt);
/* On the chance that someone will soon try again to delete this
@@ -11965,6 +12465,24 @@ delete_breakpoint (struct breakpoint *bp
xfree (bpt);
}
+/* Delete a breakpoint but don't update the list of locations. */
+
+void
+delete_breakpoint (struct breakpoint *bpt)
+{
+ delete_breakpoint_1 (bpt, 0);
+}
+
+/* Delete a breakpoint and update the list of locations. We use
+ this one to synchronize the list of conditions with the target
+ in case the target is responsible for evaluating them. */
+
+void
+delete_breakpoint_with_update (struct breakpoint *bpt)
+{
+ delete_breakpoint_1 (bpt, 1);
+}
+
static void
do_delete_breakpoint_cleanup (void *b)
{
@@ -12017,7 +12535,10 @@ iterate_over_related_breakpoints (struct
static void
do_delete_breakpoint (struct breakpoint *b, void *ignore)
{
- delete_breakpoint (b);
+ if (is_breakpoint (b))
+ delete_breakpoint_with_update (b);
+ else
+ delete_breakpoint (b);
}
/* A callback for map_breakpoint_numbers that calls
@@ -12056,7 +12577,7 @@ delete_command (char *arg, int from_tty)
{
ALL_BREAKPOINTS_SAFE (b, b_tmp)
if (user_breakpoint_p (b))
- delete_breakpoint (b);
+ do_delete_breakpoint (b, NULL);
}
}
else
@@ -12840,6 +13361,9 @@ disable_breakpoint (struct breakpoint *b
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))
{
@@ -12849,7 +13373,10 @@ disable_breakpoint (struct breakpoint *b
target_disable_tracepoint (location);
}
- update_global_location_list (0);
+ if (is_breakpoint (bpt))
+ update_global_location_list (1);
+ else
+ update_global_location_list (0);
observer_notify_breakpoint_modified (bpt);
}
@@ -12887,13 +13414,20 @@ disable_command (char *args, int from_tt
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))
target_disable_tracepoint (loc);
}
- update_global_location_list (0);
+ if (loc && is_breakpoint (loc->owner))
+ update_global_location_list (1);
+ else
+ update_global_location_list (0);
}
else
map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
@@ -12943,6 +13477,11 @@ enable_breakpoint_disp (struct breakpoin
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))
{
@@ -13001,7 +13540,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))
@@ -14405,8 +14948,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14422,8 +14966,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14441,8 +14986,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14461,8 +15007,9 @@ The \"Type\" column indicates one of:\n\
\tfinish - internal breakpoint used by the \"finish\" command\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14739,6 +15286,23 @@ inferior in all-stop mode, gdb behaves a
&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\
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h 2012-02-06 22:57:02.000000000 -0200
+++ gdb/gdb/breakpoint.h 2012-02-07 00:06:40.785895001 -0200
@@ -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. */
@@ -721,6 +760,10 @@ struct watchpoint
CORE_ADDR hw_wp_mask;
};
+/* Returns true if BPT is a breakpoint of any kind. */
+
+extern int is_breakpoint (const struct breakpoint *bpt);
+
/* Returns true if BPT is really a watchpoint. */
extern int is_watchpoint (const struct breakpoint *bpt);
Index: gdb/gdb/ax.h
===================================================================
--- gdb.orig/gdb/ax.h 2012-02-06 22:54:54.000000000 -0200
+++ gdb/gdb/ax.h 2012-02-06 22:58:04.557895001 -0200
@@ -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
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-06 20:27 ` Tom Tromey
2012-02-07 11:16 ` Luis Gustavo
@ 2012-02-07 19:13 ` Pedro Alves
2012-02-07 19:26 ` Stan Shebs
1 sibling, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2012-02-07 19:13 UTC (permalink / raw)
To: Tom Tromey; +Cc: Gustavo, Luis, gdb-patches
On 02/06/2012 08:26 PM, Tom Tromey wrote:
>>>>>> "Luis" == Luis Gustavo <luis_gustavo@mentor.com> writes:
>
> Luis> A few more changes on this patch. It addresses all the previous
> Luis> comments and suggestions.
>
> I have a few minor notes, nothing serious.
> I think someone other than me should do the final review of this patch.
I'll try to get to this, and also Yao's patches, this week.
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-07 19:13 ` Pedro Alves
@ 2012-02-07 19:26 ` Stan Shebs
0 siblings, 0 replies; 16+ messages in thread
From: Stan Shebs @ 2012-02-07 19:26 UTC (permalink / raw)
To: gdb-patches
On 2/7/12 11:12 AM, Pedro Alves wrote:
> On 02/06/2012 08:26 PM, Tom Tromey wrote:
>>>>>>> "Luis" == Luis Gustavo<luis_gustavo@mentor.com> writes:
>> Luis> A few more changes on this patch. It addresses all the previous
>> Luis> comments and suggestions.
>>
>> I have a few minor notes, nothing serious.
>> I think someone other than me should do the final review of this patch.
> I'll try to get to this, and also Yao's patches, this week.
>
I'm actually working through this patch right now.
Stan
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-01-27 20:34 [rfc target-side break conditions 3/5 v2] GDB-side changes Luis Gustavo
2012-02-06 20:27 ` Tom Tromey
@ 2012-02-07 22:08 ` Stan Shebs
2012-02-08 23:13 ` Luis Gustavo
1 sibling, 1 reply; 16+ messages in thread
From: Stan Shebs @ 2012-02-07 22:08 UTC (permalink / raw)
To: gdb-patches
On 1/27/12 12:33 PM, Luis Gustavo wrote:
> A few more changes on this patch. It addresses all the previous
> comments and suggestions.
>
>
> I've changed the "info break" output a little. We now display "<mode>
> evaluates conditions" next to the location description, and we also
> output that same information via MI. Though it works, i'm not entirely
> happy with the way it is displayed.
>
> Previously i displayed such information next to the condition field,
> but it doesn't work right for breakpoints with multiple locations
> since the conditions are printed for the breakpoint instead of the
> locations. Suggestions?
Can it actually happen that some locations of a breakpoint are evaluated
host-side, and other target-side? It makes my head hurt trying to think
of an example. :-)
In any case, the note should follow the condition, and I suggest the
wording "(host evals)" and "(target evals)" if all locations are going
to be handled the same way. If locations are varying, then the
condition follower can say "(host or target evals)" then each location
description can say just "(host)" or "(target)". It's a little messier
to calculate, but users will appreciate the clarity.
(I'm preferring "host" to "gdb", but I suppose that might be confusing
if GDB was talking to a sprite also running on the host and controlling
target via JTAG.)
+/* Mark locations as "conditions have changed" in case
+ the target supports evaluating conditions on
+ its side. */
This is kind of petty, but shouldn't the lines be filled? I think Emacs would make this a two-line comment.
+ warning (_("Target does not support condition evaluation.\n"
+ "Using GDB evaluation mode instead."));
I tend to think this should say "breakpoint condition", so it's clear that it's not referring to tracepoint conditions, or command list conditions, or Python conditions, etc.
+ /* If we got here, it means the condition could not be parse to a valid
be parsed
(Eventually we should be nicer and say *why* the condition didn't make the cut. Users would be happy to replace a convenience var with a literal value if they knew that's all that was wrong.)
- update_global_location_list (0);
+ if (is_breakpoint (bpt))
+ update_global_location_list (1);
+ else
+ update_global_location_list (0);
update_global_location_list (is_breakpoint (bpt))
Stan
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-07 11:16 ` Luis Gustavo
@ 2012-02-08 19:33 ` Pedro Alves
2012-02-08 20:56 ` Luis Gustavo
2012-02-09 13:00 ` Pedro Alves
1 sibling, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2012-02-08 19:33 UTC (permalink / raw)
To: Gustavo, Luis; +Cc: Tom Tromey, gdb-patches
On 02/07/2012 11:15 AM, Luis Gustavo wrote:
> + /* Does this target support evaluation breakpoint conditions on its end? */
> + int (*to_supports_breakpoint_conditions) (void);
s/evaluation/evaluating/ or s/evaluation/evaluation of/ ?
On 02/07/2012 11:15 AM, Luis Gustavo wrote:
> +#define ALL_BP_LOCATIONS_AT_ADDR(BP_LOCP_TMP, BP_LOCP_START, ADDRESS) \
> + if (!BP_LOCP_START) \
> + BP_LOCP_START = get_first_locp_gte_addr (ADDRESS); \
> + for (BP_LOCP_TMP = BP_LOCP_START; \
> + (BP_LOCP_TMP < bp_location + bp_location_count \
> + && (*BP_LOCP_TMP)->address == ADDRESS); \
> + BP_LOCP_TMP++)
> +
This will break if ever someone does
if (foo)
ALL_BP_LOCATIONS_AT_ADDR(...);
You can move the initialization of BP_LOCP_START to the for initializer
instead, like so:
#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) : NULL, \
BP_LOCP_TMP = BP_LOCP_START; \
(BP_LOCP_TMP < bp_location + bp_location_count \
&& (*BP_LOCP_TMP)->address == ADDRESS); \
BP_LOCP_TMP++)
On 02/07/2012 11:15 AM, Luis Gustavo wrote:
> + when we go through update_global_location_list (...). */
Please drop the "()" whenever you refer to a function by name. */
> /* Delete a breakpoint and clean up all traces of it in the data
> - structures. */
> + structures. If UPDATE is true, proceed to update the list of
> + locations, otherwise don't update it. */
>
> -void
> -delete_breakpoint (struct breakpoint *bpt)
> +static void
> +delete_breakpoint_1 (struct breakpoint *bpt, int update)
> {
> struct breakpoint *b;
>
> @@ -11955,8 +12451,12 @@ delete_breakpoint (struct breakpoint *bp
> belong to this breakpoint. Do this before freeing the breakpoint
> itself, since remove_breakpoint looks at location's owner. It
> might be better design to have location completely
> - self-contained, but it's not the case now. */
> - update_global_location_list (0);
> + self-contained, but it's not the case now.
> +
> + If we have conditions being evaluated on the target, we will also
> + synchronize the list of conditions due to a deleted duplicate
> + breakpoint. */
> + update_global_location_list (update);
>
> bpt->ops->dtor (bpt);
> /* On the chance that someone will soon try again to delete this
> @@ -11965,6 +12465,24 @@ delete_breakpoint (struct breakpoint *bp
> xfree (bpt);
> }
>
> +/* Delete a breakpoint but don't update the list of locations. */
> +
> +void
> +delete_breakpoint (struct breakpoint *bpt)
> +{
> + delete_breakpoint_1 (bpt, 0);
> +}
> +
> +/* Delete a breakpoint and update the list of locations. We use
> + this one to synchronize the list of conditions with the target
> + in case the target is responsible for evaluating them. */
> +
> +void
> +delete_breakpoint_with_update (struct breakpoint *bpt)
> +{
> + delete_breakpoint_1 (bpt, 1);
> +}
> +
> static void
> do_delete_breakpoint_cleanup (void *b)
> {
> @@ -12017,7 +12535,10 @@ iterate_over_related_breakpoints (struct
> static void
> do_delete_breakpoint (struct breakpoint *b, void *ignore)
> {
> - delete_breakpoint (b);
> + if (is_breakpoint (b))
> + delete_breakpoint_with_update (b);
> + else
> + delete_breakpoint (b);
> }
>
> /* A callback for map_breakpoint_numbers that calls
> @@ -12056,7 +12577,7 @@ delete_command (char *arg, int from_tty)
> {
> ALL_BREAKPOINTS_SAFE (b, b_tmp)
> if (user_breakpoint_p (b))
> - delete_breakpoint (b);
> + do_delete_breakpoint (b, NULL);
> }
> }
> else
> @@ -12840,6 +13361,9 @@ disable_breakpoint (struct breakpoint *b
>
> 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))
> {
> @@ -12849,7 +13373,10 @@ disable_breakpoint (struct breakpoint *b
> target_disable_tracepoint (location);
> }
>
> - update_global_location_list (0);
> + if (is_breakpoint (bpt))
> + update_global_location_list (1);
> + else
> + update_global_location_list (0);
I'm confused. How does this (and all similar places) address the issued I
pointed out before? If you're passing one to update_global_location_list
when deleting a breakpoint, you're pretty much defeating the whole
purpose of the update_global_location_list's argument in the first place.
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-08 19:33 ` Pedro Alves
@ 2012-02-08 20:56 ` Luis Gustavo
2012-02-09 12:56 ` Pedro Alves
0 siblings, 1 reply; 16+ messages in thread
From: Luis Gustavo @ 2012-02-08 20:56 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
Fixed all the other comments...
On 02/08/2012 05:33 PM, Pedro Alves wrote:
>> /* Delete a breakpoint and clean up all traces of it in the data
>> - structures. */
>> + structures. If UPDATE is true, proceed to update the list of
>> + locations, otherwise don't update it. */
>>
>> -void
>> -delete_breakpoint (struct breakpoint *bpt)
>> +static void
>> +delete_breakpoint_1 (struct breakpoint *bpt, int update)
>> {
>> struct breakpoint *b;
>>
>> @@ -11955,8 +12451,12 @@ delete_breakpoint (struct breakpoint *bp
>> belong to this breakpoint. Do this before freeing the breakpoint
>> itself, since remove_breakpoint looks at location's owner. It
>> might be better design to have location completely
>> - self-contained, but it's not the case now. */
>> - update_global_location_list (0);
>> + self-contained, but it's not the case now.
>> +
>> + If we have conditions being evaluated on the target, we will also
>> + synchronize the list of conditions due to a deleted duplicate
>> + breakpoint. */
>> + update_global_location_list (update);
>>
>> bpt->ops->dtor (bpt);
>> /* On the chance that someone will soon try again to delete this
>> @@ -11965,6 +12465,24 @@ delete_breakpoint (struct breakpoint *bp
>> xfree (bpt);
>> }
>>
>> +/* Delete a breakpoint but don't update the list of locations. */
>> +
>> +void
>> +delete_breakpoint (struct breakpoint *bpt)
>> +{
>> + delete_breakpoint_1 (bpt, 0);
>> +}
>> +
>> +/* Delete a breakpoint and update the list of locations. We use
>> + this one to synchronize the list of conditions with the target
>> + in case the target is responsible for evaluating them. */
>> +
>> +void
>> +delete_breakpoint_with_update (struct breakpoint *bpt)
>> +{
>> + delete_breakpoint_1 (bpt, 1);
>> +}
>> +
>> static void
>> do_delete_breakpoint_cleanup (void *b)
>> {
>> @@ -12017,7 +12535,10 @@ iterate_over_related_breakpoints (struct
>> static void
>> do_delete_breakpoint (struct breakpoint *b, void *ignore)
>> {
>> - delete_breakpoint (b);
>> + if (is_breakpoint (b))
>> + delete_breakpoint_with_update (b);
>> + else
>> + delete_breakpoint (b);
>> }
>>
>> /* A callback for map_breakpoint_numbers that calls
>> @@ -12056,7 +12577,7 @@ delete_command (char *arg, int from_tty)
>> {
>> ALL_BREAKPOINTS_SAFE (b, b_tmp)
>> if (user_breakpoint_p (b))
>> - delete_breakpoint (b);
>> + do_delete_breakpoint (b, NULL);
>> }
>> }
>> else
>> @@ -12840,6 +13361,9 @@ disable_breakpoint (struct breakpoint *b
>>
>> 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))
>> {
>> @@ -12849,7 +13373,10 @@ disable_breakpoint (struct breakpoint *b
>> target_disable_tracepoint (location);
>> }
>>
>> - update_global_location_list (0);
>> + if (is_breakpoint (bpt))
>> + update_global_location_list (1);
>> + else
>> + update_global_location_list (0);
>
> I'm confused. How does this (and all similar places) address the issued I
> pointed out before? If you're passing one to update_global_location_list
> when deleting a breakpoint, you're pretty much defeating the whole
> purpose of the update_global_location_list's argument in the first place.
>
Updates will only take place when the user explicitly removes/disables a
breakpoint. Functions that are deleting breakpoints (like
remove_thread_event_breakpoints) won't cause insertion of any
breakpoints since they go through the "delete_breakpoint" path, not the
delete_breakpoint_with_update one.
Is disabling breakpoints also something we would like to do without
triggering insertions? If so, i'm inclined to go with the same solution
as for deleting user breakpoints.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-07 22:08 ` Stan Shebs
@ 2012-02-08 23:13 ` Luis Gustavo
0 siblings, 0 replies; 16+ messages in thread
From: Luis Gustavo @ 2012-02-08 23:13 UTC (permalink / raw)
To: Stan Shebs; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 3262 bytes --]
On 02/07/2012 08:08 PM, Stan Shebs wrote:
> On 1/27/12 12:33 PM, Luis Gustavo wrote:
>> A few more changes on this patch. It addresses all the previous
>> comments and suggestions.
>>
>>
>> I've changed the "info break" output a little. We now display "<mode>
>> evaluates conditions" next to the location description, and we also
>> output that same information via MI. Though it works, i'm not entirely
>> happy with the way it is displayed.
>>
>> Previously i displayed such information next to the condition field,
>> but it doesn't work right for breakpoints with multiple locations
>> since the conditions are printed for the breakpoint instead of the
>> locations. Suggestions?
>
> Can it actually happen that some locations of a breakpoint are evaluated
> host-side, and other target-side? It makes my head hurt trying to think
> of an example. :-)
>
Yes and no. It can happen when, for example, you have two inferiors with
the same function, like "main". Inserting a breakpoint in "main" will
create a breakpoint with two locations (one for each inferior).
Suppose we start one them, but not the other. If we have a condition,
the condition from the location of the inferior that has been started
can be evaluated on the target, whereas the one from the inferior that
did not start can't. It's more of a corner case.
> In any case, the note should follow the condition, and I suggest the
> wording "(host evals)" and "(target evals)" if all locations are going
> to be handled the same way. If locations are varying, then the condition
> follower can say "(host or target evals)" then each location description
> can say just "(host)" or "(target)". It's a little messier to calculate,
> but users will appreciate the clarity.
>
> (I'm preferring "host" to "gdb", but I suppose that might be confusing
> if GDB was talking to a sprite also running on the host and controlling
> target via JTAG.)
I switched to using "host" and "target" now. And i did the change to the
output of "info break".
>
> +/* Mark locations as "conditions have changed" in case
> + the target supports evaluating conditions on
> + its side. */
>
>
> This is kind of petty, but shouldn't the lines be filled? I think Emacs
> would make this a two-line comment.
Fixed.
>
>
> + warning (_("Target does not support condition evaluation.\n"
> + "Using GDB evaluation mode instead."));
>
>
> I tend to think this should say "breakpoint condition", so it's clear
> that it's not referring to tracepoint conditions, or command list
> conditions, or Python conditions, etc.
Fixed.
>
> + /* If we got here, it means the condition could not be parse to a valid
>
>
> be parsed
Fixed.
>
> (Eventually we should be nicer and say *why* the condition didn't make
> the cut. Users would be happy to replace a convenience var with a
> literal value if they knew that's all that was wrong.)
I'll handle this in a different patch as it involves translating cryptic
internal error messages to something the users can actually read and
undestand.
>
> - update_global_location_list (0);
> + if (is_breakpoint (bpt))
> + update_global_location_list (1);
> + else
> + update_global_location_list (0);
>
>
> update_global_location_list (is_breakpoint (bpt))
Fixed. Thanks.
Luis
[-- Attachment #2: 0002-break_condition_bytecode.diff --]
[-- Type: text/x-patch, Size: 46652 bytes --]
2012-02-08 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.
(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 (...).
(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.
(bp_location_dtor): Free agent expression bytecode.
(delete_breakpoint): Rename to delete_breakpoint_1, add new update
parameter and make it static.
(delete_breakpoint): New function.
(delete_breakpoint_with_update): New function.
(do_delete_breakpoint): Call delete_breakpoint_with_update (...) for
breakpoints.
(delete_command): Call do_delete_breakpoint (...) instead of
delete_breakpoint (...).
(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.
Index: gdb/gdb/remote.c
===================================================================
--- gdb.orig/gdb/remote.c 2012-02-08 19:30:19.171075001 -0200
+++ gdb/gdb/remote.c 2012-02-08 19:30:19.711075000 -0200
@@ -242,6 +242,8 @@ static int remote_read_description_p (st
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. */
@@ -7720,6 +7722,43 @@ extended_remote_create_inferior (struct
}
\f
+/* 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_length (agent_expr_p, bp_tgt->conditions))
+ {
+ sprintf (buf + strlen (buf), "%s", ";conditions=");
+ }
+ else
+ return 0;
+
+ /* 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 + strlen (buf), "X%x,", aexpr->len);
+ pkt = buf + strlen (buf);
+ for (i = 0; i < aexpr->len; ++i)
+ pkt = pack_hex_byte (pkt, aexpr->buf[i]);
+ *pkt = '\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. */
@@ -7739,6 +7778,7 @@ remote_insert_breakpoint (struct gdbarch
struct remote_state *rs;
char *p;
int bpsize;
+ struct condition_list *cond = NULL;
gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
@@ -7752,6 +7792,9 @@ remote_insert_breakpoint (struct 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);
@@ -7977,6 +8020,9 @@ remote_insert_hw_breakpoint (struct gdba
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);
@@ -10770,6 +10816,7 @@ Specify the serial device it is connecte
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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c 2012-02-08 19:29:41.651075000 -0200
+++ gdb/gdb/target.c 2012-02-08 19:30:19.715075000 -0200
@@ -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
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h 2012-02-08 19:29:41.611074999 -0200
+++ gdb/gdb/target.h 2012-02-08 19:30:19.715075000 -0200
@@ -662,6 +662,9 @@ struct target_ops
/* Does this target support the tracenz bytecode for string collection? */
int (*to_supports_string_tracing) (void);
+ /* Does this target support evaluation 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 +971,12 @@ int target_supports_disable_randomizatio
#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);
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c 2012-02-08 19:30:17.043075000 -0200
+++ gdb/gdb/breakpoint.c 2012-02-08 19:40:27.755075001 -0200
@@ -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"
@@ -255,6 +256,8 @@ static void trace_pass_command (char *,
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. */
@@ -403,6 +406,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 "gdb"
+ 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? */
@@ -434,6 +495,19 @@ 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_TMP < bp_location + bp_location_count \
+ && (*BP_LOCP_TMP)->address == ADDRESS); \
+ BP_LOCP_TMP++)
+
/* Iterator for tracepoints only. */
#define ALL_TRACEPOINTS(B) \
@@ -617,6 +691,144 @@ get_breakpoint (int num)
\f
+/* 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 GDB 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:
+
+ "gdb" -> "target": Send all (valid) conditions to the target.
+ "target" -> "gdb": 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 to 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);
+}
+
+/* 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. */
+
+static struct bp_location **
+get_first_locp_gte_addr (CORE_ADDR address)
+{
+ struct bp_location **locp = bp_location;
+
+ while (locp < bp_location + bp_location_count
+ && (*locp)->address < address)
+ locp++;
+
+ return locp;
+}
+
void
set_breakpoint_condition (struct breakpoint *b, char *exp,
int from_tty)
@@ -639,6 +851,10 @@ set_breakpoint_condition (struct breakpo
{
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. */
}
}
@@ -681,6 +897,8 @@ set_breakpoint_condition (struct breakpo
}
}
}
+ mark_breakpoint_modified (b);
+
breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
@@ -714,6 +932,10 @@ condition_command (char *arg, int from_t
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;
}
@@ -1213,6 +1435,16 @@ breakpoint_xfer_memory (gdb_byte *readbu
}
\f
+/* Return true if BPT is of any breakpoint kind, hardware or
+ software. */
+
+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
@@ -1655,6 +1887,143 @@ unduplicated_should_be_inserted (struct
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 == bl->pspace)
+ {
+ 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 == bl->pspace)
+ {
+ /* 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 == bl->pspace
+ && 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.
@@ -1671,7 +2040,7 @@ insert_bp_location (struct bp_location *
{
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. */
@@ -1680,6 +2049,18 @@ insert_bp_location (struct bp_location *
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)
{
@@ -2011,7 +2392,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
@@ -4089,6 +4470,10 @@ bpstat_check_breakpoint_conditions (bpst
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;
@@ -4664,6 +5049,66 @@ wrap_indent_at_field (struct ui_out *uio
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
@@ -4722,6 +5167,16 @@ print_breakpoint_location (struct breakp
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);
}
@@ -4997,6 +5452,18 @@ print_one_breakpoint_location (struct br
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");
}
@@ -5709,6 +6176,7 @@ init_bp_location (struct bp_location *lo
loc->ops = ops;
loc->owner = owner;
loc->cond = NULL;
+ loc->cond_bytecode = NULL;
loc->shlib_disabled = 0;
loc->enabled = 1;
@@ -5736,9 +6204,11 @@ init_bp_location (struct bp_location *lo
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:
@@ -10693,6 +11163,7 @@ swap_insertion (struct bp_location *left
{
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. */
@@ -10703,12 +11174,67 @@ swap_insertion (struct bp_location *left
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;
+ struct program_space *pspace = NULL;
+
+ address = bl->address;
+ pspace = bl->pspace;
+
+ /* 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 != loc->pspace)
+ continue;
+
+ /* Flag the location appropriately. We use a different number 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 this 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
@@ -10730,6 +11256,10 @@ update_global_location_list (int should_
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 updated. */
+ struct program_space *last_pspace = NULL;
/* Used in the duplicates detection below. When iterating over all
bp_locations, points to the first bp_location of a given address.
@@ -10802,13 +11332,27 @@ update_global_location_list (int should_
&& (*loc2p)->address == old_loc->address);
loc2p++)
{
+ /* 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)
+ force_breakpoint_reinsertion ((*loc2p));
+
if (*loc2p == old_loc)
- {
- found_object = 1;
- break;
- }
+ 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
@@ -10828,6 +11372,10 @@ update_global_location_list (int should_
}
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
@@ -10980,7 +11528,11 @@ update_global_location_list (int should_
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)
@@ -11003,6 +11555,13 @@ update_global_location_list (int should_
{
*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;
}
@@ -11014,6 +11573,9 @@ update_global_location_list (int should_
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__,
@@ -11138,6 +11700,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);
}
@@ -11861,10 +12425,11 @@ strace_marker_p (struct breakpoint *b)
}
/* Delete a breakpoint and clean up all traces of it in the data
- structures. */
+ structures. If UPDATE is true, proceed to update the list of
+ locations, otherwise don't update it. */
-void
-delete_breakpoint (struct breakpoint *bpt)
+static void
+delete_breakpoint_1 (struct breakpoint *bpt, int update)
{
struct breakpoint *b;
@@ -11946,8 +12511,12 @@ delete_breakpoint (struct breakpoint *bp
belong to this breakpoint. Do this before freeing the breakpoint
itself, since remove_breakpoint looks at location's owner. It
might be better design to have location completely
- self-contained, but it's not the case now. */
- update_global_location_list (0);
+ self-contained, but it's not the case now.
+
+ If we have conditions being evaluated on the target, we will also
+ synchronize the list of conditions due to a deleted duplicate
+ breakpoint. */
+ update_global_location_list (update);
bpt->ops->dtor (bpt);
/* On the chance that someone will soon try again to delete this
@@ -11956,6 +12525,24 @@ delete_breakpoint (struct breakpoint *bp
xfree (bpt);
}
+/* Delete a breakpoint but don't update the list of locations. */
+
+void
+delete_breakpoint (struct breakpoint *bpt)
+{
+ delete_breakpoint_1 (bpt, 0);
+}
+
+/* Delete a breakpoint and update the list of locations. We use
+ this one to synchronize the list of conditions with the target
+ in case the target is responsible for evaluating them. */
+
+void
+delete_breakpoint_with_update (struct breakpoint *bpt)
+{
+ delete_breakpoint_1 (bpt, 1);
+}
+
static void
do_delete_breakpoint_cleanup (void *b)
{
@@ -12008,7 +12595,10 @@ iterate_over_related_breakpoints (struct
static void
do_delete_breakpoint (struct breakpoint *b, void *ignore)
{
- delete_breakpoint (b);
+ if (is_breakpoint (b))
+ delete_breakpoint_with_update (b);
+ else
+ delete_breakpoint (b);
}
/* A callback for map_breakpoint_numbers that calls
@@ -12047,7 +12637,7 @@ delete_command (char *arg, int from_tty)
{
ALL_BREAKPOINTS_SAFE (b, b_tmp)
if (user_breakpoint_p (b))
- delete_breakpoint (b);
+ do_delete_breakpoint (b, NULL);
}
}
else
@@ -12831,6 +13421,9 @@ disable_breakpoint (struct breakpoint *b
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))
{
@@ -12840,7 +13433,7 @@ disable_breakpoint (struct breakpoint *b
target_disable_tracepoint (location);
}
- update_global_location_list (0);
+ update_global_location_list (is_breakpoint (bpt));
observer_notify_breakpoint_modified (bpt);
}
@@ -12878,13 +13471,20 @@ disable_command (char *args, int from_tt
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))
target_disable_tracepoint (loc);
}
- update_global_location_list (0);
+ if (loc && is_breakpoint (loc->owner))
+ update_global_location_list (1);
+ else
+ update_global_location_list (0);
}
else
map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
@@ -12934,6 +13534,11 @@ enable_breakpoint_disp (struct breakpoin
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))
{
@@ -12992,7 +13597,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))
@@ -14396,8 +15005,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14413,8 +15023,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14432,8 +15043,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14452,8 +15064,9 @@ The \"Type\" column indicates one of:\n\
\tfinish - internal breakpoint used by the \"finish\" command\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14730,6 +15343,23 @@ inferior in all-stop mode, gdb behaves a
&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\
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h 2012-02-08 19:29:41.615075002 -0200
+++ gdb/gdb/breakpoint.h 2012-02-08 19:30:19.731075000 -0200
@@ -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. */
@@ -721,6 +760,10 @@ struct watchpoint
CORE_ADDR hw_wp_mask;
};
+/* Returns true if BPT is a breakpoint of any kind. */
+
+extern int is_breakpoint (const struct breakpoint *bpt);
+
/* Returns true if BPT is really a watchpoint. */
extern int is_watchpoint (const struct breakpoint *bpt);
Index: gdb/gdb/ax.h
===================================================================
--- gdb.orig/gdb/ax.h 2012-02-08 19:29:41.623075001 -0200
+++ gdb/gdb/ax.h 2012-02-08 19:30:19.731075000 -0200
@@ -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
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-08 20:56 ` Luis Gustavo
@ 2012-02-09 12:56 ` Pedro Alves
2012-02-22 15:29 ` Luis Gustavo
0 siblings, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2012-02-09 12:56 UTC (permalink / raw)
To: Gustavo, Luis; +Cc: Tom Tromey, gdb-patches
On 02/08/2012 08:56 PM, Luis Gustavo wrote:
>> I'm confused. How does this (and all similar places) address the issued I
>> pointed out before? If you're passing one to update_global_location_list
>> when deleting a breakpoint, you're pretty much defeating the whole
>> purpose of the update_global_location_list's argument in the first place.
>>
>
> Updates will only take place when the user explicitly removes/disables a breakpoint. Functions that are deleting breakpoints (like remove_thread_event_breakpoints) won't cause insertion of any breakpoints since they go through the "delete_breakpoint" path, not the delete_breakpoint_with_update one.
Ah, got it now. Thanks. But please:
> + structures. If UPDATE is true, proceed to update the list of
> + locations, otherwise don't update it. */
>
> -void
> -delete_breakpoint (struct breakpoint *bpt)
> +static void
> +delete_breakpoint_1 (struct breakpoint *bpt, int update)
"update" here is quite confusing, because that's not what is happening. Or at
least, update is so overloaded that I'm not understanding it the way you are.
The list of locations is still updated/regenerated, and we do delete locations
from the target, but, we don't allow new insertions. So, could we
s/update/somethingelse/ please? Even pointing at update_global_location_list's
description of its parameter would be good.
Or maybe, I just had an idea --- I wonder if we made update_global_location_list
still re-insert _only_ the _already inserted_ locations when the
condition changes, then we'd be good. That is, something like:
update_global_location_list:
...
- if (breakpoints_always_inserted_mode () && should_insert
- && (have_live_inferiors ()
- || (gdbarch_has_global_breakpoints (target_gdbarch))))
- insert_breakpoint_locations ();
+ if (breakpoints_always_inserted_mode ()
+ && (have_live_inferiors ()
+ || (gdbarch_has_global_breakpoints (target_gdbarch))))
+ {
+ if (should_insert)
+ insert_breakpoint_locations ();
+ else
+ update_inserted_breakpoint_locations ();
+ }
The problem is that a delete_breakpoint would trigger insertions of all
_other_ breakpoints. But if we're allow "reinserting" breakpoints that
are _already_ inserted, I think we're fine.
> Is disabling breakpoints also something we would like to do without triggering insertions? If so, i'm inclined to go with the same solution as for deleting user breakpoints.
Maybe, not sure. Better be safe, I think.
It'd be nice to come up with a better way to solve the initial problem that
led to update_global_location_list having an argument in the first place. :-/
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-07 11:16 ` Luis Gustavo
2012-02-08 19:33 ` Pedro Alves
@ 2012-02-09 13:00 ` Pedro Alves
1 sibling, 0 replies; 16+ messages in thread
From: Pedro Alves @ 2012-02-09 13:00 UTC (permalink / raw)
To: Gustavo, Luis; +Cc: Tom Tromey, gdb-patches
BTW,
On 02/07/2012 11:15 AM, Luis Gustavo wrote:
> +/* Returns true if BPT is a breakpoint of any kind. */
This is ambiguous, because "breakpoint" can mean all kinds of breakpoints,
watchpoints, tracepoints, whateverpoints.
Witness:
/* This is for all kinds of breakpoints. */
struct breakpoint
{
Best be a bit more explicit.
> +
> +extern int is_breakpoint (const struct breakpoint *bpt);
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-09 12:56 ` Pedro Alves
@ 2012-02-22 15:29 ` Luis Gustavo
2012-02-23 17:38 ` Pedro Alves
0 siblings, 1 reply; 16+ messages in thread
From: Luis Gustavo @ 2012-02-22 15:29 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 3253 bytes --]
On 02/09/2012 10:56 AM, Pedro Alves wrote:
> On 02/08/2012 08:56 PM, Luis Gustavo wrote:
>
>>> I'm confused. How does this (and all similar places) address the issued I
>>> pointed out before? If you're passing one to update_global_location_list
>>> when deleting a breakpoint, you're pretty much defeating the whole
>>> purpose of the update_global_location_list's argument in the first place.
>>>
>>
>> Updates will only take place when the user explicitly removes/disables a breakpoint. Functions that are deleting breakpoints (like remove_thread_event_breakpoints) won't cause insertion of any breakpoints since they go through the "delete_breakpoint" path, not the delete_breakpoint_with_update one.
>
> Ah, got it now. Thanks. But please:
>
>> + structures. If UPDATE is true, proceed to update the list of
>> + locations, otherwise don't update it. */
>>
>> -void
>> -delete_breakpoint (struct breakpoint *bpt)
>> +static void
>> +delete_breakpoint_1 (struct breakpoint *bpt, int update)
>
> "update" here is quite confusing, because that's not what is happening. Or at
> least, update is so overloaded that I'm not understanding it the way you are.
> The list of locations is still updated/regenerated, and we do delete locations
> from the target, but, we don't allow new insertions. So, could we
> s/update/somethingelse/ please? Even pointing at update_global_location_list's
> description of its parameter would be good.
>
> Or maybe, I just had an idea --- I wonder if we made update_global_location_list
> still re-insert _only_ the _already inserted_ locations when the
> condition changes, then we'd be good. That is, something like:
>
> update_global_location_list:
> ...
> - if (breakpoints_always_inserted_mode ()&& should_insert
> -&& (have_live_inferiors ()
> - || (gdbarch_has_global_breakpoints (target_gdbarch))))
> - insert_breakpoint_locations ();
> + if (breakpoints_always_inserted_mode ()
> +&& (have_live_inferiors ()
> + || (gdbarch_has_global_breakpoints (target_gdbarch))))
> + {
> + if (should_insert)
> + insert_breakpoint_locations ();
> + else
> + update_inserted_breakpoint_locations ();
> + }
>
> The problem is that a delete_breakpoint would trigger insertions of all
> _other_ breakpoints. But if we're allow "reinserting" breakpoints that
> are _already_ inserted, I think we're fine.
I implemented this change. update_inserted_breakpoint_locations is a
simpler version of insert_breakpoint_locations. Its purpose is to synch
conditions of already-inserted breakpoint locations with the target.
>
>> Is disabling breakpoints also something we would like to do without triggering insertions? If so, i'm inclined to go with the same solution as for deleting user breakpoints.
>
> Maybe, not sure. Better be safe, I think.
>
> It'd be nice to come up with a better way to solve the initial problem that
> led to update_global_location_list having an argument in the first place. :-/
I've confirmed this works with both delete and disable. Looks like a
good solution for now.
The breakpoint infrastructure could use a little cleaning and
refactoring i suppose. :-(
Also, i changed remote.c to not pass the "conditions" marker anymore.
Luis
[-- Attachment #2: 0002-break_condition_bytecode.diff --]
[-- Type: text/x-patch, Size: 46371 bytes --]
2012-02-22 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.
(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.
Index: gdb/gdb/remote.c
===================================================================
--- gdb.orig/gdb/remote.c 2012-02-22 13:22:16.930553985 -0200
+++ gdb/gdb/remote.c 2012-02-22 13:22:49.174553987 -0200
@@ -242,6 +242,8 @@ static int remote_read_description_p (st
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
}
\f
+/* 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_length (agent_expr_p, bp_tgt->conditions))
+ {
+ sprintf (buf + strlen (buf), "%s", ";");
+ }
+ else
+ return 0;
+
+ /* 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 + strlen (buf), "X%x,", aexpr->len);
+ pkt = buf + strlen (buf);
+ for (i = 0; i < aexpr->len; ++i)
+ pkt = pack_hex_byte (pkt, aexpr->buf[i]);
+ *pkt = '\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
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
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 gdba
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 connecte
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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c 2012-02-22 13:22:16.946553985 -0200
+++ gdb/gdb/target.c 2012-02-22 13:22:49.174553987 -0200
@@ -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
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h 2012-02-22 13:22:16.894553984 -0200
+++ gdb/gdb/target.h 2012-02-22 13:22:49.178553986 -0200
@@ -662,6 +662,9 @@ struct target_ops
/* Does this target support the tracenz bytecode for string collection? */
int (*to_supports_string_tracing) (void);
+ /* Does this target support evaluation 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 +971,12 @@ int target_supports_disable_randomizatio
#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);
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c 2012-02-22 13:22:16.882553985 -0200
+++ gdb/gdb/breakpoint.c 2012-02-22 13:22:58.038553985 -0200
@@ -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 *,
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 "gdb"
+ 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,19 @@ 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_TMP < bp_location + bp_location_count \
+ && (*BP_LOCP_TMP)->address == ADDRESS); \
+ BP_LOCP_TMP++)
+
/* Iterator for tracepoints only. */
#define ALL_TRACEPOINTS(B) \
@@ -620,6 +694,144 @@ get_breakpoint (int num)
\f
+/* 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 GDB 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:
+
+ "gdb" -> "target": Send all (valid) conditions to the target.
+ "target" -> "gdb": 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 to 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);
+}
+
+/* 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. */
+
+static struct bp_location **
+get_first_locp_gte_addr (CORE_ADDR address)
+{
+ struct bp_location **locp = bp_location;
+
+ while (locp < bp_location + bp_location_count
+ && (*locp)->address < address)
+ locp++;
+
+ return locp;
+}
+
void
set_breakpoint_condition (struct breakpoint *b, char *exp,
int from_tty)
@@ -642,6 +854,10 @@ set_breakpoint_condition (struct breakpo
{
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 +900,8 @@ set_breakpoint_condition (struct breakpo
}
}
}
+ mark_breakpoint_modified (b);
+
breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
@@ -717,6 +935,10 @@ condition_command (char *arg, int from_t
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 +1438,15 @@ breakpoint_xfer_memory (gdb_byte *readbu
}
\f
+/* 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 +1889,143 @@ unduplicated_should_be_inserted (struct
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 == bl->pspace)
+ {
+ 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 == bl->pspace)
+ {
+ /* 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 == bl->pspace
+ && 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 +2042,7 @@ insert_bp_location (struct bp_location *
{
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 +2051,18 @@ insert_bp_location (struct bp_location *
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 +2371,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 +2454,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 +4532,10 @@ bpstat_check_breakpoint_conditions (bpst
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 +5113,66 @@ wrap_indent_at_field (struct ui_out *uio
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 +5231,16 @@ print_breakpoint_location (struct breakp
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 +5516,18 @@ print_one_breakpoint_location (struct br
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 +6257,7 @@ init_bp_location (struct bp_location *lo
loc->ops = ops;
loc->owner = owner;
loc->cond = NULL;
+ loc->cond_bytecode = NULL;
loc->shlib_disabled = 0;
loc->enabled = 1;
@@ -5758,9 +6285,11 @@ init_bp_location (struct bp_location *lo
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:
@@ -10717,6 +11246,7 @@ swap_insertion (struct bp_location *left
{
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. */
@@ -10727,12 +11257,67 @@ swap_insertion (struct bp_location *left
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;
+ struct program_space *pspace = NULL;
+
+ address = bl->address;
+ pspace = bl->pspace;
+
+ /* 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 != loc->pspace)
+ continue;
+
+ /* Flag the location appropriately. We use a different number 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 this 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
@@ -10754,6 +11339,10 @@ update_global_location_list (int should_
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 updated. */
+ struct program_space *last_pspace = NULL;
/* Used in the duplicates detection below. When iterating over all
bp_locations, points to the first bp_location of a given address.
@@ -10826,13 +11415,27 @@ update_global_location_list (int should_
&& (*loc2p)->address == old_loc->address);
loc2p++)
{
+ /* 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)
+ force_breakpoint_reinsertion ((*loc2p));
+
if (*loc2p == old_loc)
- {
- found_object = 1;
- break;
- }
+ 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
@@ -10852,6 +11455,10 @@ update_global_location_list (int should_
}
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
@@ -11004,7 +11611,11 @@ update_global_location_list (int should_
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)
@@ -11027,6 +11638,13 @@ update_global_location_list (int should_
{
*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;
}
@@ -11038,6 +11656,9 @@ update_global_location_list (int should_
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__,
@@ -11045,10 +11666,21 @@ update_global_location_list (int should_
"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 ();
@@ -11162,6 +11794,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);
}
@@ -12855,6 +13489,9 @@ disable_breakpoint (struct breakpoint *b
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))
{
@@ -12902,7 +13539,11 @@ disable_command (char *args, int from_tt
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))
@@ -12959,6 +13600,11 @@ enable_breakpoint_disp (struct breakpoin
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))
{
@@ -13018,7 +13664,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))
@@ -14459,8 +15109,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14476,8 +15127,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14495,8 +15147,9 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14515,8 +15168,9 @@ The \"Type\" column indicates one of:\n\
\tfinish - internal breakpoint used by the \"finish\" command\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively. The \"Cond Eval\" column\n\
+indicates where the breakpoint condition will be evaluated.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14793,6 +15447,23 @@ inferior in all-stop mode, gdb behaves a
&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\
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h 2012-02-22 13:22:16.906553986 -0200
+++ gdb/gdb/breakpoint.h 2012-02-22 13:22:49.190553987 -0200
@@ -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,10 @@ struct watchpoint
CORE_ADDR hw_wp_mask;
};
+/* Returns true if BPT is a breakpoint of any kind. */
+
+extern int is_breakpoint (const struct breakpoint *bpt);
+
/* Returns true if BPT is really a watchpoint. */
extern int is_watchpoint (const struct breakpoint *bpt);
Index: gdb/gdb/ax.h
===================================================================
--- gdb.orig/gdb/ax.h 2012-02-22 13:22:16.918553987 -0200
+++ gdb/gdb/ax.h 2012-02-22 13:22:49.194553986 -0200
@@ -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
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-22 15:29 ` Luis Gustavo
@ 2012-02-23 17:38 ` Pedro Alves
2012-02-24 12:20 ` Luis Gustavo
0 siblings, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2012-02-23 17:38 UTC (permalink / raw)
To: Gustavo, Luis; +Cc: Tom Tromey, gdb-patches
On 02/22/2012 03:24 PM, Luis Gustavo wrote:
> On 02/09/2012 10:56 AM, Pedro Alves wrote:
>> On 02/08/2012 08:56 PM, Luis Gustavo wrote:
>>
>>>> I'm confused. How does this (and all similar places) address the issued I
>>>> pointed out before? If you're passing one to update_global_location_list
>>>> when deleting a breakpoint, you're pretty much defeating the whole
>>>> purpose of the update_global_location_list's argument in the first place.
>>>>
>>>
>>> Updates will only take place when the user explicitly removes/disables a breakpoint. Functions that are deleting breakpoints (like remove_thread_event_breakpoints) won't cause insertion of any breakpoints since they go through the "delete_breakpoint" path, not the delete_breakpoint_with_update one.
>>
>> Ah, got it now. Thanks. But please:
>>
>>> + structures. If UPDATE is true, proceed to update the list of
>>> + locations, otherwise don't update it. */
>>>
>>> -void
>>> -delete_breakpoint (struct breakpoint *bpt)
>>> +static void
>>> +delete_breakpoint_1 (struct breakpoint *bpt, int update)
>>
>> "update" here is quite confusing, because that's not what is happening. Or at
>> least, update is so overloaded that I'm not understanding it the way you are.
>> The list of locations is still updated/regenerated, and we do delete locations
>> from the target, but, we don't allow new insertions. So, could we
>> s/update/somethingelse/ please? Even pointing at update_global_location_list's
>> description of its parameter would be good.
>>
>> Or maybe, I just had an idea --- I wonder if we made update_global_location_list
>> still re-insert _only_ the _already inserted_ locations when the
>> condition changes, then we'd be good. That is, something like:
>>
>> update_global_location_list:
>> ...
>> - if (breakpoints_always_inserted_mode ()&& should_insert
>> -&& (have_live_inferiors ()
>> - || (gdbarch_has_global_breakpoints (target_gdbarch))))
>> - insert_breakpoint_locations ();
>> + if (breakpoints_always_inserted_mode ()
>> +&& (have_live_inferiors ()
>> + || (gdbarch_has_global_breakpoints (target_gdbarch))))
>> + {
>> + if (should_insert)
>> + insert_breakpoint_locations ();
>> + else
>> + update_inserted_breakpoint_locations ();
>> + }
>>
>> The problem is that a delete_breakpoint would trigger insertions of all
>> _other_ breakpoints. But if we're allow "reinserting" breakpoints that
>> are _already_ inserted, I think we're fine.
>
> I implemented this change. update_inserted_breakpoint_locations is a simpler version of insert_breakpoint_locations. Its purpose is to synch conditions of already-inserted breakpoint locations with the target.
>
>>
>>> Is disabling breakpoints also something we would like to do without triggering insertions? If so, i'm inclined to go with the same solution as for deleting user breakpoints.
>>
>> Maybe, not sure. Better be safe, I think.
>>
>> It'd be nice to come up with a better way to solve the initial problem that
>> led to update_global_location_list having an argument in the first place. :-/
>
> I've confirmed this works with both delete and disable. Looks like a good solution for now.
>
Yes, looks much better. Thanks. The patch looks mostly good to me now. Only a
few comments below.
> The breakpoint infrastructure could use a little cleaning and refactoring i suppose. :-(
What doesn't? :-)
>
> Also, i changed remote.c to not pass the "conditions" marker anymore.
>
> Luis
>
> 0002-break_condition_bytecode.diff
>
>
> 2012-02-22 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.
> (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.
>
> Index: gdb/gdb/remote.c
> ===================================================================
> --- gdb.orig/gdb/remote.c 2012-02-22 13:22:16.930553985 -0200
> +++ gdb/gdb/remote.c 2012-02-22 13:22:49.174553987 -0200
> @@ -242,6 +242,8 @@ static int remote_read_description_p (st
>
> 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
> }
>
>
> +/* 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_length (agent_expr_p, bp_tgt->conditions))
if (!VEC_empty...)
if better:
if (VEC_empty...)
return 0;
sprintf (buf + strlen (buf), "%s", ";");
...
> + {
> + sprintf (buf + strlen (buf), "%s", ";");
> + }
> + else
> + return 0;
> +
and all these repeated strlen calls are unnecessary:
buf += strlen (buf);
sprintf (buf, "%s", ";");
> + /* 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 + strlen (buf), "X%x,", aexpr->len);
> + pkt = buf + strlen (buf);
> + for (i = 0; i < aexpr->len; ++i)
> + pkt = pack_hex_byte (pkt, aexpr->buf[i]);
> + *pkt = '\0';
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
> 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
> 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 gdba
> 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 connecte
> 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;
> Index: gdb/gdb/target.c
> ===================================================================
> --- gdb.orig/gdb/target.c 2012-02-22 13:22:16.946553985 -0200
> +++ gdb/gdb/target.c 2012-02-22 13:22:49.174553987 -0200
> @@ -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
> Index: gdb/gdb/target.h
> ===================================================================
> --- gdb.orig/gdb/target.h 2012-02-22 13:22:16.894553984 -0200
> +++ gdb/gdb/target.h 2012-02-22 13:22:49.178553986 -0200
> @@ -662,6 +662,9 @@ struct target_ops
> /* Does this target support the tracenz bytecode for string collection? */
> int (*to_supports_string_tracing) (void);
>
> + /* Does this target support evaluation breakpoint conditions on its end? */
either "evaluation of breakpoint conditions", or "evaluating breakpoint conditions"?
> + 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 +971,12 @@ int target_supports_disable_randomizatio
> #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);
>
> Index: gdb/gdb/breakpoint.c
> ===================================================================
> --- gdb.orig/gdb/breakpoint.c 2012-02-22 13:22:16.882553985 -0200
> +++ gdb/gdb/breakpoint.c 2012-02-22 13:22:58.038553985 -0200
> @@ -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 *,
>
> 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 "gdb"
It's "host" now, no longer "gdb".
> + 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,19 @@ 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_TMP < bp_location + bp_location_count \
> + && (*BP_LOCP_TMP)->address == ADDRESS); \
> + BP_LOCP_TMP++)
> +
> /* Iterator for tracepoints only. */
>
> #define ALL_TRACEPOINTS(B) \
> @@ -620,6 +694,144 @@ 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 GDB evaluation mode instead."));
s/GDB/host/ ?
> + 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:
> +
> + "gdb" -> "target": Send all (valid) conditions to the target.
> + "target" -> "gdb": Remove all the conditions from the target.
s/gdb/host/ ?
> + */
> +
> + /* Flip the switch. */
> + condition_evaluation_mode = condition_evaluation_mode_1;
> +
> + if (new_mode == condition_evaluation_target)
> + {
> + /* Mark everything modified and to 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);
> +}
> +
> +/* 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. */
> +
> +static struct bp_location **
> +get_first_locp_gte_addr (CORE_ADDR address)
> +{
> + struct bp_location **locp = bp_location;
> +
> + while (locp < bp_location + bp_location_count
> + && (*locp)->address < address)
> + locp++;
> +
> + return locp;
> +}
> +
> void
> set_breakpoint_condition (struct breakpoint *b, char *exp,
> int from_tty)
> @@ -642,6 +854,10 @@ set_breakpoint_condition (struct breakpo
> {
> 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 +900,8 @@ set_breakpoint_condition (struct breakpo
> }
> }
> }
> + mark_breakpoint_modified (b);
> +
> breakpoints_changed ();
> observer_notify_breakpoint_modified (b);
> }
> @@ -717,6 +935,10 @@ condition_command (char *arg, int from_t
> 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 +1438,15 @@ breakpoint_xfer_memory (gdb_byte *readbu
> }
>
>
> +/* Return true if BPT is either a software breakpoint or a hardware
> + breakpoint. */
> +int
Space between comment and function, please.
> +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 +1889,143 @@ unduplicated_should_be_inserted (struct
> 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 == bl->pspace)
> + {
> + 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 == bl->pspace)
> + {
> + /* 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 == bl->pspace
> + && 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 +2042,7 @@ insert_bp_location (struct bp_location *
> {
> 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 +2051,18 @@ insert_bp_location (struct bp_location *
> 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 +2371,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 +2454,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 +4532,10 @@ bpstat_check_breakpoint_conditions (bpst
> 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 +5113,66 @@ wrap_indent_at_field (struct ui_out *uio
> 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 +5231,16 @@ print_breakpoint_location (struct breakp
> 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 +5516,18 @@ print_one_breakpoint_location (struct br
> 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 +6257,7 @@ init_bp_location (struct bp_location *lo
> loc->ops = ops;
> loc->owner = owner;
> loc->cond = NULL;
> + loc->cond_bytecode = NULL;
> loc->shlib_disabled = 0;
> loc->enabled = 1;
>
> @@ -5758,9 +6285,11 @@ init_bp_location (struct bp_location *lo
> 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:
> @@ -10717,6 +11246,7 @@ swap_insertion (struct bp_location *left
> {
> 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. */
> @@ -10727,12 +11257,67 @@ swap_insertion (struct bp_location *left
>
> 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;
> + struct program_space *pspace = NULL;
> +
> + address = bl->address;
> + pspace = bl->pspace;
> +
> + /* 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)
It's unfortunate that we're introducing these extra iterations over
all locations. I think we can easily get rid of them by using
bsearch'ing for the initial location at address (and then rewinding
a bit for the first location that matches). I'm not making it
a requirement for acceptance, but I think it may be a good idea.
> + {
> + loc = *loc2p;
> +
> + if (!is_breakpoint (loc->owner)
> + || pspace != loc->pspace)
> + continue;
> +
> + /* Flag the location appropriately. We use a different number to
number? I think this was referring to before you had enums, right?
s/number/state/ would work, I think.
> + 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 this 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
> @@ -10754,6 +11339,10 @@ update_global_location_list (int should_
> 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 updated. */
"for update".
> + struct program_space *last_pspace = NULL;
>
> /* Used in the duplicates detection below. When iterating over all
> bp_locations, points to the first bp_location of a given address.
> @@ -10826,13 +11415,27 @@ update_global_location_list (int should_
> && (*loc2p)->address == old_loc->address);
> loc2p++)
> {
> + /* 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)
> + force_breakpoint_reinsertion ((*loc2p));
Unnecessary double parens '(('.
I think we need to check pspaces as well, in case the addresses are
the same, but the pspaces aren't.
> +
> if (*loc2p == old_loc)
> - {
> - found_object = 1;
> - break;
> - }
> + 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
> @@ -10852,6 +11455,10 @@ update_global_location_list (int should_
> }
> 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
> @@ -11004,7 +11611,11 @@ update_global_location_list (int should_
> 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)
> @@ -11027,6 +11638,13 @@ update_global_location_list (int should_
> {
> *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;
> }
>
> @@ -11038,6 +11656,9 @@ update_global_location_list (int should_
> 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__,
> @@ -11045,10 +11666,21 @@ update_global_location_list (int should_
> "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 ();
> @@ -11162,6 +11794,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);
> }
> @@ -12855,6 +13489,9 @@ disable_breakpoint (struct breakpoint *b
>
> 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))
> {
> @@ -12902,7 +13539,11 @@ disable_command (char *args, int from_tt
> 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))
> @@ -12959,6 +13600,11 @@ enable_breakpoint_disp (struct breakpoin
> 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))
> {
> @@ -13018,7 +13664,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))
> @@ -14459,8 +15109,9 @@ The \"Type\" column indicates one of:\n\
> \twatchpoint - watchpoint\n\
> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
> -address and file/line number respectively.\n\
> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
> +the address and file/line number respectively. The \"Cond Eval\" column\n\
> +indicates where the breakpoint condition will be evaluated.\n\
> \n\
> Convenience variable \"$_\" and default examine address for \"x\"\n\
> are set to the address of the last breakpoint listed unless the command\n\
> @@ -14476,8 +15127,9 @@ The \"Type\" column indicates one of:\n\
> \twatchpoint - watchpoint\n\
> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
> -address and file/line number respectively.\n\
> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
> +the address and file/line number respectively. The \"Cond Eval\" column\n\
> +indicates where the breakpoint condition will be evaluated.\n\
> \n\
> Convenience variable \"$_\" and default examine address for \"x\"\n\
> are set to the address of the last breakpoint listed unless the command\n\
> @@ -14495,8 +15147,9 @@ The \"Type\" column indicates one of:\n\
> \twatchpoint - watchpoint\n\
> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
> -address and file/line number respectively.\n\
> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
> +the address and file/line number respectively. The \"Cond Eval\" column\n\
> +indicates where the breakpoint condition will be evaluated.\n\
> \n\
> Convenience variable \"$_\" and default examine address for \"x\"\n\
> are set to the address of the last breakpoint listed unless the command\n\
> @@ -14515,8 +15168,9 @@ The \"Type\" column indicates one of:\n\
> \tfinish - internal breakpoint used by the \"finish\" command\n\
> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
> -address and file/line number respectively.\n\
> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
> +the address and file/line number respectively. The \"Cond Eval\" column\n\
> +indicates where the breakpoint condition will be evaluated.\n\
It didn't look like it is really true that we have a new "Cond Eval" column?
Can you show an example of what the new output looks like?
> \n\
> Convenience variable \"$_\" and default examine address for \"x\"\n\
> are set to the address of the last breakpoint listed unless the command\n\
> @@ -14793,6 +15447,23 @@ inferior in all-stop mode, gdb behaves a
> &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\
> Index: gdb/gdb/breakpoint.h
> ===================================================================
> --- gdb.orig/gdb/breakpoint.h 2012-02-22 13:22:16.906553986 -0200
> +++ gdb/gdb/breakpoint.h 2012-02-22 13:22:49.190553987 -0200
> +/* Returns true if BPT is a breakpoint of any kind. */
> +
> +extern int is_breakpoint (const struct breakpoint *bpt);
I see you've updated the comment on the .c side. Please update it here as
well (to be more specific).
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-23 17:38 ` Pedro Alves
@ 2012-02-24 12:20 ` Luis Gustavo
2012-02-24 13:01 ` Pedro Alves
0 siblings, 1 reply; 16+ messages in thread
From: Luis Gustavo @ 2012-02-24 12:20 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 52392 bytes --]
On 02/23/2012 03:24 PM, Pedro Alves wrote:
> On 02/22/2012 03:24 PM, Luis Gustavo wrote:
>> On 02/09/2012 10:56 AM, Pedro Alves wrote:
>>> On 02/08/2012 08:56 PM, Luis Gustavo wrote:
>>>
>>>>> I'm confused. How does this (and all similar places) address the issued I
>>>>> pointed out before? If you're passing one to update_global_location_list
>>>>> when deleting a breakpoint, you're pretty much defeating the whole
>>>>> purpose of the update_global_location_list's argument in the first place.
>>>>>
>>>>
>>>> Updates will only take place when the user explicitly removes/disables a breakpoint. Functions that are deleting breakpoints (like remove_thread_event_breakpoints) won't cause insertion of any breakpoints since they go through the "delete_breakpoint" path, not the delete_breakpoint_with_update one.
>>>
>>> Ah, got it now. Thanks. But please:
>>>
>>>> + structures. If UPDATE is true, proceed to update the list of
>>>> + locations, otherwise don't update it. */
>>>>
>>>> -void
>>>> -delete_breakpoint (struct breakpoint *bpt)
>>>> +static void
>>>> +delete_breakpoint_1 (struct breakpoint *bpt, int update)
>>>
>>> "update" here is quite confusing, because that's not what is happening. Or at
>>> least, update is so overloaded that I'm not understanding it the way you are.
>>> The list of locations is still updated/regenerated, and we do delete locations
>>> from the target, but, we don't allow new insertions. So, could we
>>> s/update/somethingelse/ please? Even pointing at update_global_location_list's
>>> description of its parameter would be good.
>>>
>>> Or maybe, I just had an idea --- I wonder if we made update_global_location_list
>>> still re-insert _only_ the _already inserted_ locations when the
>>> condition changes, then we'd be good. That is, something like:
>>>
>>> update_global_location_list:
>>> ...
>>> - if (breakpoints_always_inserted_mode ()&& should_insert
>>> -&& (have_live_inferiors ()
>>> - || (gdbarch_has_global_breakpoints (target_gdbarch))))
>>> - insert_breakpoint_locations ();
>>> + if (breakpoints_always_inserted_mode ()
>>> +&& (have_live_inferiors ()
>>> + || (gdbarch_has_global_breakpoints (target_gdbarch))))
>>> + {
>>> + if (should_insert)
>>> + insert_breakpoint_locations ();
>>> + else
>>> + update_inserted_breakpoint_locations ();
>>> + }
>>>
>>> The problem is that a delete_breakpoint would trigger insertions of all
>>> _other_ breakpoints. But if we're allow "reinserting" breakpoints that
>>> are _already_ inserted, I think we're fine.
>>
>> I implemented this change. update_inserted_breakpoint_locations is a simpler version of insert_breakpoint_locations. Its purpose is to synch conditions of already-inserted breakpoint locations with the target.
>>
>>>
>>>> Is disabling breakpoints also something we would like to do without triggering insertions? If so, i'm inclined to go with the same solution as for deleting user breakpoints.
>>>
>>> Maybe, not sure. Better be safe, I think.
>>>
>>> It'd be nice to come up with a better way to solve the initial problem that
>>> led to update_global_location_list having an argument in the first place. :-/
>>
>> I've confirmed this works with both delete and disable. Looks like a good solution for now.
>>
>
> Yes, looks much better. Thanks. The patch looks mostly good to me now. Only a
> few comments below.
>
>> The breakpoint infrastructure could use a little cleaning and refactoring i suppose. :-(
>
> What doesn't? :-)
>
>>
>> Also, i changed remote.c to not pass the "conditions" marker anymore.
>>
>> Luis
>>
>> 0002-break_condition_bytecode.diff
>>
>>
>> 2012-02-22 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.
>> (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.
>>
>> Index: gdb/gdb/remote.c
>> ===================================================================
>> --- gdb.orig/gdb/remote.c 2012-02-22 13:22:16.930553985 -0200
>> +++ gdb/gdb/remote.c 2012-02-22 13:22:49.174553987 -0200
>> @@ -242,6 +242,8 @@ static int remote_read_description_p (st
>>
>> 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
>> }
>>
>>
>> +/* 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_length (agent_expr_p, bp_tgt->conditions))
>
> if (!VEC_empty...)
>
> if better:
>
>
> if (VEC_empty...)
> return 0;
>
> sprintf (buf + strlen (buf), "%s", ";");
> ...
>
>> + {
>> + sprintf (buf + strlen (buf), "%s", ";");
>> + }
>> + else
>> + return 0;
>> +
>
> and all these repeated strlen calls are unnecessary:
>
> buf += strlen (buf);
> sprintf (buf, "%s", ";");
>
>
>> + /* 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 + strlen (buf), "X%x,", aexpr->len);
>> + pkt = buf + strlen (buf);
>> + for (i = 0; i< aexpr->len; ++i)
>> + pkt = pack_hex_byte (pkt, aexpr->buf[i]);
>> + *pkt = '\0';
>
> 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
>> 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
>> 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 gdba
>> 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 connecte
>> 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;
>> Index: gdb/gdb/target.c
>> ===================================================================
>> --- gdb.orig/gdb/target.c 2012-02-22 13:22:16.946553985 -0200
>> +++ gdb/gdb/target.c 2012-02-22 13:22:49.174553987 -0200
>> @@ -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
>> Index: gdb/gdb/target.h
>> ===================================================================
>> --- gdb.orig/gdb/target.h 2012-02-22 13:22:16.894553984 -0200
>> +++ gdb/gdb/target.h 2012-02-22 13:22:49.178553986 -0200
>> @@ -662,6 +662,9 @@ struct target_ops
>> /* Does this target support the tracenz bytecode for string collection? */
>> int (*to_supports_string_tracing) (void);
>>
>> + /* Does this target support evaluation breakpoint conditions on its end? */
>
> either "evaluation of breakpoint conditions", or "evaluating breakpoint conditions"?
>
>
>> + 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 +971,12 @@ int target_supports_disable_randomizatio
>> #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);
>>
>> Index: gdb/gdb/breakpoint.c
>> ===================================================================
>> --- gdb.orig/gdb/breakpoint.c 2012-02-22 13:22:16.882553985 -0200
>> +++ gdb/gdb/breakpoint.c 2012-02-22 13:22:58.038553985 -0200
>> @@ -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 *,
>>
>> 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 "gdb"
>
> It's "host" now, no longer "gdb".
>
>> + 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,19 @@ 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_TMP< bp_location + bp_location_count \
>> + && (*BP_LOCP_TMP)->address == ADDRESS); \
>> + BP_LOCP_TMP++)
>> +
>> /* Iterator for tracepoints only. */
>>
>> #define ALL_TRACEPOINTS(B) \
>> @@ -620,6 +694,144 @@ 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 GDB evaluation mode instead."));
>
> s/GDB/host/ ?
>
>> + 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:
>> +
>> + "gdb" -> "target": Send all (valid) conditions to the target.
>> + "target" -> "gdb": Remove all the conditions from the target.
>
> s/gdb/host/ ?
>
>> + */
>> +
>> + /* Flip the switch. */
>> + condition_evaluation_mode = condition_evaluation_mode_1;
>> +
>> + if (new_mode == condition_evaluation_target)
>> + {
>> + /* Mark everything modified and to 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);
>> +}
>> +
>> +/* 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. */
>> +
>> +static struct bp_location **
>> +get_first_locp_gte_addr (CORE_ADDR address)
>> +{
>> + struct bp_location **locp = bp_location;
>> +
>> + while (locp< bp_location + bp_location_count
>> + && (*locp)->address< address)
>> + locp++;
>> +
>> + return locp;
>> +}
>> +
>> void
>> set_breakpoint_condition (struct breakpoint *b, char *exp,
>> int from_tty)
>> @@ -642,6 +854,10 @@ set_breakpoint_condition (struct breakpo
>> {
>> 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 +900,8 @@ set_breakpoint_condition (struct breakpo
>> }
>> }
>> }
>> + mark_breakpoint_modified (b);
>> +
>> breakpoints_changed ();
>> observer_notify_breakpoint_modified (b);
>> }
>> @@ -717,6 +935,10 @@ condition_command (char *arg, int from_t
>> 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 +1438,15 @@ breakpoint_xfer_memory (gdb_byte *readbu
>> }
>>
>>
>> +/* Return true if BPT is either a software breakpoint or a hardware
>> + breakpoint. */
>> +int
>
> Space between comment and function, please.
>
>> +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 +1889,143 @@ unduplicated_should_be_inserted (struct
>> 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 == bl->pspace)
>> + {
>> + 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 == bl->pspace)
>> + {
>> + /* 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 == bl->pspace
>> + && 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 +2042,7 @@ insert_bp_location (struct bp_location *
>> {
>> 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 +2051,18 @@ insert_bp_location (struct bp_location *
>> 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 +2371,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 +2454,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 +4532,10 @@ bpstat_check_breakpoint_conditions (bpst
>> 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 +5113,66 @@ wrap_indent_at_field (struct ui_out *uio
>> 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 +5231,16 @@ print_breakpoint_location (struct breakp
>> 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 +5516,18 @@ print_one_breakpoint_location (struct br
>> 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 +6257,7 @@ init_bp_location (struct bp_location *lo
>> loc->ops = ops;
>> loc->owner = owner;
>> loc->cond = NULL;
>> + loc->cond_bytecode = NULL;
>> loc->shlib_disabled = 0;
>> loc->enabled = 1;
>>
>> @@ -5758,9 +6285,11 @@ init_bp_location (struct bp_location *lo
>> 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:
>> @@ -10717,6 +11246,7 @@ swap_insertion (struct bp_location *left
>> {
>> 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. */
>> @@ -10727,12 +11257,67 @@ swap_insertion (struct bp_location *left
>>
>> 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;
>> + struct program_space *pspace = NULL;
>> +
>> + address = bl->address;
>> + pspace = bl->pspace;
>> +
>> + /* 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)
>
> It's unfortunate that we're introducing these extra iterations over
> all locations. I think we can easily get rid of them by using
> bsearch'ing for the initial location at address (and then rewinding
> a bit for the first location that matches). I'm not making it
> a requirement for acceptance, but I think it may be a good idea.
>
Yes, sounds like a good optimization. What do you think of the following
patch?
>> + {
>> + loc = *loc2p;
>> +
>> + if (!is_breakpoint (loc->owner)
>> + || pspace != loc->pspace)
>> + continue;
>> +
>> + /* Flag the location appropriately. We use a different number to
>
> number? I think this was referring to before you had enums, right?
> s/number/state/ would work, I think.
>
>> + 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 this 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
>> @@ -10754,6 +11339,10 @@ update_global_location_list (int should_
>> 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 updated. */
>
> "for update".
>
>> + struct program_space *last_pspace = NULL;
>>
>> /* Used in the duplicates detection below. When iterating over all
>> bp_locations, points to the first bp_location of a given address.
>> @@ -10826,13 +11415,27 @@ update_global_location_list (int should_
>> && (*loc2p)->address == old_loc->address);
>> loc2p++)
>> {
>> + /* 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)
>> + force_breakpoint_reinsertion ((*loc2p));
>
> Unnecessary double parens '(('.
>
> I think we need to check pspaces as well, in case the addresses are
> the same, but the pspaces aren't.
>
Fixed this. We're checking pspace numbers now.
>> +
>> if (*loc2p == old_loc)
>> - {
>> - found_object = 1;
>> - break;
>> - }
>> + 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
>> @@ -10852,6 +11455,10 @@ update_global_location_list (int should_
>> }
>> 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
>> @@ -11004,7 +11611,11 @@ update_global_location_list (int should_
>> 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)
>> @@ -11027,6 +11638,13 @@ update_global_location_list (int should_
>> {
>> *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;
>> }
>>
>> @@ -11038,6 +11656,9 @@ update_global_location_list (int should_
>> 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__,
>> @@ -11045,10 +11666,21 @@ update_global_location_list (int should_
>> "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 ();
>> @@ -11162,6 +11794,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);
>> }
>> @@ -12855,6 +13489,9 @@ disable_breakpoint (struct breakpoint *b
>>
>> 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))
>> {
>> @@ -12902,7 +13539,11 @@ disable_command (char *args, int from_tt
>> 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))
>> @@ -12959,6 +13600,11 @@ enable_breakpoint_disp (struct breakpoin
>> 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))
>> {
>> @@ -13018,7 +13664,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))
>> @@ -14459,8 +15109,9 @@ The \"Type\" column indicates one of:\n\
>> \twatchpoint - watchpoint\n\
>> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
>> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
>> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
>> -address and file/line number respectively.\n\
>> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
>> +the address and file/line number respectively. The \"Cond Eval\" column\n\
>> +indicates where the breakpoint condition will be evaluated.\n\
>> \n\
>> Convenience variable \"$_\" and default examine address for \"x\"\n\
>> are set to the address of the last breakpoint listed unless the command\n\
>> @@ -14476,8 +15127,9 @@ The \"Type\" column indicates one of:\n\
>> \twatchpoint - watchpoint\n\
>> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
>> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
>> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
>> -address and file/line number respectively.\n\
>> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
>> +the address and file/line number respectively. The \"Cond Eval\" column\n\
>> +indicates where the breakpoint condition will be evaluated.\n\
>> \n\
>> Convenience variable \"$_\" and default examine address for \"x\"\n\
>> are set to the address of the last breakpoint listed unless the command\n\
>> @@ -14495,8 +15147,9 @@ The \"Type\" column indicates one of:\n\
>> \twatchpoint - watchpoint\n\
>> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
>> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
>> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
>> -address and file/line number respectively.\n\
>> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
>> +the address and file/line number respectively. The \"Cond Eval\" column\n\
>> +indicates where the breakpoint condition will be evaluated.\n\
>> \n\
>> Convenience variable \"$_\" and default examine address for \"x\"\n\
>> are set to the address of the last breakpoint listed unless the command\n\
>> @@ -14515,8 +15168,9 @@ The \"Type\" column indicates one of:\n\
>> \tfinish - internal breakpoint used by the \"finish\" command\n\
>> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
>> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
>> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
>> -address and file/line number respectively.\n\
>> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
>> +the address and file/line number respectively. The \"Cond Eval\" column\n\
>> +indicates where the breakpoint condition will be evaluated.\n\
>
> It didn't look like it is really true that we have a new "Cond Eval" column?
> Can you show an example of what the new output looks like?
>
>
>> \n\
>> Convenience variable \"$_\" and default examine address for \"x\"\n\
>> are set to the address of the last breakpoint listed unless the command\n\
>> @@ -14793,6 +15447,23 @@ inferior in all-stop mode, gdb behaves a
>> &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\
>> Index: gdb/gdb/breakpoint.h
>> ===================================================================
>> --- gdb.orig/gdb/breakpoint.h 2012-02-22 13:22:16.906553986 -0200
>> +++ gdb/gdb/breakpoint.h 2012-02-22 13:22:49.190553987 -0200
>
>> +/* Returns true if BPT is a breakpoint of any kind. */
>> +
>> +extern int is_breakpoint (const struct breakpoint *bpt);
>
> I see you've updated the comment on the .c side. Please update it here as
> well (to be more specific).
>
Fixed all the other comments and addressed a few typos i've found as well.
Thanks,
Luis
[-- Attachment #2: 0002-break_condition_bytecode.diff --]
[-- Type: text/x-patch, Size: 47478 bytes --]
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.
Index: gdb/gdb/remote.c
===================================================================
--- gdb.orig/gdb/remote.c 2012-02-23 15:57:41.734553984 -0200
+++ gdb/gdb/remote.c 2012-02-23 16:45:59.294553986 -0200
@@ -242,6 +242,8 @@ static int remote_read_description_p (st
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
}
\f
+/* 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
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
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 gdba
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 connecte
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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c 2012-02-23 15:56:51.278553984 -0200
+++ gdb/gdb/target.c 2012-02-23 15:57:42.514553985 -0200
@@ -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
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h 2012-02-23 15:56:51.226553986 -0200
+++ gdb/gdb/target.h 2012-02-23 16:04:27.282553986 -0200
@@ -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_randomizatio
#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);
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c 2012-02-23 15:56:51.214553984 -0200
+++ gdb/gdb/breakpoint.c 2012-02-24 10:02:23.702553984 -0200
@@ -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 *,
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)
\f
+/* 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 breakpo
{
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 breakpo
}
}
}
+ mark_breakpoint_modified (b);
+
breakpoints_changed ();
observer_notify_breakpoint_modified (b);
}
@@ -717,6 +970,10 @@ condition_command (char *arg, int from_t
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 *readbu
}
\f
+/* 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
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 *
{
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->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 (bpst
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 *uio
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 breakp
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 br
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 *lo
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 *lo
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:
@@ -10717,6 +11282,7 @@ swap_insertion (struct bp_location *left
{
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. */
@@ -10727,12 +11293,67 @@ swap_insertion (struct bp_location *left
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
@@ -10754,6 +11375,10 @@ update_global_location_list (int should_
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.
@@ -10826,13 +11451,30 @@ update_global_location_list (int should_
&& (*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
@@ -10852,6 +11494,10 @@ update_global_location_list (int should_
}
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
@@ -11004,7 +11650,11 @@ update_global_location_list (int should_
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)
@@ -11027,6 +11677,13 @@ update_global_location_list (int should_
{
*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;
}
@@ -11038,6 +11695,9 @@ update_global_location_list (int should_
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__,
@@ -11045,10 +11705,21 @@ update_global_location_list (int should_
"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 ();
@@ -11162,6 +11833,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);
}
@@ -12855,6 +13528,9 @@ disable_breakpoint (struct breakpoint *b
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))
{
@@ -12902,7 +13578,11 @@ disable_command (char *args, int from_tt
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))
@@ -12959,6 +13639,11 @@ enable_breakpoint_disp (struct breakpoin
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))
{
@@ -13018,7 +13703,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))
@@ -14459,8 +15148,8 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14476,8 +15165,8 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14495,8 +15184,8 @@ The \"Type\" column indicates one of:\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14515,8 +15204,8 @@ The \"Type\" column indicates one of:\n\
\tfinish - internal breakpoint used by the \"finish\" command\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
-breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
-address and file/line number respectively.\n\
+breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
+the address and file/line number respectively.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed unless the command\n\
@@ -14793,6 +15482,23 @@ inferior in all-stop mode, gdb behaves a
&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\
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h 2012-02-23 15:56:51.238553987 -0200
+++ gdb/gdb/breakpoint.h 2012-02-23 16:35:43.750553987 -0200
@@ -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);
Index: gdb/gdb/ax.h
===================================================================
--- gdb.orig/gdb/ax.h 2012-02-23 15:56:51.250553985 -0200
+++ gdb/gdb/ax.h 2012-02-23 15:57:42.550553987 -0200
@@ -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
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-24 12:20 ` Luis Gustavo
@ 2012-02-24 13:01 ` Pedro Alves
2012-02-24 13:04 ` Luis Gustavo
0 siblings, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2012-02-24 13:01 UTC (permalink / raw)
To: Gustavo, Luis; +Cc: Tom Tromey, gdb-patches
On 02/24/2012 12:19 PM, Luis Gustavo wrote:
> @@ -14459,8 +15148,8 @@ The \"Type\" column indicates one of:\n\
> \twatchpoint - watchpoint\n\
> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
> -address and file/line number respectively.\n\
> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
> +the address and file/line number respectively.\n\
> \n\
> Convenience variable \"$_\" and default examine address for \"x\"\n\
> are set to the address of the last breakpoint listed unless the command\n\
> @@ -14476,8 +15165,8 @@ The \"Type\" column indicates one of:\n\
> \twatchpoint - watchpoint\n\
> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
> -address and file/line number respectively.\n\
> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
> +the address and file/line number respectively.\n\
> \n\
> Convenience variable \"$_\" and default examine address for \"x\"\n\
> are set to the address of the last breakpoint listed unless the command\n\
> @@ -14495,8 +15184,8 @@ The \"Type\" column indicates one of:\n\
> \twatchpoint - watchpoint\n\
> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
> -address and file/line number respectively.\n\
> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
> +the address and file/line number respectively.\n\
> \n\
> Convenience variable \"$_\" and default examine address for \"x\"\n\
> are set to the address of the last breakpoint listed unless the command\n\
> @@ -14515,8 +15204,8 @@ The \"Type\" column indicates one of:\n\
> \tfinish - internal breakpoint used by the \"finish\" command\n\
> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
> -address and file/line number respectively.\n\
> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
> +the address and file/line number respectively.\n\
> \n\
All these look like unintended changes now. Otherwise looks very good. Thanks.
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rfc target-side break conditions 3/5 v2] GDB-side changes
2012-02-24 13:01 ` Pedro Alves
@ 2012-02-24 13:04 ` Luis Gustavo
0 siblings, 0 replies; 16+ messages in thread
From: Luis Gustavo @ 2012-02-24 13:04 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
On 02/24/2012 10:58 AM, Pedro Alves wrote:
> On 02/24/2012 12:19 PM, Luis Gustavo wrote:
>> @@ -14459,8 +15148,8 @@ The \"Type\" column indicates one of:\n\
>> \twatchpoint - watchpoint\n\
>> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
>> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
>> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
>> -address and file/line number respectively.\n\
>> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
>> +the address and file/line number respectively.\n\
>> \n\
>> Convenience variable \"$_\" and default examine address for \"x\"\n\
>> are set to the address of the last breakpoint listed unless the command\n\
>> @@ -14476,8 +15165,8 @@ The \"Type\" column indicates one of:\n\
>> \twatchpoint - watchpoint\n\
>> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
>> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
>> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
>> -address and file/line number respectively.\n\
>> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
>> +the address and file/line number respectively.\n\
>> \n\
>> Convenience variable \"$_\" and default examine address for \"x\"\n\
>> are set to the address of the last breakpoint listed unless the command\n\
>> @@ -14495,8 +15184,8 @@ The \"Type\" column indicates one of:\n\
>> \twatchpoint - watchpoint\n\
>> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
>> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
>> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
>> -address and file/line number respectively.\n\
>> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
>> +the address and file/line number respectively.\n\
>> \n\
>> Convenience variable \"$_\" and default examine address for \"x\"\n\
>> are set to the address of the last breakpoint listed unless the command\n\
>> @@ -14515,8 +15204,8 @@ The \"Type\" column indicates one of:\n\
>> \tfinish - internal breakpoint used by the \"finish\" command\n\
>> The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
>> the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
>> -breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
>> -address and file/line number respectively.\n\
>> +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate\n\
>> +the address and file/line number respectively.\n\
>> \n\
>
> All these look like unintended changes now. Otherwise looks very good. Thanks.
>
Let me do some cleaning. Also, i realized i didn't mention the reason
for this...
There's no "Cond" column obviously. I planned to have that in the
beginning, but now such attribute is only available as an additional
block of text next to the conditions and through the "Evaluated-by" MI
field...
Luis
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2012-02-24 13:01 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-27 20:34 [rfc target-side break conditions 3/5 v2] GDB-side changes Luis Gustavo
2012-02-06 20:27 ` Tom Tromey
2012-02-07 11:16 ` Luis Gustavo
2012-02-08 19:33 ` Pedro Alves
2012-02-08 20:56 ` Luis Gustavo
2012-02-09 12:56 ` Pedro Alves
2012-02-22 15:29 ` Luis Gustavo
2012-02-23 17:38 ` Pedro Alves
2012-02-24 12:20 ` Luis Gustavo
2012-02-24 13:01 ` Pedro Alves
2012-02-24 13:04 ` Luis Gustavo
2012-02-09 13:00 ` Pedro Alves
2012-02-07 19:13 ` Pedro Alves
2012-02-07 19:26 ` Stan Shebs
2012-02-07 22:08 ` Stan Shebs
2012-02-08 23:13 ` Luis Gustavo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox