2012-02-24 Luis Machado <lgustavo@codesourcery.com>
authorLuis Machado <luisgpm@br.ibm.com>
Fri, 24 Feb 2012 15:10:59 +0000 (15:10 +0000)
committerLuis Machado <luisgpm@br.ibm.com>
Fri, 24 Feb 2012 15:10:59 +0000 (15:10 +0000)
* 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.

gdb/ChangeLog
gdb/ax.h
gdb/breakpoint.c
gdb/breakpoint.h
gdb/remote.c
gdb/target.c
gdb/target.h

index 516617b..c162792 100644 (file)
@@ -1,5 +1,82 @@
 2012-02-24  Luis Machado  <lgustavo@codesourcery.com>
 
+       * remote.c (remote_supports_cond_breakpoints): New forward
+       declaration.
+       (remote_add_target_side_condition): New function.
+       (remote_insert_breakpoint): Add target-side breakpoint
+       conditional if supported.
+       (remote_insert_hw_breakpoint): Likewise.
+       (init_remote_ops): Set to_supports_evaluation_of_breakpoint_conditions
+       hook.
+
+       * target.c (update_current_target): Inherit
+       to_supports_evaluation_of_breakpoint_conditions.
+       Default to_supports_evaluation_of_breakpoint_conditions to return_zero.
+
+       * target.h (struct target_ops)
+       <to_supports_evaluation_of_breakpoint_conditions>: New field.
+       (target_supports_evaluation_of_breakpoint_conditions): New #define.
+
+       * breakpoint.c (get_first_locp_gte_addr): New forward declaration.
+       (condition_evaluation_both, condition_evaluation_auto,
+       condition_evaluation_host, condition_evaluation_target,
+       condition_evaluation_enums, condition_evaluation_mode_1,
+       condition_evaluation_mode): New static globals.
+       (translate_condition_evaluation_mode): New function.
+       (breakpoint_condition_evaluation_mode): New function.
+       (gdb_evaluates_breakpoint_condition_p): New function.
+       (ALL_BP_LOCATIONS_AT_ADDR): New helper macro.
+       (mark_breakpoint_modified): New function.
+       (mark_breakpoint_location_modified): New function.
+       (set_condition_evaluation_mode): New function.
+       (show_condition_evaluation_mode): New function.
+       (bp_location_compare_addrs): New function.
+       (get_first_location_gte_addr): New helper function.
+       (set_breakpoint_condition): Free condition bytecode if locations
+       has become unconditional.  Call mark_breakpoint_modified (...).
+       (condition_command): Call update_global_location_list (1) for
+       breakpoints.
+       (breakpoint_xfer_memory): Use is_breakpoint (...).
+       (is_breakpoint): New function.
+       (parse_cond_to_aexpr): New function.
+       (build_target_condition_list): New function.
+       (insert_bp_location): Handle target-side conditional
+       breakpoints and call build_target_condition_list (...).
+       (update_inserted_breakpoint_locations): New function.
+       (insert_breakpoint_locations): Handle target-side conditional
+       breakpoints.
+       (bpstat_check_breakpoint_conditions): Add comment.
+       (bp_condition_evaluator): New function.
+       (bp_location_condition_evaluator): New function.
+       (print_breakpoint_location): Print information on where the condition
+       will be evaluated.
+       (print_one_breakpoint_location): Likewise.
+       (init_bp_location): Call mark_breakpoint_location_modified (...) for
+       breakpoint location.
+       (force_breakpoint_reinsertion): New functions.
+       (update_global_location_list): Handle target-side breakpoint
+       conditions.
+       Reinsert locations that are already inserted if conditions have
+       changed.
+       (bp_location_dtor): Free agent expression bytecode.
+       (disable_breakpoint): Call mark_breakpoint_modified (...).
+       Call update_global_location_list (...) with parameter 1 for breakpoints.
+       (disable_command): Call mark_breakpoint_location_modified (...).
+       Call update_global_location_list (...) with parameter 1 for breakpoints.
+       (enable_breakpoint_disp): Call mark_breakpoint_modified (...).
+       (enable_command): mark_breakpoint_location_modified (...).
+       (_initialize_breakpoint): Update documentation and add
+       condition-evaluation breakpoint subcommand.
+
+       * breakpoint.h: Include ax.h.
+       (condition_list): New data structure.
+       (condition_status): New enum.
+       (bp_target_info) <cond_list>: New field.
+       (bp_location) <condition_changed, cond_bytecode>: New fields.
+       (is_breakpoint): New prototype.
+
+2012-02-24  Luis Machado  <lgustavo@codesourcery.com>
+
        * remote.c (remote_state) <cond_breakpoints>: New field.
        (PACKET_ConditionalBreakpoints): New enum.
        (remote_cond_breakpoint_feature): New function.
index a25a3d1..d4069f7 100644 (file)
--- a/gdb/ax.h
+++ b/gdb/ax.h
@@ -20,6 +20,7 @@
 #define AGENTEXPR_H
 
 #include "doublest.h"          /* For DOUBLEST.  */
+#include "vec.h"
 
 /* It's sometimes useful to be able to debug programs that you can't
    really stop for more than a fraction of a second.  To this end, the
@@ -144,6 +145,12 @@ struct agent_expr
     unsigned char *reg_mask;
   };
 
+/* Pointer to an agent_expr structure.  */
+typedef struct agent_expr *agent_expr_p;
+
+/* Vector of pointers to agent expressions.  */
+DEF_VEC_P (agent_expr_p);
+
 /* The actual values of the various bytecode operations.  */
 
 enum agent_op
index fd9dced..3303842 100644 (file)
@@ -66,6 +66,7 @@
 #include "skip.h"
 #include "record.h"
 #include "gdb_regex.h"
+#include "ax-gdb.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -258,6 +259,8 @@ static void trace_pass_command (char *, int);
 
 static int is_masked_watchpoint (const struct breakpoint *b);
 
+static struct bp_location **get_first_locp_gte_addr (CORE_ADDR address);
+
 /* Return 1 if B refers to a static tracepoint set by marker ("-m"), zero
    otherwise.  */
 
@@ -406,6 +409,64 @@ breakpoints_always_inserted_mode (void)
          && !RECORD_IS_USED);
 }
 
+static const char condition_evaluation_both[] = "host or target";
+
+/* Modes for breakpoint condition evaluation.  */
+static const char condition_evaluation_auto[] = "auto";
+static const char condition_evaluation_host[] = "host";
+static const char condition_evaluation_target[] = "target";
+static const char *const condition_evaluation_enums[] = {
+  condition_evaluation_auto,
+  condition_evaluation_host,
+  condition_evaluation_target,
+  NULL
+};
+
+/* Global that holds the current mode for breakpoint condition evaluation.  */
+static const char *condition_evaluation_mode_1 = condition_evaluation_auto;
+
+/* Global that we use to display information to the user (gets its value from
+   condition_evaluation_mode_1.  */
+static const char *condition_evaluation_mode = condition_evaluation_auto;
+
+/* Translate a condition evaluation mode MODE into either "host"
+   or "target".  This is used mostly to translate from "auto" to the
+   real setting that is being used.  It returns the translated
+   evaluation mode.  */
+
+static const char *
+translate_condition_evaluation_mode (const char *mode)
+{
+  if (mode == condition_evaluation_auto)
+    {
+      if (target_supports_evaluation_of_breakpoint_conditions ())
+       return condition_evaluation_target;
+      else
+       return condition_evaluation_host;
+    }
+  else
+    return mode;
+}
+
+/* Discovers what condition_evaluation_auto translates to.  */
+
+static const char *
+breakpoint_condition_evaluation_mode (void)
+{
+  return translate_condition_evaluation_mode (condition_evaluation_mode);
+}
+
+/* Return true if GDB should evaluate breakpoint conditions or false
+   otherwise.  */
+
+static int
+gdb_evaluates_breakpoint_condition_p (void)
+{
+  const char *mode = breakpoint_condition_evaluation_mode ();
+
+  return (mode == condition_evaluation_host);
+}
+
 void _initialize_breakpoint (void);
 
 /* Are we executing breakpoint commands?  */
@@ -437,6 +498,20 @@ int target_exact_watchpoints = 0;
             BP_TMP < bp_location + bp_location_count && (B = *BP_TMP); \
             BP_TMP++)
 
+/* Iterates through locations with address ADDRESS for the currently selected
+   program space.  BP_LOCP_TMP points to each object.  BP_LOCP_START points
+   to where the loop should start from.
+   If BP_LOCP_START is a NULL pointer, the macro automatically seeks the
+   appropriate location to start with.  */
+
+#define ALL_BP_LOCATIONS_AT_ADDR(BP_LOCP_TMP, BP_LOCP_START, ADDRESS)  \
+       for (BP_LOCP_START = BP_LOCP_START == NULL ? get_first_locp_gte_addr (ADDRESS) : BP_LOCP_START, \
+            BP_LOCP_TMP = BP_LOCP_START;                               \
+            BP_LOCP_START                                              \
+            && (BP_LOCP_TMP < bp_location + bp_location_count          \
+            && (*BP_LOCP_TMP)->address == ADDRESS);                    \
+            BP_LOCP_TMP++)
+
 /* Iterator for tracepoints only.  */
 
 #define ALL_TRACEPOINTS(B)  \
@@ -620,6 +695,178 @@ get_breakpoint (int num)
 
 \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 breakpoint *b, char *exp,
        {
          xfree (loc->cond);
          loc->cond = NULL;
+
+         /* No need to free the condition agent expression
+            bytecode (if we have one).  We will handle this
+            when we go through update_global_location_list.  */
        }
     }
 
@@ -684,6 +935,8 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
            }
        }
     }
+  mark_breakpoint_modified (b);
+
   breakpoints_changed ();
   observer_notify_breakpoint_modified (b);
 }
@@ -717,6 +970,10 @@ condition_command (char *arg, int from_tty)
          error (_("Cannot set a condition where a Python 'stop' "
                   "method has been defined in the breakpoint."));
        set_breakpoint_condition (b, p, from_tty);
+
+       if (is_breakpoint (b))
+         update_global_location_list (1);
+
        return;
       }
 
@@ -1216,6 +1473,16 @@ breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
 }
 \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 bp_location *bl)
   return result;
 }
 
+/* Parses a conditional described by an expression COND into an
+   agent expression bytecode suitable for evaluation
+   by the bytecode interpreter.  Return NULL if there was
+   any error during parsing.  */
+
+static struct agent_expr *
+parse_cond_to_aexpr (CORE_ADDR scope, struct expression *cond)
+{
+  struct agent_expr *aexpr = NULL;
+  struct cleanup *old_chain = NULL;
+  volatile struct gdb_exception ex;
+
+  if (!cond)
+    return NULL;
+
+  /* We don't want to stop processing, so catch any errors
+     that may show up.  */
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      aexpr = gen_eval_for_expr (scope, cond);
+    }
+
+  if (ex.reason < 0)
+    {
+      /* If we got here, it means the condition could not be parsed to a valid
+        bytecode expression and thus can't be evaluated on the target's side.
+        It's no use iterating through the conditions.  */
+      return NULL;
+    }
+
+  /* We have a valid agent expression.  */
+  return aexpr;
+}
+
+/* Based on location BL, create a list of breakpoint conditions to be
+   passed on to the target.  If we have duplicated locations with different
+   conditions, we will add such conditions to the list.  The idea is that the
+   target will evaluate the list of conditions and will only notify GDB when
+   one of them is true.  */
+
+static void
+build_target_condition_list (struct bp_location *bl)
+{
+  struct bp_location **locp = NULL, **loc2p;
+  int null_condition_or_parse_error = 0;
+  int modified = bl->needs_update;
+  struct bp_location *loc;
+
+  /* This is only meaningful if the target is
+     evaluating conditions and if the user has
+     opted for condition evaluation on the target's
+     side.  */
+  if (gdb_evaluates_breakpoint_condition_p ()
+      || !target_supports_evaluation_of_breakpoint_conditions ())
+    return;
+
+  /* Do a first pass to check for locations with no assigned
+     conditions or conditions that fail to parse to a valid agent expression
+     bytecode.  If any of these happen, then it's no use to send conditions
+     to the target since this location will always trigger and generate a
+     response back to GDB.  */
+  ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+    {
+      loc = (*loc2p);
+      if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
+       {
+         if (modified)
+           {
+             struct agent_expr *aexpr;
+
+             /* Re-parse the conditions since something changed.  In that
+                case we already freed the condition bytecodes (see
+                force_breakpoint_reinsertion).  We just
+                need to parse the condition to bytecodes again.  */
+             aexpr = parse_cond_to_aexpr (bl->address, loc->cond);
+             loc->cond_bytecode = aexpr;
+
+             /* Check if we managed to parse the conditional expression
+                correctly.  If not, we will not send this condition
+                to the target.  */
+             if (aexpr)
+               continue;
+           }
+
+         /* If we have a NULL bytecode expression, it means something
+            went wrong or we have a null condition expression.  */
+         if (!loc->cond_bytecode)
+           {
+             null_condition_or_parse_error = 1;
+             break;
+           }
+       }
+    }
+
+  /* If any of these happened, it means we will have to evaluate the conditions
+     for the location's address on gdb's side.  It is no use keeping bytecodes
+     for all the other duplicate locations, thus we free all of them here.
+
+     This is so we have a finer control over which locations' conditions are
+     being evaluated by GDB or the remote stub.  */
+  if (null_condition_or_parse_error)
+    {
+      ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+       {
+         loc = (*loc2p);
+         if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num)
+           {
+             /* Only go as far as the first NULL bytecode is
+                located.  */
+             if (!loc->cond_bytecode)
+               return;
+
+             free_agent_expr (loc->cond_bytecode);
+             loc->cond_bytecode = NULL;
+           }
+       }
+    }
+
+  /* No NULL conditions or failed bytecode generation.  Build a condition list
+     for this location's address.  */
+  ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address)
+    {
+      loc = (*loc2p);
+      if (loc->cond
+         && is_breakpoint (loc->owner)
+         && loc->pspace->num == bl->pspace->num
+         && loc->owner->enable_state == bp_enabled
+         && loc->enabled)
+       /* Add the condition to the vector.  This will be used later to send the
+          conditions to the target.  */
+       VEC_safe_push (agent_expr_p, bl->target_info.conditions,
+                      loc->cond_bytecode);
+    }
+
+  return;
+}
+
 /* Insert a low-level "breakpoint" of some type.  BL is the breakpoint
    location.  Any error messages are printed to TMP_ERROR_STREAM; and
    DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
@@ -1674,7 +2078,7 @@ insert_bp_location (struct bp_location *bl,
 {
   int val = 0;
 
-  if (!should_be_inserted (bl) || bl->inserted)
+  if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
     return 0;
 
   /* Initialize the target-specific information.  */
@@ -1683,6 +2087,18 @@ insert_bp_location (struct bp_location *bl,
   bl->target_info.placed_address_space = bl->pspace->aspace;
   bl->target_info.length = bl->length;
 
+  /* When working with target-side conditions, we must pass all the conditions
+     for the same breakpoint address down to the target since GDB will not
+     insert those locations.  With a list of breakpoint conditions, the target
+     can decide when to stop and notify GDB.  */
+
+  if (is_breakpoint (bl->owner))
+    {
+      build_target_condition_list (bl);
+      /* Reset the condition modification marker.  */
+      bl->needs_update = 0;
+    }
+
   if (bl->loc_type == bp_loc_software_breakpoint
       || bl->loc_type == bp_loc_hardware_breakpoint)
     {
@@ -1991,6 +2407,66 @@ insert_breakpoints (void)
     insert_breakpoint_locations ();
 }
 
+/* This is used when we need to synch breakpoint conditions between GDB and the
+   target.  It is the case with deleting and disabling of breakpoints when using
+   always-inserted mode.  */
+
+static void
+update_inserted_breakpoint_locations (void)
+{
+  struct bp_location *bl, **blp_tmp;
+  int error_flag = 0;
+  int val = 0;
+  int disabled_breaks = 0;
+  int hw_breakpoint_error = 0;
+
+  struct ui_file *tmp_error_stream = mem_fileopen ();
+  struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream);
+
+  /* Explicitly mark the warning -- this will only be printed if
+     there was an error.  */
+  fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+
+  save_current_space_and_thread ();
+
+  ALL_BP_LOCATIONS (bl, blp_tmp)
+    {
+      /* We only want to update software breakpoints and hardware
+        breakpoints.  */
+      if (!is_breakpoint (bl->owner))
+       continue;
+
+      /* We only want to update locations that are already inserted
+        and need updating.  This is to avoid unwanted insertion during
+        deletion of breakpoints.  */
+      if (!bl->inserted || (bl->inserted && !bl->needs_update))
+       continue;
+
+      switch_to_program_space_and_thread (bl->pspace);
+
+      /* For targets that support global breakpoints, there's no need
+        to select an inferior to insert breakpoint to.  In fact, even
+        if we aren't attached to any process yet, we should still
+        insert breakpoints.  */
+      if (!gdbarch_has_global_breakpoints (target_gdbarch)
+         && ptid_equal (inferior_ptid, null_ptid))
+       continue;
+
+      val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks,
+                                   &hw_breakpoint_error);
+      if (val)
+       error_flag = val;
+    }
+
+  if (error_flag)
+    {
+      target_terminal_ours_for_output ();
+      error_stream (tmp_error_stream);
+    }
+
+  do_cleanups (cleanups);
+}
+
 /* Used when starting or continuing the program.  */
 
 static void
@@ -2014,7 +2490,7 @@ insert_breakpoint_locations (void)
 
   ALL_BP_LOCATIONS (bl, blp_tmp)
     {
-      if (!should_be_inserted (bl) || bl->inserted)
+      if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
        continue;
 
       /* There is no point inserting thread-specific breakpoints if
@@ -4092,6 +4568,10 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
   b = bs->breakpoint_at;
   gdb_assert (b != NULL);
 
+  /* Even if the target evaluated the condition on its end and notified GDB, we
+     need to do so again since GDB does not know if we stopped due to a
+     breakpoint or a single step breakpoint.  */
+
   if (frame_id_p (b->frame_id)
       && !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ())))
     bs->stop = 0;
@@ -4669,6 +5149,66 @@ wrap_indent_at_field (struct ui_out *uiout, const char *col_name)
   return NULL;
 }
 
+/* Determine if the locations of this breakpoint will have their conditions
+   evaluated by the target, host or a mix of both.  Returns the following:
+
+    "host": Host evals condition.
+    "host or target": Host or Target evals condition.
+    "target": Target evals condition.
+*/
+
+static const char *
+bp_condition_evaluator (struct breakpoint *b)
+{
+  struct bp_location *bl;
+  char host_evals = 0;
+  char target_evals = 0;
+
+  if (!b)
+    return NULL;
+
+  if (!is_breakpoint (b))
+    return NULL;
+
+  if (gdb_evaluates_breakpoint_condition_p ()
+      || !target_supports_evaluation_of_breakpoint_conditions ())
+    return condition_evaluation_host;
+
+  for (bl = b->loc; bl; bl = bl->next)
+    {
+      if (bl->cond_bytecode)
+       target_evals++;
+      else
+       host_evals++;
+    }
+
+  if (host_evals && target_evals)
+    return condition_evaluation_both;
+  else if (target_evals)
+    return condition_evaluation_target;
+  else
+    return condition_evaluation_host;
+}
+
+/* Determine the breakpoint location's condition evaluator.  This is
+   similar to bp_condition_evaluator, but for locations.  */
+
+static const char *
+bp_location_condition_evaluator (struct bp_location *bl)
+{
+  if (bl && !is_breakpoint (bl->owner))
+    return NULL;
+
+  if (gdb_evaluates_breakpoint_condition_p ()
+      || !target_supports_evaluation_of_breakpoint_conditions ())
+    return condition_evaluation_host;
+
+  if (bl && bl->cond_bytecode)
+    return condition_evaluation_target;
+  else
+    return condition_evaluation_host;
+}
+
 /* Print the LOC location out of the list of B->LOC locations.  */
 
 static void
@@ -4727,6 +5267,16 @@ print_breakpoint_location (struct breakpoint *b,
   else
     ui_out_field_string (uiout, "pending", b->addr_string);
 
+  if (loc && is_breakpoint (b)
+      && breakpoint_condition_evaluation_mode () == condition_evaluation_target
+      && bp_condition_evaluator (b) == condition_evaluation_both)
+    {
+      ui_out_text (uiout, " (");
+      ui_out_field_string (uiout, "evaluated-by",
+                          bp_location_condition_evaluator (loc));
+      ui_out_text (uiout, ")");
+    }
+
   do_cleanups (old_chain);
 }
 
@@ -5002,6 +5552,18 @@ print_one_breakpoint_location (struct breakpoint *b,
       else
        ui_out_text (uiout, "\tstop only if ");
       ui_out_field_string (uiout, "cond", b->cond_string);
+
+      /* Print whether the target is doing the breakpoint's condition
+        evaluation.  If GDB is doing the evaluation, don't print anything.  */
+      if (is_breakpoint (b)
+         && breakpoint_condition_evaluation_mode ()
+         == condition_evaluation_target)
+       {
+         ui_out_text (uiout, " (");
+         ui_out_field_string (uiout, "evaluated-by",
+                              bp_condition_evaluator (b));
+         ui_out_text (uiout, " evals)");
+       }
       ui_out_text (uiout, "\n");
     }
 
@@ -5731,6 +6293,7 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
   loc->ops = ops;
   loc->owner = owner;
   loc->cond = NULL;
+  loc->cond_bytecode = NULL;
   loc->shlib_disabled = 0;
   loc->enabled = 1;
 
@@ -5758,9 +6321,11 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
     case bp_gnu_ifunc_resolver:
     case bp_gnu_ifunc_resolver_return:
       loc->loc_type = bp_loc_software_breakpoint;
+      mark_breakpoint_location_modified (loc);
       break;
     case bp_hardware_breakpoint:
       loc->loc_type = bp_loc_hardware_breakpoint;
+      mark_breakpoint_location_modified (loc);
       break;
     case bp_hardware_watchpoint:
     case bp_read_watchpoint:
@@ -10718,6 +11283,7 @@ swap_insertion (struct bp_location *left, struct bp_location *right)
 {
   const int left_inserted = left->inserted;
   const int left_duplicate = left->duplicate;
+  const int left_needs_update = left->needs_update;
   const struct bp_target_info left_target_info = left->target_info;
 
   /* Locations of tracepoints can never be duplicated.  */
@@ -10728,12 +11294,67 @@ swap_insertion (struct bp_location *left, struct bp_location *right)
 
   left->inserted = right->inserted;
   left->duplicate = right->duplicate;
+  left->needs_update = right->needs_update;
   left->target_info = right->target_info;
   right->inserted = left_inserted;
   right->duplicate = left_duplicate;
+  right->needs_update = left_needs_update;
   right->target_info = left_target_info;
 }
 
+/* Force the re-insertion of the locations at ADDRESS.  This is called
+   once a new/deleted/modified duplicate location is found and we are evaluating
+   conditions on the target's side.  Such conditions need to be updated on
+   the target.  */
+
+static void
+force_breakpoint_reinsertion (struct bp_location *bl)
+{
+  struct bp_location **locp = NULL, **loc2p;
+  struct bp_location *loc;
+  CORE_ADDR address = 0;
+  int pspace_num;
+
+  address = bl->address;
+  pspace_num = bl->pspace->num;
+
+  /* This is only meaningful if the target is
+     evaluating conditions and if the user has
+     opted for condition evaluation on the target's
+     side.  */
+  if (gdb_evaluates_breakpoint_condition_p ()
+      || !target_supports_evaluation_of_breakpoint_conditions ())
+    return;
+
+  /* Flag all breakpoint locations with this address and
+     the same program space as the location
+     as "its condition has changed".  We need to
+     update the conditions on the target's side.  */
+  ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, address)
+    {
+      loc = *loc2p;
+
+      if (!is_breakpoint (loc->owner)
+         || pspace_num != loc->pspace->num)
+       continue;
+
+      /* Flag the location appropriately.  We use a different state to
+        let everyone know that we already updated the set of locations
+        with addr bl->address and program space bl->pspace.  This is so
+        we don't have to keep calling these functions just to mark locations
+        that have already been marked.  */
+      loc->condition_changed = condition_updated;
+
+      /* Free the agent expression bytecode as well.  We will compute
+        it later on.  */
+      if (loc->cond_bytecode)
+       {
+         free_agent_expr (loc->cond_bytecode);
+         loc->cond_bytecode = NULL;
+       }
+    }
+}
+
 /* If SHOULD_INSERT is false, do not insert any breakpoint locations
    into the inferior, only remove already-inserted locations that no
    longer should be inserted.  Functions that delete a breakpoint or
@@ -10755,6 +11376,10 @@ update_global_location_list (int should_insert)
   struct breakpoint *b;
   struct bp_location **locp, *loc;
   struct cleanup *cleanups;
+  /* Last breakpoint location address that was marked for update.  */
+  CORE_ADDR last_addr = 0;
+  /* Last breakpoint location program space that was marked for update.  */
+  int last_pspace_num = -1;
 
   /* Used in the duplicates detection below.  When iterating over all
      bp_locations, points to the first bp_location of a given address.
@@ -10827,13 +11452,30 @@ update_global_location_list (int should_insert)
            && (*loc2p)->address == old_loc->address);
           loc2p++)
        {
-         if (*loc2p == old_loc)
+         /* Check if this is a new/duplicated location or a duplicated
+            location that had its condition modified.  If so, we want to send
+            its condition to the target if evaluation of conditions is taking
+            place there.  */
+         if ((*loc2p)->condition_changed == condition_modified
+             && (last_addr != old_loc->address
+                 || last_pspace_num != old_loc->pspace->num))
            {
-             found_object = 1;
-             break;
+             force_breakpoint_reinsertion (*loc2p);
+             last_pspace_num = old_loc->pspace->num;
            }
+
+         if (*loc2p == old_loc)
+           found_object = 1;
        }
 
+      /* We have already handled this address, update it so that we don't
+        have to go through updates again.  */
+      last_addr = old_loc->address;
+
+      /* Target-side condition evaluation: Handle deleted locations.  */
+      if (!found_object)
+       force_breakpoint_reinsertion (old_loc);
+
       /* If this location is no longer present, and inserted, look if
         there's maybe a new location at the same address.  If so,
         mark that one inserted, and don't remove this one.  This is
@@ -10853,6 +11495,10 @@ update_global_location_list (int should_insert)
            }
          else
            {
+             /* This location still exists, but it won't be kept in the
+                target since it may have been disabled.  We proceed to
+                remove its target-side condition.  */
+
              /* The location is either no longer present, or got
                 disabled.  See if there's another location at the
                 same address, in which case we don't need to remove
@@ -11005,7 +11651,11 @@ update_global_location_list (int should_insert)
           never duplicated.  See the comments in field `duplicate' of
           `struct bp_location'.  */
          || is_tracepoint (b))
-       continue;
+       {
+         /* Clear the condition modification flag.  */
+         loc->condition_changed = condition_unchanged;
+         continue;
+       }
 
       /* Permanent breakpoint should always be inserted.  */
       if (b->enable_state == bp_permanent && ! loc->inserted)
@@ -11028,6 +11678,13 @@ update_global_location_list (int should_insert)
        {
          *loc_first_p = loc;
          loc->duplicate = 0;
+
+         if (is_breakpoint (loc->owner) && loc->condition_changed)
+           {
+             loc->needs_update = 1;
+             /* Clear the condition modification flag.  */
+             loc->condition_changed = condition_unchanged;
+           }
          continue;
        }
 
@@ -11039,6 +11696,9 @@ update_global_location_list (int should_insert)
        swap_insertion (loc, *loc_first_p);
       loc->duplicate = 1;
 
+      /* Clear the condition modification flag.  */
+      loc->condition_changed = condition_unchanged;
+
       if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted
          && b->enable_state != bp_permanent)
        internal_error (__FILE__, __LINE__,
@@ -11046,10 +11706,21 @@ update_global_location_list (int should_insert)
                        "a permanent breakpoint"));
     }
 
-  if (breakpoints_always_inserted_mode () && should_insert
+  if (breakpoints_always_inserted_mode ()
       && (have_live_inferiors ()
          || (gdbarch_has_global_breakpoints (target_gdbarch))))
-    insert_breakpoint_locations ();
+    {
+      if (should_insert)
+       insert_breakpoint_locations ();
+      else
+       {
+         /* Though should_insert is false, we may need to update conditions
+            on the target's side if it is evaluating such conditions.  We
+            only update conditions for locations that are marked
+            "needs_update".  */
+         update_inserted_breakpoint_locations ();
+       }
+    }
 
   if (should_insert)
     download_tracepoint_locations ();
@@ -11163,6 +11834,8 @@ static void
 bp_location_dtor (struct bp_location *self)
 {
   xfree (self->cond);
+  if (self->cond_bytecode)
+    free_agent_expr (self->cond_bytecode);
   xfree (self->function_name);
   xfree (self->source_file);
 }
@@ -12856,6 +13529,9 @@ disable_breakpoint (struct breakpoint *bpt)
 
   bpt->enable_state = bp_disabled;
 
+  /* Mark breakpoint locations modified.  */
+  mark_breakpoint_modified (bpt);
+
   if (target_supports_enable_disable_tracepoint ()
       && current_trace_status ()->running && is_tracepoint (bpt))
     {
@@ -12903,7 +13579,11 @@ disable_command (char *args, int from_tty)
       struct bp_location *loc = find_location_by_number (args);
       if (loc)
        {
-         loc->enabled = 0;
+         if (loc->enabled)
+           {
+             loc->enabled = 0;
+             mark_breakpoint_location_modified (loc);
+           }
          if (target_supports_enable_disable_tracepoint ()
              && current_trace_status ()->running && loc->owner
              && is_tracepoint (loc->owner))
@@ -12960,6 +13640,11 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition,
   if (bpt->enable_state != bp_permanent)
     bpt->enable_state = bp_enabled;
 
+  bpt->enable_state = bp_enabled;
+
+  /* Mark breakpoint locations modified.  */
+  mark_breakpoint_modified (bpt);
+
   if (target_supports_enable_disable_tracepoint ()
       && current_trace_status ()->running && is_tracepoint (bpt))
     {
@@ -13019,7 +13704,11 @@ enable_command (char *args, int from_tty)
       struct bp_location *loc = find_location_by_number (args);
       if (loc)
        {
-         loc->enabled = 1;
+         if (!loc->enabled)
+           {
+             loc->enabled = 1;
+             mark_breakpoint_location_modified (loc);
+           }
          if (target_supports_enable_disable_tracepoint ()
              && current_trace_status ()->running && loc->owner
              && is_tracepoint (loc->owner))
@@ -14794,6 +15483,23 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
                           &breakpoint_set_cmdlist,
                           &breakpoint_show_cmdlist);
 
+  add_setshow_enum_cmd ("condition-evaluation", class_breakpoint,
+                       condition_evaluation_enums,
+                       &condition_evaluation_mode_1, _("\
+Set mode of breakpoint condition evaluation."), _("\
+Show mode of breakpoint condition evaluation."), _("\
+When this is set to \"gdb\", breakpoint conditions will be\n\
+evaluated on the host's side by GDB.  When it is set to \"target\",\n\
+breakpoint conditions will be downloaded to the target (if the target\n\
+supports such feature) and conditions will be evaluated on the target's side.\n\
+If this is set to \"auto\" (default), this will be automatically set to\n\
+\"target\" if it supports condition evaluation, otherwise it will\n\
+be set to \"gdb\""),
+                          &set_condition_evaluation_mode,
+                          &show_condition_evaluation_mode,
+                          &breakpoint_set_cmdlist,
+                          &breakpoint_show_cmdlist);
+
   add_com ("break-range", class_breakpoint, break_range_command, _("\
 Set a breakpoint for an address range.\n\
 break-range START-LOCATION, END-LOCATION\n\
index 07e3fc9..7e8c597 100644 (file)
@@ -22,6 +22,7 @@
 #include "frame.h"
 #include "value.h"
 #include "vec.h"
+#include "ax.h"
 
 struct value;
 struct block;
@@ -215,6 +216,16 @@ enum target_hw_bp_type
   };
 
 
+/* Status of breakpoint conditions used when synchronizing
+   conditions with the target.  */
+
+enum condition_status
+  {
+    condition_unchanged = 0,
+    condition_modified,
+    condition_updated
+  };
+
 /* Information used by targets to insert and remove breakpoints.  */
 
 struct bp_target_info
@@ -249,6 +260,10 @@ struct bp_target_info
      (e.g. if a remote stub handled the details).  We may still need
      the size to remove the breakpoint safely.  */
   int placed_size;
+
+  /* Vector of conditions the target should evaluate if it supports target-side
+     breakpoint conditions.  */
+  VEC(agent_expr_p) *conditions;
 };
 
 /* GDB maintains two types of information about each breakpoint (or
@@ -315,6 +330,30 @@ struct bp_location
      the owner breakpoint object.  */
   struct expression *cond;
 
+  /* Conditional expression in agent expression
+     bytecode form.  This is used for stub-side breakpoint
+     condition evaluation.  */
+  struct agent_expr *cond_bytecode;
+
+  /* Signals that the condition has changed since the last time
+     we updated the global location list.  This means the condition
+     needs to be sent to the target again.  This is used together
+     with target-side breakpoint conditions.
+
+     condition_unchanged: It means there has been no condition changes.
+
+     condition_modified: It means this location had its condition modified.
+
+     condition_updated: It means we already marked all the locations that are
+     duplicates of this location and thus we don't need to call
+     force_breakpoint_reinsertion (...) for this location.  */
+
+  enum condition_status condition_changed;
+
+  /* Signals that breakpoint conditions need to be re-synched with the
+     target.  This has no use other than target-side breakpoints.  */
+  char needs_update;
+
   /* This location's address is in an unloaded solib, and so this
      location should not be inserted.  It will be automatically
      enabled when that solib is loaded.  */
@@ -726,6 +765,11 @@ struct watchpoint
   CORE_ADDR hw_wp_mask;
 };
 
+/* Return true if BPT is either a software breakpoint or a hardware
+   breakpoint.  */
+
+extern int is_breakpoint (const struct breakpoint *bpt);
+
 /* Returns true if BPT is really a watchpoint.  */
 
 extern int is_watchpoint (const struct breakpoint *bpt);
index e094917..68c8fd2 100644 (file)
@@ -242,6 +242,8 @@ static int remote_read_description_p (struct target_ops *target);
 
 static void remote_console_output (char *msg);
 
+static int remote_supports_cond_breakpoints (void);
+
 /* The non-stop remote protocol provisions for one pending stop reply.
    This is where we keep it until it is acknowledged.  */
 
@@ -7729,6 +7731,43 @@ extended_remote_create_inferior (struct target_ops *ops,
 }
 \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 *gdbarch,
       struct remote_state *rs;
       char *p;
       int bpsize;
+      struct condition_list *cond = NULL;
 
       gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
 
@@ -7761,6 +7801,9 @@ remote_insert_breakpoint (struct gdbarch *gdbarch,
       p += hexnumstr (p, addr);
       sprintf (p, ",%d", bpsize);
 
+      if (remote_supports_cond_breakpoints ())
+       remote_add_target_side_condition (gdbarch, bp_tgt, p);
+
       putpkt (rs->buf);
       getpkt (&rs->buf, &rs->buf_size, 0);
 
@@ -7986,6 +8029,9 @@ remote_insert_hw_breakpoint (struct gdbarch *gdbarch,
   p += hexnumstr (p, (ULONGEST) addr);
   sprintf (p, ",%x", bp_tgt->placed_size);
 
+  if (remote_supports_cond_breakpoints ())
+    remote_add_target_side_condition (gdbarch, bp_tgt, p);
+
   putpkt (rs->buf);
   getpkt (&rs->buf, &rs->buf_size, 0);
 
@@ -10781,6 +10827,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_fileio_readlink = remote_hostio_readlink;
   remote_ops.to_supports_enable_disable_tracepoint = remote_supports_enable_disable_tracepoint;
   remote_ops.to_supports_string_tracing = remote_supports_string_tracing;
+  remote_ops.to_supports_evaluation_of_breakpoint_conditions = remote_supports_cond_breakpoints;
   remote_ops.to_trace_init = remote_trace_init;
   remote_ops.to_download_tracepoint = remote_download_tracepoint;
   remote_ops.to_can_download_tracepoint = remote_can_download_tracepoint;
index ad304bc..1f408f6 100644 (file)
@@ -699,6 +699,7 @@ update_current_target (void)
       INHERIT (to_static_tracepoint_markers_by_strid, t);
       INHERIT (to_traceframe_info, t);
       INHERIT (to_magic, t);
+      INHERIT (to_supports_evaluation_of_breakpoint_conditions, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
       /* Do not inherit to_flash_done.  */
@@ -925,6 +926,9 @@ update_current_target (void)
   de_fault (to_traceframe_info,
            (struct traceframe_info * (*) (void))
            tcomplain);
+  de_fault (to_supports_evaluation_of_breakpoint_conditions,
+           (int (*) (void))
+           return_zero);
   de_fault (to_execution_direction, default_execution_direction);
 
 #undef de_fault
index d4605ae..d2b5056 100644 (file)
@@ -662,6 +662,10 @@ struct target_ops
     /* Does this target support the tracenz bytecode for string collection?  */
     int (*to_supports_string_tracing) (void);
 
+    /* Does this target support evaluation of breakpoint conditions on its
+       end?  */
+    int (*to_supports_evaluation_of_breakpoint_conditions) (void);
+
     /* Determine current architecture of thread PTID.
 
        The target is supposed to determine the architecture of the code where
@@ -968,6 +972,12 @@ int target_supports_disable_randomization (void);
 #define target_supports_string_tracing() \
   (*current_target.to_supports_string_tracing) ()
 
+/* Returns true if this target can handle breakpoint conditions
+   on its end.  */
+
+#define target_supports_evaluation_of_breakpoint_conditions() \
+  (*current_target.to_supports_evaluation_of_breakpoint_conditions) ()
+
 /* Invalidate all target dcaches.  */
 extern void target_dcache_invalidate (void);