public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Breakpoint conditions at locations with differing contexts
@ 2020-07-31 15:42 Tankut Baris Aktemur
       [not found] ` <cover.1596209606.git.tankut.baris.aktemur@intel.com>
                   ` (4 more replies)
  0 siblings, 5 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-07-31 15:42 UTC (permalink / raw)
  To: gdb-patches

Hi,

This is a short series about conditional breakpoints where the
condition may be invalid at some breakpoint locations because of their
context.  Currently, GDB does not allow defining a condition if it's
not valid at all locations.  This series aims at bringing more
flexibility: the locations at which the condition expression is
invalid are disabled automatically.

The first patch is the one that implements the new behavior.
The second one is an RFC.  Depending on the community comments,
I'd like to take a direction and complete it.

Regards
Baris


Tankut Baris Aktemur (2):
  gdb/breakpoint: disable a bp location if condition is invalid at that
    location
  gdb/breakpoint: add a '-force' flag to the 'condition' command

 gdb/ada-lang.c                                |   2 +-
 gdb/breakpoint.c                              | 224 ++++++++++++++----
 gdb/breakpoint.h                              |  12 +-
 gdb/doc/gdb.texinfo                           |   6 +
 gdb/guile/scm-breakpoint.c                    |   2 +-
 gdb/python/py-breakpoint.c                    |   2 +-
 .../condbreak-multi-context-included.c        |  18 ++
 .../gdb.base/condbreak-multi-context.c        |  51 ++++
 .../gdb.base/condbreak-multi-context.exp      | 218 +++++++++++++++++
 9 files changed, 478 insertions(+), 57 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context-included.c
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.c
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
       [not found] ` <cover.1596209606.git.tankut.baris.aktemur@intel.com>
@ 2020-07-31 15:42   ` Tankut Baris Aktemur
  2020-07-31 15:42   ` [RFC][PATCH 2/2] gdb/breakpoint: add a '-force' flag to the 'condition' command Tankut Baris Aktemur
  1 sibling, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-07-31 15:42 UTC (permalink / raw)
  To: gdb-patches

Currently, for a conditional breakpoint, GDB checks if the condition
can be evaluated in the context of the first symtab and line (SAL).
In case of an error, defining the conditional breakpoint is aborted.
This prevents having a conditional breakpoint whose condition may
actually be meaningful for some of the location contexts.  This patch
makes it possible to define conditional BPs by checking all location
contexts.  If the condition is meaningful for even one context, the
breakpoint is defined.  The locations for which the condition gives
errors are disabled.

The bp_location struct is introduced a new field, 'disabled_by_cond'.
This field denotes whether the location is disabled automatically
because the condition was non-evaluatable.  Disabled-by-cond locations
cannot be enabled by the user.  But locations that are not
disabled-by-cond can be enabled/disabled by the user manually as
before.

For a concrete example, consider 3 contexts; func1, func2, and func3.
Each context contains instructions coming from the same source.
For instance:

  void
  func1 (int *value)
  {
    int a = 10;
    value += a;
    int b = 1;
  #include "included.c"
  }

  void
  func2 (int *value)
  {
    int b = 2;
  #include "included.c"
  }

  void
  func3 (int *value)
  {
    int c = 30;
    value += c;
    int b = 3;
  #include "included.c"
  }

Note that

* the variable 'a' is defined only in the context defined by func1.
* the variable 'c' is defined only in the context defined by func3.
* the variable 'b' is defined in all the three contexts.

With the existing GDB, it's not possible to define a conditional
breakpoint at "included.c:1" if the condition refers to 'a' or 'c':

  (gdb) break included.c:1 if a == 10
  No symbol "a" in current context.
  (gdb) break included.c:1 if c == 30
  No symbol "c" in current context.
  (gdb) info breakpoints
  No breakpoints or watchpoints.

With this patch, it becomes possible:

  (gdb) break included.c:1 if a == 10
  warning: disabling breakpoint location 2: No symbol "a" in current context.
  warning: disabling breakpoint location 3: No symbol "a" in current context.
  Breakpoint 1 at 0x117d: included.c:1. (3 locations)
  (gdb) break included.c:1 if c == 30
  Note: breakpoint 1 also set at pc 0x117d.
  warning: disabling breakpoint location 1: No symbol "c" in current context.
  Note: breakpoint 1 also set at pc 0x119c.
  warning: disabling breakpoint location 2: No symbol "c" in current context.
  Note: breakpoint 1 also set at pc 0x11cf.
  Breakpoint 2 at 0x117d: included.c:1. (3 locations)
  (gdb) info break
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         y   0x000000000000117d in func1 at included.c:1
  1.2                         n   0x000000000000119c in func2 at included.c:1
  1.3                         n   0x00000000000011cf in func3 at included.c:1
  2       breakpoint     keep y   <MULTIPLE>
          stop only if c == 30
  2.1                         n   0x000000000000117d in func1 at included.c:1
  2.2                         n   0x000000000000119c in func2 at included.c:1
  2.3                         y   0x00000000000011cf in func3 at included.c:1

Executing the code hits the breakpoints 1.1 and 2.3 as expected.

Defining a condition on an unconditional breakpoint gives the same
behavior above:

  (gdb) break included.c:1
  Breakpoint 1 at 0x117d: included.c:1. (3 locations)
  (gdb) cond 1 a == 10
  warning: disabling breakpoint 1.2: No symbol "a" in current context.
  warning: disabling breakpoint 1.3: No symbol "a" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         y   0x000000000000117d in func1 at included.c:1
  1.2                         n   0x000000000000119c in func2 at included.c:1
  1.3                         n   0x00000000000011cf in func3 at included.c:1

Locations that are disabled because of a condition cannot be enabled
by the user:

  ...
  (gdb) enable 1.2
  Location is disabled because of the condition; cannot enable manually.

Resetting the condition enables the locations back:

  ...
  (gdb) cond 1
  Breakpoint 1.2 is now enabled.
  Breakpoint 1.3 is now enabled.
  Breakpoint 1 now unconditional.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
  1.1                         y   0x000000000000117d in func1 at included.c:1
  1.2                         y   0x000000000000119c in func2 at included.c:1
  1.3                         y   0x00000000000011cf in func3 at included.c:1

If a location is disabled by the user, a condition can still be defined
but the location will remain disabled even if the condition is meaningful
for the disabled location:

  ...
  (gdb) disable 1.1
  (gdb) cond 1 a == 10
  warning: disabling breakpoint 1.2: No symbol "a" in current context.
  warning: disabling breakpoint 1.3: No symbol "a" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         n   0x000000000000117d in func1 at included.c:1
  1.2                         n   0x000000000000119c in func2 at included.c:1
  1.3                         n   0x00000000000011cf in func3 at included.c:1

The condition of a breakpoint can be changed.  Locations'
enable/disable states are updated accordingly.

  ...
  (gdb) cond 1 c == 30
  warning: disabling breakpoint 1.1: No symbol "c" in current context.
  warning: disabling breakpoint 1.2: No symbol "c" in current context.
  Breakpoint 1.3 is now enabled.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if c == 30
  1.1                         n   0x000000000000117d in func1 at included.c:1
  1.2                         n   0x000000000000119c in func2 at included.c:1
  1.3                         y   0x00000000000011cf in func3 at included.c:1
  (gdb) cond 1 b == 20
  Breakpoint 1.2 is now enabled.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if b == 20
  1.1                         n   0x000000000000117d in func1 at included.c:1
  1.2                         y   0x000000000000119c in func2 at included.c:1
  1.3                         y   0x00000000000011cf in func3 at included.c:1
  # Note that location 1.1 was disabled by the user previously.

If the condition expression is bad for all the locations, it will be
rejected.

  (gdb) cond 1 garbage
  No symbol "garbage" in current context.

For conditions that are invalid or valid for all the locations of a
breakpoint, the existing behavior is preserved.

Regression-tested on X86_64 Linux.

gdb/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (class bp_location) <disabled_by_cond>: New field.
	* breakpoint.c (set_breakpoint_location_condition): New function.
	(set_breakpoint_condition): Disable a breakpoint
	location if parsing the condition string gives an error.
	(should_be_inserted): Update to consider the 'disabled_by_cond' field.
	(build_target_condition_list): Ditto.
	(build_target_command_list): Ditto.
	(build_bpstat_chain): Ditto.
	(print_one_breakpoint_location): Ditto.
	(print_one_breakpoint): Ditto.
	(bp_location::bp_location): Ditto.
	(locations_are_equal): Ditto.
	(update_breakpoint_locations): Ditto.
	(enable_disable_bp_num_loc): Ditto.
	(init_breakpoint_sal): Use set_breakpoint_location_condition.
	(find_condition_and_thread_for_sals): New static function.
	(create_breakpoint): Call find_condition_and_thread_for_sals.
	(location_to_sals): Call find_condition_and_thread_for_sals instead
	of find_condition_and_thread.

gdb/testsuite/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.base/condbreak-multi-context-included.c: New file.
	* gdb.base/condbreak-multi-context.c: New file.
	* gdb.base/condbreak-multi-context.exp: New file.
---
 gdb/breakpoint.c                              | 201 ++++++++++++----
 gdb/breakpoint.h                              |   6 +
 .../condbreak-multi-context-included.c        |  18 ++
 .../gdb.base/condbreak-multi-context.c        |  51 ++++
 .../gdb.base/condbreak-multi-context.exp      | 218 ++++++++++++++++++
 5 files changed, 446 insertions(+), 48 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context-included.c
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.c
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 977599db1db..7abfd510abc 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -830,6 +830,48 @@ get_first_locp_gte_addr (CORE_ADDR address)
   return locp_found;
 }
 
+/* Parse COND_STRING in the context of LOC and set as the condition
+   expression of LOC.  BP_NUM is the number of LOC's owner, LOC_NUM is
+   the number of LOC within its owner.  In case of parsing error, mark
+   LOC as DISABLED_BY_COND.  In case of success, unset DISABLED_BY_COND.  */
+
+static void
+set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
+				   int bp_num, int loc_num)
+{
+  bool has_junk = false;
+  try
+    {
+      expression_up new_exp = parse_exp_1 (&cond_string, loc->address,
+					   block_for_pc (loc->address), 0);
+      if (*cond_string != 0)
+	has_junk = true;
+      else
+	{
+	  loc->cond = std::move (new_exp);
+	  if (loc->disabled_by_cond && loc->enabled)
+	    printf_filtered (_("Breakpoint %d.%d is now enabled.\n"),
+			     bp_num, loc_num);
+
+	  loc->disabled_by_cond = false;
+	}
+    }
+  catch (const gdb_exception_error &e)
+    {
+      if (bp_num != 0)
+	warning (_("disabling breakpoint %d.%d: %s"),
+		 bp_num, loc_num, e.what ());
+      else
+	warning (_("disabling breakpoint location %d: %s"),
+		 loc_num, e.what ());
+
+      loc->disabled_by_cond = true;
+    }
+
+  if (has_junk)
+    error (_("Garbage '%s' follows condition"), cond_string);
+}
+
 void
 set_breakpoint_condition (struct breakpoint *b, const char *exp,
 			  int from_tty)
@@ -843,9 +885,15 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	static_cast<watchpoint *> (b)->cond_exp.reset ();
       else
 	{
+	  int loc_num = 1;
 	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
 	    {
 	      loc->cond.reset ();
+	      if (loc->disabled_by_cond && loc->enabled)
+		printf_filtered (_("Breakpoint %d.%d is now enabled.\n"),
+				 b->number, loc_num);
+	      loc->disabled_by_cond = false;
+	      loc_num++;
 
 	      /* No need to free the condition agent expression
 		 bytecode (if we have one).  We will handle this
@@ -873,29 +921,37 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	{
 	  /* Parse and set condition expressions.  We make two passes.
 	     In the first, we parse the condition string to see if it
-	     is valid in all locations.  If so, the condition would be
-	     accepted.  So we go ahead and set the locations'
-	     conditions.  In case a failing case is found, we throw
+	     is valid in at least one location.  If so, the condition
+	     would be accepted.  So we go ahead and set the locations'
+	     conditions.  In case no valid case is found, we throw
 	     the error and the condition string will be rejected.
 	     This two-pass approach is taken to avoid setting the
 	     state of locations in case of a reject.  */
 	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
 	    {
-	      const char *arg = exp;
-	      parse_exp_1 (&arg, loc->address,
-			   block_for_pc (loc->address), 0);
-	      if (*arg != 0)
-		error (_("Junk at end of expression"));
+	      try
+		{
+		  const char *arg = exp;
+		  parse_exp_1 (&arg, loc->address,
+			       block_for_pc (loc->address), 0);
+		  if (*arg != 0)
+		    error (_("Junk at end of expression"));
+		  break;
+		}
+	      catch (const gdb_exception_error &e)
+		{
+		  /* Condition string is invalid.  If this happens to
+		     be the last loc, abandon.  */
+		  if (loc->next == nullptr)
+		    throw;
+		}
 	    }
 
-	  /* If we reach here, the condition is valid at all locations.  */
-	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
-	    {
-	      const char *arg = exp;
-	      loc->cond =
-		parse_exp_1 (&arg, loc->address,
-			     block_for_pc (loc->address), 0);
-	    }
+	  /* If we reach here, the condition is valid at some locations.  */
+          int loc_num = 1;
+          for (bp_location *loc = b->loc; loc != nullptr;
+               loc = loc->next, loc_num++)
+            set_breakpoint_location_condition (exp, loc, b->number, loc_num);
 	}
 
       /* We know that the new condition parsed successfully.  The
@@ -2000,7 +2056,8 @@ should_be_inserted (struct bp_location *bl)
   if (bl->owner->disposition == disp_del_at_next_stop)
     return 0;
 
-  if (!bl->enabled || bl->shlib_disabled || bl->duplicate)
+  if (!bl->enabled || bl->disabled_by_cond
+      || bl->shlib_disabled || bl->duplicate)
     return 0;
 
   if (user_breakpoint_p (bl->owner) && bl->pspace->executing_startup)
@@ -2205,7 +2262,8 @@ build_target_condition_list (struct bp_location *bl)
 	  && is_breakpoint (loc->owner)
 	  && loc->pspace->num == bl->pspace->num
 	  && loc->owner->enable_state == bp_enabled
-	  && loc->enabled)
+	  && loc->enabled
+	  && !loc->disabled_by_cond)
 	{
 	  /* Add the condition to the vector.  This will be used later
 	     to send the conditions to the target.  */
@@ -2395,7 +2453,8 @@ build_target_command_list (struct bp_location *bl)
 	  && is_breakpoint (loc->owner)
 	  && loc->pspace->num == bl->pspace->num
 	  && loc->owner->enable_state == bp_enabled
-	  && loc->enabled)
+	  && loc->enabled
+	  && !loc->disabled_by_cond)
 	{
 	  /* Add the command to the vector.  This will be used later
 	     to send the commands to the target.  */
@@ -5278,7 +5337,7 @@ build_bpstat_chain (const address_space *aspace, CORE_ADDR bp_addr,
 	  if (b->type == bp_hardware_watchpoint && bl != b->loc)
 	    break;
 
-	  if (!bl->enabled || bl->shlib_disabled)
+	  if (!bl->enabled || bl->disabled_by_cond || bl->shlib_disabled)
 	    continue;
 
 	  if (!bpstat_check_location (bl, aspace, bp_addr, ws))
@@ -5985,7 +6044,8 @@ print_one_breakpoint_location (struct breakpoint *b,
      breakpoints with single disabled location.  */
   if (loc == NULL 
       && (b->loc != NULL 
-	  && (b->loc->next != NULL || !b->loc->enabled)))
+	  && (b->loc->next != NULL
+	      || !b->loc->enabled || b->loc->disabled_by_cond)))
     header_of_multiple = 1;
   if (loc == NULL)
     loc = b->loc;
@@ -6016,7 +6076,8 @@ print_one_breakpoint_location (struct breakpoint *b,
   /* 4 */
   annotate_field (3);
   if (part_of_multiple)
-    uiout->field_string ("enabled", loc->enabled ? "y" : "n");
+    uiout->field_string ("enabled",
+			 (loc->enabled && !loc->disabled_by_cond) ? "y" : "n");
   else
     uiout->field_fmt ("enabled", "%c", bpenables[(int) b->enable_state]);
 
@@ -6316,7 +6377,9 @@ print_one_breakpoint (struct breakpoint *b,
 	  && (!is_catchpoint (b) || is_exception_catchpoint (b)
 	      || is_ada_exception_catchpoint (b))
 	  && (allflag
-	      || (b->loc && (b->loc->next || !b->loc->enabled))))
+	      || (b->loc && (b->loc->next
+			     || !b->loc->enabled
+			     || b->loc->disabled_by_cond))))
 	{
 	  gdb::optional<ui_out_emit_list> locations_list;
 
@@ -6958,6 +7021,7 @@ bp_location::bp_location (breakpoint *owner, bp_loc_type type)
   this->cond_bytecode = NULL;
   this->shlib_disabled = 0;
   this->enabled = 1;
+  this->disabled_by_cond = false;
 
   this->loc_type = type;
 
@@ -8766,9 +8830,11 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 
   gdb_assert (!sals.empty ());
 
+  int loc_num = 0;
   for (const auto &sal : sals)
     {
       struct bp_location *loc;
+      loc_num++;
 
       if (from_tty)
 	{
@@ -8841,14 +8907,8 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 	}
 
       if (b->cond_string)
-	{
-	  const char *arg = b->cond_string;
-
-	  loc->cond = parse_exp_1 (&arg, loc->address,
-				   block_for_pc (loc->address), 0);
-	  if (*arg)
-              error (_("Garbage '%s' follows condition"), arg);
-	}
+	set_breakpoint_location_condition (b->cond_string, loc,
+					   b->number, loc_num);
 
       /* Dynamic printf requires and uses additional arguments on the
 	 command line, otherwise it's an error.  */
@@ -9151,6 +9211,50 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
     }
 }
 
+/* Call 'find_condition_and_thread' for each sal in SALS until a parse
+   succeeds.  The parsed values are written to COND_STRING, THREAD,
+   TASK, and REST.  See the comment of 'find_condition_and_thread'
+   for the description of these parameters and INPUT.  */
+
+static void
+find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
+				    const char *input, char **cond_string,
+				    int *thread, int *task, char **rest)
+{
+  int num_failures = 0;
+  for (auto &sal : sals)
+    {
+      char *cond = nullptr;
+      int thread_id = 0;
+      int task_id = 0;
+      char *remaining = nullptr;
+
+      /* Here we want to parse 'arg' to separate condition from thread
+	 number.  But because parsing happens in a context and the
+	 contexts of sals might be different, try each until there is
+	 success.  Finding one successful parse is sufficient for our
+	 goal.  When setting the breakpoint we'll re-parse the
+	 condition in the context of each sal.  */
+      try
+	{
+	  find_condition_and_thread (input, sal.pc, &cond, &thread_id,
+				     &task_id, &remaining);
+	  *cond_string = cond;
+	  *thread = thread_id;
+	  *task = task_id;
+	  *rest = remaining;
+	  break;
+	}
+      catch (const gdb_exception_error &e)
+	{
+	  num_failures++;
+	  /* If no sal remains, do not continue.  */
+	  if (num_failures == sals.size ())
+	    throw;
+	}
+    }
+}
+
 /* Decode a static tracepoint marker spec.  */
 
 static std::vector<symtab_and_line>
@@ -9314,13 +9418,8 @@ create_breakpoint (struct gdbarch *gdbarch,
 
 	  const linespec_sals &lsal = canonical.lsals[0];
 
-	  /* Here we only parse 'arg' to separate condition
-	     from thread number, so parsing in context of first
-	     sal is OK.  When setting the breakpoint we'll
-	     re-parse it in context of each sal.  */
-
-	  find_condition_and_thread (extra_string, lsal.sals[0].pc,
-				     &cond, &thread, &task, &rest);
+	  find_condition_and_thread_for_sals (lsal.sals, extra_string,
+					      &cond, &thread, &task, &rest);
 	  cond_string_copy.reset (cond);
 	  extra_string_copy.reset (rest);
         }
@@ -13434,6 +13533,9 @@ locations_are_equal (struct bp_location *a, struct bp_location *b)
       if (a->enabled != b->enabled)
 	return 0;
 
+      if (a->disabled_by_cond != b->disabled_by_cond)
+	return 0;
+
       a = a->next;
       b = b->next;
     }
@@ -13541,10 +13643,7 @@ update_breakpoint_locations (struct breakpoint *b,
 	    }
 	  catch (const gdb_exception_error &e)
 	    {
-	      warning (_("failed to reevaluate condition "
-			 "for breakpoint %d: %s"), 
-		       b->number, e.what ());
-	      new_loc->enabled = 0;
+	      new_loc->disabled_by_cond = true;
 	    }
 	}
 
@@ -13569,7 +13668,7 @@ update_breakpoint_locations (struct breakpoint *b,
 
     for (; e; e = e->next)
       {
-	if (!e->enabled && e->function_name)
+	if ((!e->enabled || e->disabled_by_cond) && e->function_name)
 	  {
 	    struct bp_location *l = b->loc;
 	    if (have_ambiguous_names)
@@ -13585,7 +13684,8 @@ update_breakpoint_locations (struct breakpoint *b,
 		       enough.  */
 		    if (breakpoint_locations_match (e, l, true))
 		      {
-			l->enabled = 0;
+			l->enabled = e->enabled;
+			l->disabled_by_cond = e->disabled_by_cond;
 			break;
 		      }
 		  }
@@ -13596,7 +13696,8 @@ update_breakpoint_locations (struct breakpoint *b,
 		  if (l->function_name
 		      && strcmp (e->function_name, l->function_name) == 0)
 		    {
-		      l->enabled = 0;
+		      l->enabled = e->enabled;
+		      l->disabled_by_cond = e->disabled_by_cond;
 		      break;
 		    }
 	      }
@@ -13670,9 +13771,9 @@ location_to_sals (struct breakpoint *b, struct event_location *location,
 	  char *cond_string, *extra_string;
 	  int thread, task;
 
-	  find_condition_and_thread (b->extra_string, sals[0].pc,
-				     &cond_string, &thread, &task,
-				     &extra_string);
+	  find_condition_and_thread_for_sals (sals, b->extra_string,
+					      &cond_string, &thread,
+					      &task, &extra_string);
 	  gdb_assert (b->cond_string == NULL);
 	  if (cond_string)
 	    b->cond_string = cond_string;
@@ -14157,6 +14258,10 @@ enable_disable_bp_num_loc (int bp_num, int loc_num, bool enable)
   struct bp_location *loc = find_location_by_number (bp_num, loc_num);
   if (loc != NULL)
     {
+      if (loc->disabled_by_cond && enable)
+	error(_("Location is disabled because of the condition; "
+		"cannot enable manually."));
+
       if (loc->enabled != enable)
 	{
 	  loc->enabled = enable;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 347aeb75f30..145bc8a397a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -387,6 +387,12 @@ class bp_location
   /* Is this particular location enabled.  */
   bool enabled = false;
   
+  /* Is this particular location disabled because the condition
+     expression is invalid at this location.  For a location to be
+     reported as enabled, the ENABLED field above has to be true *and*
+     the DISABLED_BY_COND field has to be false.  */
+  bool disabled_by_cond = false;
+
   /* True if this breakpoint is now inserted.  */
   bool inserted = false;
 
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context-included.c b/gdb/testsuite/gdb.base/condbreak-multi-context-included.c
new file mode 100644
index 00000000000..810943eda10
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context-included.c
@@ -0,0 +1,18 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+value += b; /* breakpoint-here */
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.c b/gdb/testsuite/gdb.base/condbreak-multi-context.c
new file mode 100644
index 00000000000..42a445a2d7d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.c
@@ -0,0 +1,51 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+void
+func1 (int *value)
+{
+  int a = 10;
+  value += a;
+  int b = 1;
+#include "condbreak-multi-context-included.c"
+}
+
+void
+func2 (int *value)
+{
+  int b = 2;
+#include "condbreak-multi-context-included.c"
+}
+
+void
+func3 (int *value)
+{
+  int c = 30;
+  value += c;
+  int b = 3;
+#include "condbreak-multi-context-included.c"
+}
+
+int
+main ()
+{
+  int val = 0;
+  func1 (&val);
+  func2 (&val);
+  func3 (&val);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
new file mode 100644
index 00000000000..b02a0a2e40c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -0,0 +1,218 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test defining a conditional breakpoint that applies to multiple
+# locations with different contexts (e.g. different set of local vars).
+
+standard_testfile condbreak-multi-context.c condbreak-multi-context-included.c
+
+if {[prepare_for_testing "failed to prepare" ${binfile} ${srcfile}]} {
+    return
+}
+
+set warning "warning: disabling breakpoint"
+set fill "\[^\r\n\]*"
+
+set bp_location [gdb_get_line_number "breakpoint-here" $srcfile2]
+
+# Check that breakpoints are as expected.
+
+proc test_info_break {suffix} {
+    global bpnum1 bpnum2 fill
+
+    set bp_hit_info "${fill}(\r\n${fill}breakpoint already hit 1 time)?"
+
+    gdb_test "info break ${bpnum1} ${bpnum2}" \
+	[multi_line \
+	     "Num${fill}" \
+	     "${bpnum1}${fill}breakpoint${fill}keep y${fill}MULTIPLE${fill}" \
+	     "${fill}stop only if a == 10${bp_hit_info}" \
+	     "${bpnum1}.1${fill}y${fill}func1${fill}" \
+	     "${bpnum1}.2${fill}n${fill}func2${fill}" \
+	     "${bpnum1}.3${fill}n${fill}func3${fill}" \
+	     "${bpnum2}${fill}breakpoint${fill}keep y${fill}MULTIPLE${fill}" \
+	     "${fill}stop only if c == 30${bp_hit_info}" \
+	     "${bpnum2}.1${fill}n${fill}func1${fill}" \
+	     "${bpnum2}.2${fill}n${fill}func2${fill}" \
+	     "${bpnum2}.3${fill}y${fill}func3${fill}"] \
+	"info break $suffix"
+}
+
+# Scenario 1: Define breakpoints conditionally, using the "break N if
+# cond" syntax.  Run the program, check that we hit those locations
+# only.
+
+with_test_prefix "scenario 1" {
+    # Define the conditional breakpoints.
+    gdb_test "break $srcfile2:$bp_location if a == 10" \
+	[multi_line \
+	     "${warning} location 2: No symbol \"a\" in current context." \
+	     "${warning} location 3: No symbol \"a\" in current context." \
+	     "Breakpoint $decimal at $fill .3 locations."] \
+	"define bp with condition a == 10"
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+
+    gdb_test "break $srcfile2:$bp_location if c == 30" \
+	[multi_line \
+	     ".*${warning} location 1: No symbol \"c\" in current context." \
+	     ".*${warning} location 2: No symbol \"c\" in current context." \
+	     ".*Breakpoint $decimal at $fill .3 locations."] \
+	"define bp with condition c == 30"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+
+    test_info_break 1
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_run_cmd
+
+    # Check our conditional breakpoints.
+    gdb_test "" ".*Breakpoint \[0-9\]+, func1 .*" \
+	"run until func1"
+    gdb_test "print a" " = 10"
+
+    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, func3 .*" \
+	"run until func3"
+    gdb_test "print c" " = 30"
+
+    # No more hits!
+    gdb_continue_to_end
+
+    test_info_break 2
+}
+
+# Start GDB with two breakpoints and define the conditions separately.
+
+proc setup_bps {} {
+    global srcfile binfile srcfile2
+    global bpnum1 bpnum2 bp_location warning
+
+    clean_restart ${binfile}
+
+    # Define the breakpoints.
+    gdb_breakpoint "$srcfile2:$bp_location"
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+
+    gdb_breakpoint "$srcfile2:$bp_location"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+
+    # Defining a condition on 'a' disables 2 locations.
+    gdb_test "cond $bpnum1 a == 10" \
+	[multi_line \
+	     "$warning ${bpnum1}.2: No symbol \"a\" in current context." \
+	     "$warning ${bpnum1}.3: No symbol \"a\" in current context."]
+
+    # Defining a condition on 'c' disables 2 locations.
+    gdb_test "cond $bpnum2 c == 30" \
+	[multi_line \
+	     "$warning ${bpnum2}.1: No symbol \"c\" in current context." \
+	     "$warning ${bpnum2}.2: No symbol \"c\" in current context."]
+}
+
+# Scenario 2: Define breakpoints unconditionally, and then define
+# conditions using the "cond N <cond>" syntax.  Expect that the
+# locations where <cond> is not evaluatable are disabled.  Run the
+# program, check that we hit the enabled locations only.
+
+with_test_prefix "scenario 2" {
+    setup_bps
+
+    test_info_break 1
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_run_cmd
+
+    # Check that we hit enabled locations only.
+    gdb_test "" ".*Breakpoint \[0-9\]+, func1 .*" \
+	"run until func1"
+    gdb_test "print a" " = 10"
+
+    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, func3 .*" \
+	"run until func3"
+    gdb_test "print c" " = 30"
+
+    # No more hits!
+    gdb_continue_to_end
+
+    test_info_break 2
+}
+
+# Test the breakpoint location enabled states.
+
+proc check_bp_locations {bpnum states msg} {
+    global fill
+
+    set expected  ".*${bpnum}.1${fill} [lindex $states 0] ${fill}\r\n"
+    append expected "${bpnum}.2${fill} [lindex $states 1] ${fill}\r\n"
+    append expected "${bpnum}.3${fill} [lindex $states 2] ${fill}"
+
+    gdb_test "info break $bpnum" $expected "check bp $bpnum $msg"
+}
+
+# Scenario 3: Apply misc. checks on the already-defined breakpoints.
+
+with_test_prefix "scenario 3" {
+    setup_bps
+
+    gdb_test "cond $bpnum1 c == 30" \
+	[multi_line \
+	     "${warning} 1.1: No symbol \"c\" in current context." \
+	     "${warning} 1.2: No symbol \"c\" in current context." \
+	     "Breakpoint 1.3 is now enabled."] \
+	"change the condition of bp 1"
+    check_bp_locations $bpnum1 {n n y} "after changing the condition"
+
+    gdb_test "cond $bpnum1" \
+	[multi_line \
+	     "Breakpoint 1.1 is now enabled." \
+	     "Breakpoint 1.2 is now enabled." \
+	     "Breakpoint 1 now unconditional."] \
+	"reset the condition of bp 1"
+    check_bp_locations $bpnum1 {y y y} "after resetting the condition"
+
+    gdb_test_no_output "disable ${bpnum2}.2"
+    check_bp_locations $bpnum2 {n n y} "after disabling loc 2"
+
+    gdb_test "cond $bpnum2" ".*" "reset the condition of bp 2"
+    check_bp_locations $bpnum2 {y n y} "loc 2 should remain disabled"
+
+    gdb_test_no_output "disable ${bpnum2}.3"
+    check_bp_locations $bpnum2 {y n n} "after disabling loc 3"
+
+    gdb_test "cond $bpnum2 c == 30" \
+	[multi_line \
+	     "${warning} 2.1: No symbol \"c\" in current context." \
+	     "${warning} 2.2: No symbol \"c\" in current context."] \
+	"re-define a condition"
+    check_bp_locations $bpnum2 {n n n} "loc 3 should remain disabled"
+
+    gdb_test "enable ${bpnum2}.1" \
+	"Location is disabled because of the condition; cannot enable manually." \
+	"reject enabling a location that is disabled-by-cond"
+    check_bp_locations $bpnum2 {n n n} "after enable attempt"
+
+    gdb_test "cond $bpnum2 garbage" \
+	"No symbol \"garbage\" in current context." \
+	"reject condition if bad for all locations"
+
+    gdb_test_no_output "delete $bpnum1"
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_breakpoint "main"
+    gdb_run_cmd
+    gdb_test "" ".*reakpoint .*, main .*${srcfile}.*" "start"
+
+    # The second BP's locations are all disabled.  No more hits!
+    gdb_continue_to_end
+}
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [RFC][PATCH 2/2] gdb/breakpoint: add a '-force' flag to the 'condition' command
       [not found] ` <cover.1596209606.git.tankut.baris.aktemur@intel.com>
  2020-07-31 15:42   ` [PATCH 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
@ 2020-07-31 15:42   ` Tankut Baris Aktemur
  2020-08-03 10:28     ` Andrew Burgess
  1 sibling, 1 reply; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-07-31 15:42 UTC (permalink / raw)
  To: gdb-patches

The previous patch made it possible to define a condition if it's
valid at some locations.  If the condition is invalid at all of the
locations, it's rejected.  However, there may be cases where the user
knows the condition will be valid at a location in the *future*,
e.g. due to a shared library load.

To make it possible that such condition is defined, this patch
adds an optional '-force' flag to the 'condition' command.  When this
command is passed, the condition is not rejected even when it is
invalid for all the current locations (note that all the locations
would be internally disabled in this case).

For instance:

  (gdb) break test.c:5
  Breakpoint 1 at 0x1155: file test.c, line 5.
  (gdb) cond 1 foo == 42
  No symbol "foo" in current context.

Defining the condition was not possible because 'foo' is not
available.  The user can override this behavior with the '-force'
flag:

  (gdb) cond -force 1 foo == 42
  warning: disabling breakpoint 1.1: No symbol "foo" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if foo == 42
  1.1                         n   0x0000000000001155 in main at test.c:5

Now the condition is accepted, but the location is automatically
disabled.  If a future location has a context in which 'foo' is
available, that location would be enabled.

This is an RFC.  If the idea of having this '-force' flag makes sense,
I could also work on the same feature for the 'break' command, write
test cases, and submit as a full patch.

Another potentially interesting approach is to query the user.
Something along the following idea:

  (gdb) cond 1 foo == 42
  Condition expression is invalid at all locations of breakpoint 1.
  Do you want force GDB to nevertheless define the condition, but
  disable the current locations? [y/N] y
  warning: disabling breakpoint 1.1: No symbol "foo" in current context.

This query approach may break some scripts because it is changing the
existing behavior.

gdb/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (set_breakpoint_condition): Add a new bool parameter.
	* breakpoint.c (set_breakpoint_condition): Take a new bool parameter
	to control whether condition definition should be forced even when
	the condition expression is invalid in all of the current locations.
	(condition_command): Update the call to 'set_breakpoint_condition'.
	* ada-lang.c (create_ada_exception_catchpoint): Ditto.
	* guile/scm-breakpoint.c (gdbscm_set_breakpoint_condition_x): Ditto.
	* python/py-breakpoint.c (bppy_set_condition): Ditto.

gdb/doc/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo: Document the '-force' flag of the 'condition' command.
---
 gdb/ada-lang.c             |  2 +-
 gdb/breakpoint.c           | 28 ++++++++++++++++++++++------
 gdb/breakpoint.h           |  6 ++++--
 gdb/doc/gdb.texinfo        |  6 ++++++
 gdb/guile/scm-breakpoint.c |  2 +-
 gdb/python/py-breakpoint.c |  2 +-
 6 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 29951528e5e..69b3c3c63cd 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12702,7 +12702,7 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
   c->excep_string = excep_string;
   create_excep_cond_exprs (c.get (), ex_kind);
   if (!cond_string.empty ())
-    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty);
+    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty, false);
   install_breakpoint (0, std::move (c), 1);
 }
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 7abfd510abc..5fe9358b381 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -874,7 +874,7 @@ set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
 
 void
 set_breakpoint_condition (struct breakpoint *b, const char *exp,
-			  int from_tty)
+			  int from_tty, bool force)
 {
   if (*exp == 0)
     {
@@ -941,9 +941,11 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	      catch (const gdb_exception_error &e)
 		{
 		  /* Condition string is invalid.  If this happens to
-		     be the last loc, abandon.  */
+		     be the last loc, abandon (if not forced) or continue
+		     (if forced).  */
 		  if (loc->next == nullptr)
-		    throw;
+		    if (!force)
+		      throw;
 		}
 	    }
 
@@ -1023,6 +1025,18 @@ condition_command (const char *arg, int from_tty)
     error_no_arg (_("breakpoint number"));
 
   p = arg;
+
+  /* Check if the "-force" flag was passed.  */
+  bool force = false;
+  const char *tok = skip_spaces (p);
+  const char *end_tok = skip_to_space (tok);
+  int toklen = end_tok - tok;
+  if (toklen >= 1 && strncmp (tok, "-force", toklen) == 0)
+    {
+      force = true;
+      p = end_tok + 1;
+    }
+
   bnum = get_number (&p);
   if (bnum == 0)
     error (_("Bad breakpoint argument: '%s'"), arg);
@@ -1042,7 +1056,7 @@ condition_command (const char *arg, int from_tty)
 		     " a %s stop condition defined for this breakpoint."),
 		   ext_lang_capitalized_name (extlang));
 	  }
-	set_breakpoint_condition (b, p, from_tty);
+	set_breakpoint_condition (b, p, from_tty, force);
 
 	if (is_breakpoint (b))
 	  update_global_location_list (UGLL_MAY_INSERT);
@@ -15576,8 +15590,10 @@ then no output is printed when it is hit, except what the commands print."));
 
   c = add_com ("condition", class_breakpoint, condition_command, _("\
 Specify breakpoint number N to break only if COND is true.\n\
-Usage is `condition N COND', where N is an integer and COND is an\n\
-expression to be evaluated whenever breakpoint N is reached."));
+Usage is `condition [-force] N COND', where N is an integer and COND\n\
+is an expression to be evaluated whenever breakpoint N is reached.\n\
+With the `-force` flag, the condition is defined even when it is\n\
+invalid for all current locations."));
   set_cmd_completer (c, condition_completer);
 
   c = add_com ("tbreak", class_breakpoint, tbreak_command, _("\
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 145bc8a397a..6acec428a9a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1617,9 +1617,11 @@ extern int breakpoints_should_be_inserted_now (void);
    in our opinion won't ever trigger.  */
 extern void breakpoint_retire_moribund (void);
 
-/* Set break condition of breakpoint B to EXP.  */
+/* Set break condition of breakpoint B to EXP.
+   If FORCE, define the condition even if it is invalid in
+   all of the breakpoint locations.  */
 extern void set_breakpoint_condition (struct breakpoint *b, const char *exp,
-				      int from_tty);
+				      int from_tty, bool force);
 
 /* Checks if we are catching syscalls or not.
    Returns 0 if not, greater than 0 if we are.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1b9f76573b9..a81689dab21 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -5453,6 +5453,12 @@ prints an error message:
 No symbol "foo" in current context.
 @end smallexample
 
+@item condition -force @var{bnum} @var{expression}
+When the @code{-force} flag is used, define the condition even if
+@var{expression} is invalid in all the current locations of breakpoint
+@var{bpnum}.  This is useful if it is known that @var{expression} will
+be valid for a future shared library location.
+
 @noindent
 @value{GDBN} does
 not actually evaluate @var{expression} at the time the @code{condition}
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index 96b6ca91f8d..7c9707235ec 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -905,7 +905,7 @@ gdbscm_set_breakpoint_condition_x (SCM self, SCM newvalue)
 	   ? nullptr
 	   : gdbscm_scm_to_c_string (newvalue));
 
-      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0);
+      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0, false);
 
       return SCM_UNSPECIFIED;
     });
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 11345ad3052..56640421994 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -461,7 +461,7 @@ bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
 
   try
     {
-      set_breakpoint_condition (self_bp->bp, exp, 0);
+      set_breakpoint_condition (self_bp->bp, exp, 0, false);
     }
   catch (gdb_exception &ex)
     {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [RFC][PATCH 2/2] gdb/breakpoint: add a '-force' flag to the 'condition' command
  2020-07-31 15:42   ` [RFC][PATCH 2/2] gdb/breakpoint: add a '-force' flag to the 'condition' command Tankut Baris Aktemur
@ 2020-08-03 10:28     ` Andrew Burgess
  0 siblings, 0 replies; 103+ messages in thread
From: Andrew Burgess @ 2020-08-03 10:28 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

* Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org> [2020-07-31 17:42:29 +0200]:

> The previous patch made it possible to define a condition if it's
> valid at some locations.  If the condition is invalid at all of the
> locations, it's rejected.  However, there may be cases where the user
> knows the condition will be valid at a location in the *future*,
> e.g. due to a shared library load.
> 
> To make it possible that such condition is defined, this patch
> adds an optional '-force' flag to the 'condition' command.  When this
> command is passed, the condition is not rejected even when it is
> invalid for all the current locations (note that all the locations
> would be internally disabled in this case).
> 
> For instance:
> 
>   (gdb) break test.c:5
>   Breakpoint 1 at 0x1155: file test.c, line 5.
>   (gdb) cond 1 foo == 42
>   No symbol "foo" in current context.
> 
> Defining the condition was not possible because 'foo' is not
> available.  The user can override this behavior with the '-force'
> flag:
> 
>   (gdb) cond -force 1 foo == 42
>   warning: disabling breakpoint 1.1: No symbol "foo" in current context.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if foo == 42
>   1.1                         n   0x0000000000001155 in main at test.c:5
> 
> Now the condition is accepted, but the location is automatically
> disabled.  If a future location has a context in which 'foo' is
> available, that location would be enabled.
> 
> This is an RFC.  If the idea of having this '-force' flag makes sense,
> I could also work on the same feature for the 'break' command, write
> test cases, and submit as a full patch.

I'd be happy to see the `-force` flag added, I think adding flags like
this makes perfect sense.  There's already many flags like this for
the break command so I don't see why adding one more should be a
problem.

I'd be tempted to name the flag for `break` as `-force-condition` to
make it clear what's being forced.  The flags already accept unique
sub-strings, so `-force` would still work, plus there's always
tab-completion.

> 
> Another potentially interesting approach is to query the user.
> Something along the following idea:
> 
>   (gdb) cond 1 foo == 42
>   Condition expression is invalid at all locations of breakpoint 1.
>   Do you want force GDB to nevertheless define the condition, but
>   disable the current locations? [y/N] y
>   warning: disabling breakpoint 1.1: No symbol "foo" in current context.
> 
> This query approach may break some scripts because it is changing the
> existing behavior.

Unless the script is parsing the exact output of GDB this should be a
problem.  When GDB is run in an non-interactive manor the default
answer is assumed to prompts like this, so in the above case the user
would still get the `N` behaviour.

But I wouldn't rush to add more interactive prompts to GDB personally.

These are just my thoughts.  Others might feel differently.

Thanks,
Andrew


> 
> gdb/ChangeLog:
> 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* breakpoint.h (set_breakpoint_condition): Add a new bool parameter.
> 	* breakpoint.c (set_breakpoint_condition): Take a new bool parameter
> 	to control whether condition definition should be forced even when
> 	the condition expression is invalid in all of the current locations.
> 	(condition_command): Update the call to 'set_breakpoint_condition'.
> 	* ada-lang.c (create_ada_exception_catchpoint): Ditto.
> 	* guile/scm-breakpoint.c (gdbscm_set_breakpoint_condition_x): Ditto.
> 	* python/py-breakpoint.c (bppy_set_condition): Ditto.
> 
> gdb/doc/ChangeLog:
> 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.texinfo: Document the '-force' flag of the 'condition' command.
> ---
>  gdb/ada-lang.c             |  2 +-
>  gdb/breakpoint.c           | 28 ++++++++++++++++++++++------
>  gdb/breakpoint.h           |  6 ++++--
>  gdb/doc/gdb.texinfo        |  6 ++++++
>  gdb/guile/scm-breakpoint.c |  2 +-
>  gdb/python/py-breakpoint.c |  2 +-
>  6 files changed, 35 insertions(+), 11 deletions(-)
> 
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 29951528e5e..69b3c3c63cd 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12702,7 +12702,7 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
>    c->excep_string = excep_string;
>    create_excep_cond_exprs (c.get (), ex_kind);
>    if (!cond_string.empty ())
> -    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty);
> +    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty, false);
>    install_breakpoint (0, std::move (c), 1);
>  }
>  
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 7abfd510abc..5fe9358b381 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -874,7 +874,7 @@ set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
>  
>  void
>  set_breakpoint_condition (struct breakpoint *b, const char *exp,
> -			  int from_tty)
> +			  int from_tty, bool force)
>  {
>    if (*exp == 0)
>      {
> @@ -941,9 +941,11 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
>  	      catch (const gdb_exception_error &e)
>  		{
>  		  /* Condition string is invalid.  If this happens to
> -		     be the last loc, abandon.  */
> +		     be the last loc, abandon (if not forced) or continue
> +		     (if forced).  */
>  		  if (loc->next == nullptr)
> -		    throw;
> +		    if (!force)
> +		      throw;
>  		}
>  	    }
>  
> @@ -1023,6 +1025,18 @@ condition_command (const char *arg, int from_tty)
>      error_no_arg (_("breakpoint number"));
>  
>    p = arg;
> +
> +  /* Check if the "-force" flag was passed.  */
> +  bool force = false;
> +  const char *tok = skip_spaces (p);
> +  const char *end_tok = skip_to_space (tok);
> +  int toklen = end_tok - tok;
> +  if (toklen >= 1 && strncmp (tok, "-force", toklen) == 0)
> +    {
> +      force = true;
> +      p = end_tok + 1;
> +    }
> +
>    bnum = get_number (&p);
>    if (bnum == 0)
>      error (_("Bad breakpoint argument: '%s'"), arg);
> @@ -1042,7 +1056,7 @@ condition_command (const char *arg, int from_tty)
>  		     " a %s stop condition defined for this breakpoint."),
>  		   ext_lang_capitalized_name (extlang));
>  	  }
> -	set_breakpoint_condition (b, p, from_tty);
> +	set_breakpoint_condition (b, p, from_tty, force);
>  
>  	if (is_breakpoint (b))
>  	  update_global_location_list (UGLL_MAY_INSERT);
> @@ -15576,8 +15590,10 @@ then no output is printed when it is hit, except what the commands print."));
>  
>    c = add_com ("condition", class_breakpoint, condition_command, _("\
>  Specify breakpoint number N to break only if COND is true.\n\
> -Usage is `condition N COND', where N is an integer and COND is an\n\
> -expression to be evaluated whenever breakpoint N is reached."));
> +Usage is `condition [-force] N COND', where N is an integer and COND\n\
> +is an expression to be evaluated whenever breakpoint N is reached.\n\
> +With the `-force` flag, the condition is defined even when it is\n\
> +invalid for all current locations."));
>    set_cmd_completer (c, condition_completer);
>  
>    c = add_com ("tbreak", class_breakpoint, tbreak_command, _("\
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 145bc8a397a..6acec428a9a 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1617,9 +1617,11 @@ extern int breakpoints_should_be_inserted_now (void);
>     in our opinion won't ever trigger.  */
>  extern void breakpoint_retire_moribund (void);
>  
> -/* Set break condition of breakpoint B to EXP.  */
> +/* Set break condition of breakpoint B to EXP.
> +   If FORCE, define the condition even if it is invalid in
> +   all of the breakpoint locations.  */
>  extern void set_breakpoint_condition (struct breakpoint *b, const char *exp,
> -				      int from_tty);
> +				      int from_tty, bool force);
>  
>  /* Checks if we are catching syscalls or not.
>     Returns 0 if not, greater than 0 if we are.  */
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 1b9f76573b9..a81689dab21 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -5453,6 +5453,12 @@ prints an error message:
>  No symbol "foo" in current context.
>  @end smallexample
>  
> +@item condition -force @var{bnum} @var{expression}
> +When the @code{-force} flag is used, define the condition even if
> +@var{expression} is invalid in all the current locations of breakpoint
> +@var{bpnum}.  This is useful if it is known that @var{expression} will
> +be valid for a future shared library location.
> +
>  @noindent
>  @value{GDBN} does
>  not actually evaluate @var{expression} at the time the @code{condition}
> diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
> index 96b6ca91f8d..7c9707235ec 100644
> --- a/gdb/guile/scm-breakpoint.c
> +++ b/gdb/guile/scm-breakpoint.c
> @@ -905,7 +905,7 @@ gdbscm_set_breakpoint_condition_x (SCM self, SCM newvalue)
>  	   ? nullptr
>  	   : gdbscm_scm_to_c_string (newvalue));
>  
> -      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0);
> +      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0, false);
>  
>        return SCM_UNSPECIFIED;
>      });
> diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
> index 11345ad3052..56640421994 100644
> --- a/gdb/python/py-breakpoint.c
> +++ b/gdb/python/py-breakpoint.c
> @@ -461,7 +461,7 @@ bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
>  
>    try
>      {
> -      set_breakpoint_condition (self_bp->bp, exp, 0);
> +      set_breakpoint_condition (self_bp->bp, exp, 0, false);
>      }
>    catch (gdb_exception &ex)
>      {
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts
  2020-07-31 15:42 [PATCH 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
       [not found] ` <cover.1596209606.git.tankut.baris.aktemur@intel.com>
@ 2020-08-20 21:24 ` Tankut Baris Aktemur
  2020-08-20 21:24   ` [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
                     ` (4 more replies)
  2020-09-25 15:51 ` [PATCH v3 " Tankut Baris Aktemur
                   ` (2 subsequent siblings)
  4 siblings, 5 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-08-20 21:24 UTC (permalink / raw)
  To: gdb-patches

Hi,

This is a follow-up of

  https://sourceware.org/pipermail/gdb-patches/2020-July/170984.html

which is a short series about conditional breakpoints where the
condition may be invalid at some breakpoint locations because of their
context.  Currently, GDB does not allow defining a condition if it's
not valid at all locations.  This series aims at bringing more
flexibility: the locations at which the condition expression is
invalid are disabled automatically.

Patch 1/2 is the same as in v1.  Patch 2/2 was previously an RFC.  Andrew
Burgess commented on it at

  https://sourceware.org/pipermail/gdb-patches/2020-August/171012.html

In v2, I extend Patch 2/2 with the '-force-condition' flag for the break
command, add test cases and more documentation.  It is no longer an RFC.

Regards.
Baris


Tankut Baris Aktemur (2):
  gdb/breakpoint: disable a bp location if condition is invalid at that
    location
  gdb/breakpoint: add flags to 'condition' and 'break' commands to force
    condition

 gdb/ada-lang.c                                |   2 +-
 gdb/breakpoint.c                              | 249 ++++++++++++++----
 gdb/breakpoint.h                              |  12 +-
 gdb/doc/gdb.texinfo                           |  50 ++++
 gdb/guile/scm-breakpoint.c                    |   2 +-
 gdb/linespec.c                                |  18 +-
 gdb/python/py-breakpoint.c                    |   2 +-
 .../condbreak-multi-context-included.c        |  18 ++
 .../gdb.base/condbreak-multi-context.c        |  51 ++++
 .../gdb.base/condbreak-multi-context.exp      | 240 +++++++++++++++++
 gdb/testsuite/gdb.linespec/cpcompletion.exp   |  12 +-
 gdb/testsuite/gdb.linespec/explicit.exp       |   1 +
 gdb/testsuite/lib/completion-support.exp      |   2 +-
 13 files changed, 592 insertions(+), 67 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context-included.c
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.c
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-08-20 21:24 ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
@ 2020-08-20 21:24   ` Tankut Baris Aktemur
  2020-09-19  3:05     ` Simon Marchi
  2020-08-20 21:24   ` [PATCH v2 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-08-20 21:24 UTC (permalink / raw)
  To: gdb-patches

Currently, for a conditional breakpoint, GDB checks if the condition
can be evaluated in the context of the first symtab and line (SAL).
In case of an error, defining the conditional breakpoint is aborted.
This prevents having a conditional breakpoint whose condition may
actually be meaningful for some of the location contexts.  This patch
makes it possible to define conditional BPs by checking all location
contexts.  If the condition is meaningful for even one context, the
breakpoint is defined.  The locations for which the condition gives
errors are disabled.

The bp_location struct is introduced a new field, 'disabled_by_cond'.
This field denotes whether the location is disabled automatically
because the condition was non-evaluatable.  Disabled-by-cond locations
cannot be enabled by the user.  But locations that are not
disabled-by-cond can be enabled/disabled by the user manually as
before.

For a concrete example, consider 3 contexts; func1, func2, and func3.
Each context contains instructions coming from the same source.
For instance:

  void
  func1 (int *value)
  {
    int a = 10;
    value += a;
    int b = 1;
  #include "included.c"
  }

  void
  func2 (int *value)
  {
    int b = 2;
  #include "included.c"
  }

  void
  func3 (int *value)
  {
    int c = 30;
    value += c;
    int b = 3;
  #include "included.c"
  }

Note that

* the variable 'a' is defined only in the context defined by func1.
* the variable 'c' is defined only in the context defined by func3.
* the variable 'b' is defined in all the three contexts.

With the existing GDB, it's not possible to define a conditional
breakpoint at "included.c:1" if the condition refers to 'a' or 'c':

  (gdb) break included.c:1 if a == 10
  No symbol "a" in current context.
  (gdb) break included.c:1 if c == 30
  No symbol "c" in current context.
  (gdb) info breakpoints
  No breakpoints or watchpoints.

With this patch, it becomes possible:

  (gdb) break included.c:1 if a == 10
  warning: disabling breakpoint location 2: No symbol "a" in current context.
  warning: disabling breakpoint location 3: No symbol "a" in current context.
  Breakpoint 1 at 0x117d: included.c:1. (3 locations)
  (gdb) break included.c:1 if c == 30
  Note: breakpoint 1 also set at pc 0x117d.
  warning: disabling breakpoint location 1: No symbol "c" in current context.
  Note: breakpoint 1 also set at pc 0x119c.
  warning: disabling breakpoint location 2: No symbol "c" in current context.
  Note: breakpoint 1 also set at pc 0x11cf.
  Breakpoint 2 at 0x117d: included.c:1. (3 locations)
  (gdb) info break
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         y   0x000000000000117d in func1 at included.c:1
  1.2                         n   0x000000000000119c in func2 at included.c:1
  1.3                         n   0x00000000000011cf in func3 at included.c:1
  2       breakpoint     keep y   <MULTIPLE>
          stop only if c == 30
  2.1                         n   0x000000000000117d in func1 at included.c:1
  2.2                         n   0x000000000000119c in func2 at included.c:1
  2.3                         y   0x00000000000011cf in func3 at included.c:1

Executing the code hits the breakpoints 1.1 and 2.3 as expected.

Defining a condition on an unconditional breakpoint gives the same
behavior above:

  (gdb) break included.c:1
  Breakpoint 1 at 0x117d: included.c:1. (3 locations)
  (gdb) cond 1 a == 10
  warning: disabling breakpoint 1.2: No symbol "a" in current context.
  warning: disabling breakpoint 1.3: No symbol "a" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         y   0x000000000000117d in func1 at included.c:1
  1.2                         n   0x000000000000119c in func2 at included.c:1
  1.3                         n   0x00000000000011cf in func3 at included.c:1

Locations that are disabled because of a condition cannot be enabled
by the user:

  ...
  (gdb) enable 1.2
  Location is disabled because of the condition; cannot enable manually.

Resetting the condition enables the locations back:

  ...
  (gdb) cond 1
  Breakpoint 1.2 is now enabled.
  Breakpoint 1.3 is now enabled.
  Breakpoint 1 now unconditional.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
  1.1                         y   0x000000000000117d in func1 at included.c:1
  1.2                         y   0x000000000000119c in func2 at included.c:1
  1.3                         y   0x00000000000011cf in func3 at included.c:1

If a location is disabled by the user, a condition can still be defined
but the location will remain disabled even if the condition is meaningful
for the disabled location:

  ...
  (gdb) disable 1.1
  (gdb) cond 1 a == 10
  warning: disabling breakpoint 1.2: No symbol "a" in current context.
  warning: disabling breakpoint 1.3: No symbol "a" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         n   0x000000000000117d in func1 at included.c:1
  1.2                         n   0x000000000000119c in func2 at included.c:1
  1.3                         n   0x00000000000011cf in func3 at included.c:1

The condition of a breakpoint can be changed.  Locations'
enable/disable states are updated accordingly.

  ...
  (gdb) cond 1 c == 30
  warning: disabling breakpoint 1.1: No symbol "c" in current context.
  warning: disabling breakpoint 1.2: No symbol "c" in current context.
  Breakpoint 1.3 is now enabled.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if c == 30
  1.1                         n   0x000000000000117d in func1 at included.c:1
  1.2                         n   0x000000000000119c in func2 at included.c:1
  1.3                         y   0x00000000000011cf in func3 at included.c:1
  (gdb) cond 1 b == 20
  Breakpoint 1.2 is now enabled.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if b == 20
  1.1                         n   0x000000000000117d in func1 at included.c:1
  1.2                         y   0x000000000000119c in func2 at included.c:1
  1.3                         y   0x00000000000011cf in func3 at included.c:1
  # Note that location 1.1 was disabled by the user previously.

If the condition expression is bad for all the locations, it will be
rejected.

  (gdb) cond 1 garbage
  No symbol "garbage" in current context.

For conditions that are invalid or valid for all the locations of a
breakpoint, the existing behavior is preserved.

Regression-tested on X86_64 Linux.

gdb/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (class bp_location) <disabled_by_cond>: New field.
	* breakpoint.c (set_breakpoint_location_condition): New function.
	(set_breakpoint_condition): Disable a breakpoint
	location if parsing the condition string gives an error.
	(should_be_inserted): Update to consider the 'disabled_by_cond' field.
	(build_target_condition_list): Ditto.
	(build_target_command_list): Ditto.
	(build_bpstat_chain): Ditto.
	(print_one_breakpoint_location): Ditto.
	(print_one_breakpoint): Ditto.
	(bp_location::bp_location): Ditto.
	(locations_are_equal): Ditto.
	(update_breakpoint_locations): Ditto.
	(enable_disable_bp_num_loc): Ditto.
	(init_breakpoint_sal): Use set_breakpoint_location_condition.
	(find_condition_and_thread_for_sals): New static function.
	(create_breakpoint): Call find_condition_and_thread_for_sals.
	(location_to_sals): Call find_condition_and_thread_for_sals instead
	of find_condition_and_thread.

gdb/testsuite/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.base/condbreak-multi-context-included.c: New file.
	* gdb.base/condbreak-multi-context.c: New file.
	* gdb.base/condbreak-multi-context.exp: New file.
---
 gdb/breakpoint.c                              | 201 ++++++++++++----
 gdb/breakpoint.h                              |   6 +
 .../condbreak-multi-context-included.c        |  18 ++
 .../gdb.base/condbreak-multi-context.c        |  51 ++++
 .../gdb.base/condbreak-multi-context.exp      | 218 ++++++++++++++++++
 5 files changed, 446 insertions(+), 48 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context-included.c
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.c
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 977599db1db..7abfd510abc 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -830,6 +830,48 @@ get_first_locp_gte_addr (CORE_ADDR address)
   return locp_found;
 }
 
+/* Parse COND_STRING in the context of LOC and set as the condition
+   expression of LOC.  BP_NUM is the number of LOC's owner, LOC_NUM is
+   the number of LOC within its owner.  In case of parsing error, mark
+   LOC as DISABLED_BY_COND.  In case of success, unset DISABLED_BY_COND.  */
+
+static void
+set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
+				   int bp_num, int loc_num)
+{
+  bool has_junk = false;
+  try
+    {
+      expression_up new_exp = parse_exp_1 (&cond_string, loc->address,
+					   block_for_pc (loc->address), 0);
+      if (*cond_string != 0)
+	has_junk = true;
+      else
+	{
+	  loc->cond = std::move (new_exp);
+	  if (loc->disabled_by_cond && loc->enabled)
+	    printf_filtered (_("Breakpoint %d.%d is now enabled.\n"),
+			     bp_num, loc_num);
+
+	  loc->disabled_by_cond = false;
+	}
+    }
+  catch (const gdb_exception_error &e)
+    {
+      if (bp_num != 0)
+	warning (_("disabling breakpoint %d.%d: %s"),
+		 bp_num, loc_num, e.what ());
+      else
+	warning (_("disabling breakpoint location %d: %s"),
+		 loc_num, e.what ());
+
+      loc->disabled_by_cond = true;
+    }
+
+  if (has_junk)
+    error (_("Garbage '%s' follows condition"), cond_string);
+}
+
 void
 set_breakpoint_condition (struct breakpoint *b, const char *exp,
 			  int from_tty)
@@ -843,9 +885,15 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	static_cast<watchpoint *> (b)->cond_exp.reset ();
       else
 	{
+	  int loc_num = 1;
 	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
 	    {
 	      loc->cond.reset ();
+	      if (loc->disabled_by_cond && loc->enabled)
+		printf_filtered (_("Breakpoint %d.%d is now enabled.\n"),
+				 b->number, loc_num);
+	      loc->disabled_by_cond = false;
+	      loc_num++;
 
 	      /* No need to free the condition agent expression
 		 bytecode (if we have one).  We will handle this
@@ -873,29 +921,37 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	{
 	  /* Parse and set condition expressions.  We make two passes.
 	     In the first, we parse the condition string to see if it
-	     is valid in all locations.  If so, the condition would be
-	     accepted.  So we go ahead and set the locations'
-	     conditions.  In case a failing case is found, we throw
+	     is valid in at least one location.  If so, the condition
+	     would be accepted.  So we go ahead and set the locations'
+	     conditions.  In case no valid case is found, we throw
 	     the error and the condition string will be rejected.
 	     This two-pass approach is taken to avoid setting the
 	     state of locations in case of a reject.  */
 	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
 	    {
-	      const char *arg = exp;
-	      parse_exp_1 (&arg, loc->address,
-			   block_for_pc (loc->address), 0);
-	      if (*arg != 0)
-		error (_("Junk at end of expression"));
+	      try
+		{
+		  const char *arg = exp;
+		  parse_exp_1 (&arg, loc->address,
+			       block_for_pc (loc->address), 0);
+		  if (*arg != 0)
+		    error (_("Junk at end of expression"));
+		  break;
+		}
+	      catch (const gdb_exception_error &e)
+		{
+		  /* Condition string is invalid.  If this happens to
+		     be the last loc, abandon.  */
+		  if (loc->next == nullptr)
+		    throw;
+		}
 	    }
 
-	  /* If we reach here, the condition is valid at all locations.  */
-	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
-	    {
-	      const char *arg = exp;
-	      loc->cond =
-		parse_exp_1 (&arg, loc->address,
-			     block_for_pc (loc->address), 0);
-	    }
+	  /* If we reach here, the condition is valid at some locations.  */
+          int loc_num = 1;
+          for (bp_location *loc = b->loc; loc != nullptr;
+               loc = loc->next, loc_num++)
+            set_breakpoint_location_condition (exp, loc, b->number, loc_num);
 	}
 
       /* We know that the new condition parsed successfully.  The
@@ -2000,7 +2056,8 @@ should_be_inserted (struct bp_location *bl)
   if (bl->owner->disposition == disp_del_at_next_stop)
     return 0;
 
-  if (!bl->enabled || bl->shlib_disabled || bl->duplicate)
+  if (!bl->enabled || bl->disabled_by_cond
+      || bl->shlib_disabled || bl->duplicate)
     return 0;
 
   if (user_breakpoint_p (bl->owner) && bl->pspace->executing_startup)
@@ -2205,7 +2262,8 @@ build_target_condition_list (struct bp_location *bl)
 	  && is_breakpoint (loc->owner)
 	  && loc->pspace->num == bl->pspace->num
 	  && loc->owner->enable_state == bp_enabled
-	  && loc->enabled)
+	  && loc->enabled
+	  && !loc->disabled_by_cond)
 	{
 	  /* Add the condition to the vector.  This will be used later
 	     to send the conditions to the target.  */
@@ -2395,7 +2453,8 @@ build_target_command_list (struct bp_location *bl)
 	  && is_breakpoint (loc->owner)
 	  && loc->pspace->num == bl->pspace->num
 	  && loc->owner->enable_state == bp_enabled
-	  && loc->enabled)
+	  && loc->enabled
+	  && !loc->disabled_by_cond)
 	{
 	  /* Add the command to the vector.  This will be used later
 	     to send the commands to the target.  */
@@ -5278,7 +5337,7 @@ build_bpstat_chain (const address_space *aspace, CORE_ADDR bp_addr,
 	  if (b->type == bp_hardware_watchpoint && bl != b->loc)
 	    break;
 
-	  if (!bl->enabled || bl->shlib_disabled)
+	  if (!bl->enabled || bl->disabled_by_cond || bl->shlib_disabled)
 	    continue;
 
 	  if (!bpstat_check_location (bl, aspace, bp_addr, ws))
@@ -5985,7 +6044,8 @@ print_one_breakpoint_location (struct breakpoint *b,
      breakpoints with single disabled location.  */
   if (loc == NULL 
       && (b->loc != NULL 
-	  && (b->loc->next != NULL || !b->loc->enabled)))
+	  && (b->loc->next != NULL
+	      || !b->loc->enabled || b->loc->disabled_by_cond)))
     header_of_multiple = 1;
   if (loc == NULL)
     loc = b->loc;
@@ -6016,7 +6076,8 @@ print_one_breakpoint_location (struct breakpoint *b,
   /* 4 */
   annotate_field (3);
   if (part_of_multiple)
-    uiout->field_string ("enabled", loc->enabled ? "y" : "n");
+    uiout->field_string ("enabled",
+			 (loc->enabled && !loc->disabled_by_cond) ? "y" : "n");
   else
     uiout->field_fmt ("enabled", "%c", bpenables[(int) b->enable_state]);
 
@@ -6316,7 +6377,9 @@ print_one_breakpoint (struct breakpoint *b,
 	  && (!is_catchpoint (b) || is_exception_catchpoint (b)
 	      || is_ada_exception_catchpoint (b))
 	  && (allflag
-	      || (b->loc && (b->loc->next || !b->loc->enabled))))
+	      || (b->loc && (b->loc->next
+			     || !b->loc->enabled
+			     || b->loc->disabled_by_cond))))
 	{
 	  gdb::optional<ui_out_emit_list> locations_list;
 
@@ -6958,6 +7021,7 @@ bp_location::bp_location (breakpoint *owner, bp_loc_type type)
   this->cond_bytecode = NULL;
   this->shlib_disabled = 0;
   this->enabled = 1;
+  this->disabled_by_cond = false;
 
   this->loc_type = type;
 
@@ -8766,9 +8830,11 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 
   gdb_assert (!sals.empty ());
 
+  int loc_num = 0;
   for (const auto &sal : sals)
     {
       struct bp_location *loc;
+      loc_num++;
 
       if (from_tty)
 	{
@@ -8841,14 +8907,8 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 	}
 
       if (b->cond_string)
-	{
-	  const char *arg = b->cond_string;
-
-	  loc->cond = parse_exp_1 (&arg, loc->address,
-				   block_for_pc (loc->address), 0);
-	  if (*arg)
-              error (_("Garbage '%s' follows condition"), arg);
-	}
+	set_breakpoint_location_condition (b->cond_string, loc,
+					   b->number, loc_num);
 
       /* Dynamic printf requires and uses additional arguments on the
 	 command line, otherwise it's an error.  */
@@ -9151,6 +9211,50 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
     }
 }
 
+/* Call 'find_condition_and_thread' for each sal in SALS until a parse
+   succeeds.  The parsed values are written to COND_STRING, THREAD,
+   TASK, and REST.  See the comment of 'find_condition_and_thread'
+   for the description of these parameters and INPUT.  */
+
+static void
+find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
+				    const char *input, char **cond_string,
+				    int *thread, int *task, char **rest)
+{
+  int num_failures = 0;
+  for (auto &sal : sals)
+    {
+      char *cond = nullptr;
+      int thread_id = 0;
+      int task_id = 0;
+      char *remaining = nullptr;
+
+      /* Here we want to parse 'arg' to separate condition from thread
+	 number.  But because parsing happens in a context and the
+	 contexts of sals might be different, try each until there is
+	 success.  Finding one successful parse is sufficient for our
+	 goal.  When setting the breakpoint we'll re-parse the
+	 condition in the context of each sal.  */
+      try
+	{
+	  find_condition_and_thread (input, sal.pc, &cond, &thread_id,
+				     &task_id, &remaining);
+	  *cond_string = cond;
+	  *thread = thread_id;
+	  *task = task_id;
+	  *rest = remaining;
+	  break;
+	}
+      catch (const gdb_exception_error &e)
+	{
+	  num_failures++;
+	  /* If no sal remains, do not continue.  */
+	  if (num_failures == sals.size ())
+	    throw;
+	}
+    }
+}
+
 /* Decode a static tracepoint marker spec.  */
 
 static std::vector<symtab_and_line>
@@ -9314,13 +9418,8 @@ create_breakpoint (struct gdbarch *gdbarch,
 
 	  const linespec_sals &lsal = canonical.lsals[0];
 
-	  /* Here we only parse 'arg' to separate condition
-	     from thread number, so parsing in context of first
-	     sal is OK.  When setting the breakpoint we'll
-	     re-parse it in context of each sal.  */
-
-	  find_condition_and_thread (extra_string, lsal.sals[0].pc,
-				     &cond, &thread, &task, &rest);
+	  find_condition_and_thread_for_sals (lsal.sals, extra_string,
+					      &cond, &thread, &task, &rest);
 	  cond_string_copy.reset (cond);
 	  extra_string_copy.reset (rest);
         }
@@ -13434,6 +13533,9 @@ locations_are_equal (struct bp_location *a, struct bp_location *b)
       if (a->enabled != b->enabled)
 	return 0;
 
+      if (a->disabled_by_cond != b->disabled_by_cond)
+	return 0;
+
       a = a->next;
       b = b->next;
     }
@@ -13541,10 +13643,7 @@ update_breakpoint_locations (struct breakpoint *b,
 	    }
 	  catch (const gdb_exception_error &e)
 	    {
-	      warning (_("failed to reevaluate condition "
-			 "for breakpoint %d: %s"), 
-		       b->number, e.what ());
-	      new_loc->enabled = 0;
+	      new_loc->disabled_by_cond = true;
 	    }
 	}
 
@@ -13569,7 +13668,7 @@ update_breakpoint_locations (struct breakpoint *b,
 
     for (; e; e = e->next)
       {
-	if (!e->enabled && e->function_name)
+	if ((!e->enabled || e->disabled_by_cond) && e->function_name)
 	  {
 	    struct bp_location *l = b->loc;
 	    if (have_ambiguous_names)
@@ -13585,7 +13684,8 @@ update_breakpoint_locations (struct breakpoint *b,
 		       enough.  */
 		    if (breakpoint_locations_match (e, l, true))
 		      {
-			l->enabled = 0;
+			l->enabled = e->enabled;
+			l->disabled_by_cond = e->disabled_by_cond;
 			break;
 		      }
 		  }
@@ -13596,7 +13696,8 @@ update_breakpoint_locations (struct breakpoint *b,
 		  if (l->function_name
 		      && strcmp (e->function_name, l->function_name) == 0)
 		    {
-		      l->enabled = 0;
+		      l->enabled = e->enabled;
+		      l->disabled_by_cond = e->disabled_by_cond;
 		      break;
 		    }
 	      }
@@ -13670,9 +13771,9 @@ location_to_sals (struct breakpoint *b, struct event_location *location,
 	  char *cond_string, *extra_string;
 	  int thread, task;
 
-	  find_condition_and_thread (b->extra_string, sals[0].pc,
-				     &cond_string, &thread, &task,
-				     &extra_string);
+	  find_condition_and_thread_for_sals (sals, b->extra_string,
+					      &cond_string, &thread,
+					      &task, &extra_string);
 	  gdb_assert (b->cond_string == NULL);
 	  if (cond_string)
 	    b->cond_string = cond_string;
@@ -14157,6 +14258,10 @@ enable_disable_bp_num_loc (int bp_num, int loc_num, bool enable)
   struct bp_location *loc = find_location_by_number (bp_num, loc_num);
   if (loc != NULL)
     {
+      if (loc->disabled_by_cond && enable)
+	error(_("Location is disabled because of the condition; "
+		"cannot enable manually."));
+
       if (loc->enabled != enable)
 	{
 	  loc->enabled = enable;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 347aeb75f30..145bc8a397a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -387,6 +387,12 @@ class bp_location
   /* Is this particular location enabled.  */
   bool enabled = false;
   
+  /* Is this particular location disabled because the condition
+     expression is invalid at this location.  For a location to be
+     reported as enabled, the ENABLED field above has to be true *and*
+     the DISABLED_BY_COND field has to be false.  */
+  bool disabled_by_cond = false;
+
   /* True if this breakpoint is now inserted.  */
   bool inserted = false;
 
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context-included.c b/gdb/testsuite/gdb.base/condbreak-multi-context-included.c
new file mode 100644
index 00000000000..810943eda10
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context-included.c
@@ -0,0 +1,18 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+value += b; /* breakpoint-here */
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.c b/gdb/testsuite/gdb.base/condbreak-multi-context.c
new file mode 100644
index 00000000000..42a445a2d7d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.c
@@ -0,0 +1,51 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+void
+func1 (int *value)
+{
+  int a = 10;
+  value += a;
+  int b = 1;
+#include "condbreak-multi-context-included.c"
+}
+
+void
+func2 (int *value)
+{
+  int b = 2;
+#include "condbreak-multi-context-included.c"
+}
+
+void
+func3 (int *value)
+{
+  int c = 30;
+  value += c;
+  int b = 3;
+#include "condbreak-multi-context-included.c"
+}
+
+int
+main ()
+{
+  int val = 0;
+  func1 (&val);
+  func2 (&val);
+  func3 (&val);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
new file mode 100644
index 00000000000..b02a0a2e40c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -0,0 +1,218 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test defining a conditional breakpoint that applies to multiple
+# locations with different contexts (e.g. different set of local vars).
+
+standard_testfile condbreak-multi-context.c condbreak-multi-context-included.c
+
+if {[prepare_for_testing "failed to prepare" ${binfile} ${srcfile}]} {
+    return
+}
+
+set warning "warning: disabling breakpoint"
+set fill "\[^\r\n\]*"
+
+set bp_location [gdb_get_line_number "breakpoint-here" $srcfile2]
+
+# Check that breakpoints are as expected.
+
+proc test_info_break {suffix} {
+    global bpnum1 bpnum2 fill
+
+    set bp_hit_info "${fill}(\r\n${fill}breakpoint already hit 1 time)?"
+
+    gdb_test "info break ${bpnum1} ${bpnum2}" \
+	[multi_line \
+	     "Num${fill}" \
+	     "${bpnum1}${fill}breakpoint${fill}keep y${fill}MULTIPLE${fill}" \
+	     "${fill}stop only if a == 10${bp_hit_info}" \
+	     "${bpnum1}.1${fill}y${fill}func1${fill}" \
+	     "${bpnum1}.2${fill}n${fill}func2${fill}" \
+	     "${bpnum1}.3${fill}n${fill}func3${fill}" \
+	     "${bpnum2}${fill}breakpoint${fill}keep y${fill}MULTIPLE${fill}" \
+	     "${fill}stop only if c == 30${bp_hit_info}" \
+	     "${bpnum2}.1${fill}n${fill}func1${fill}" \
+	     "${bpnum2}.2${fill}n${fill}func2${fill}" \
+	     "${bpnum2}.3${fill}y${fill}func3${fill}"] \
+	"info break $suffix"
+}
+
+# Scenario 1: Define breakpoints conditionally, using the "break N if
+# cond" syntax.  Run the program, check that we hit those locations
+# only.
+
+with_test_prefix "scenario 1" {
+    # Define the conditional breakpoints.
+    gdb_test "break $srcfile2:$bp_location if a == 10" \
+	[multi_line \
+	     "${warning} location 2: No symbol \"a\" in current context." \
+	     "${warning} location 3: No symbol \"a\" in current context." \
+	     "Breakpoint $decimal at $fill .3 locations."] \
+	"define bp with condition a == 10"
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+
+    gdb_test "break $srcfile2:$bp_location if c == 30" \
+	[multi_line \
+	     ".*${warning} location 1: No symbol \"c\" in current context." \
+	     ".*${warning} location 2: No symbol \"c\" in current context." \
+	     ".*Breakpoint $decimal at $fill .3 locations."] \
+	"define bp with condition c == 30"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+
+    test_info_break 1
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_run_cmd
+
+    # Check our conditional breakpoints.
+    gdb_test "" ".*Breakpoint \[0-9\]+, func1 .*" \
+	"run until func1"
+    gdb_test "print a" " = 10"
+
+    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, func3 .*" \
+	"run until func3"
+    gdb_test "print c" " = 30"
+
+    # No more hits!
+    gdb_continue_to_end
+
+    test_info_break 2
+}
+
+# Start GDB with two breakpoints and define the conditions separately.
+
+proc setup_bps {} {
+    global srcfile binfile srcfile2
+    global bpnum1 bpnum2 bp_location warning
+
+    clean_restart ${binfile}
+
+    # Define the breakpoints.
+    gdb_breakpoint "$srcfile2:$bp_location"
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+
+    gdb_breakpoint "$srcfile2:$bp_location"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+
+    # Defining a condition on 'a' disables 2 locations.
+    gdb_test "cond $bpnum1 a == 10" \
+	[multi_line \
+	     "$warning ${bpnum1}.2: No symbol \"a\" in current context." \
+	     "$warning ${bpnum1}.3: No symbol \"a\" in current context."]
+
+    # Defining a condition on 'c' disables 2 locations.
+    gdb_test "cond $bpnum2 c == 30" \
+	[multi_line \
+	     "$warning ${bpnum2}.1: No symbol \"c\" in current context." \
+	     "$warning ${bpnum2}.2: No symbol \"c\" in current context."]
+}
+
+# Scenario 2: Define breakpoints unconditionally, and then define
+# conditions using the "cond N <cond>" syntax.  Expect that the
+# locations where <cond> is not evaluatable are disabled.  Run the
+# program, check that we hit the enabled locations only.
+
+with_test_prefix "scenario 2" {
+    setup_bps
+
+    test_info_break 1
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_run_cmd
+
+    # Check that we hit enabled locations only.
+    gdb_test "" ".*Breakpoint \[0-9\]+, func1 .*" \
+	"run until func1"
+    gdb_test "print a" " = 10"
+
+    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, func3 .*" \
+	"run until func3"
+    gdb_test "print c" " = 30"
+
+    # No more hits!
+    gdb_continue_to_end
+
+    test_info_break 2
+}
+
+# Test the breakpoint location enabled states.
+
+proc check_bp_locations {bpnum states msg} {
+    global fill
+
+    set expected  ".*${bpnum}.1${fill} [lindex $states 0] ${fill}\r\n"
+    append expected "${bpnum}.2${fill} [lindex $states 1] ${fill}\r\n"
+    append expected "${bpnum}.3${fill} [lindex $states 2] ${fill}"
+
+    gdb_test "info break $bpnum" $expected "check bp $bpnum $msg"
+}
+
+# Scenario 3: Apply misc. checks on the already-defined breakpoints.
+
+with_test_prefix "scenario 3" {
+    setup_bps
+
+    gdb_test "cond $bpnum1 c == 30" \
+	[multi_line \
+	     "${warning} 1.1: No symbol \"c\" in current context." \
+	     "${warning} 1.2: No symbol \"c\" in current context." \
+	     "Breakpoint 1.3 is now enabled."] \
+	"change the condition of bp 1"
+    check_bp_locations $bpnum1 {n n y} "after changing the condition"
+
+    gdb_test "cond $bpnum1" \
+	[multi_line \
+	     "Breakpoint 1.1 is now enabled." \
+	     "Breakpoint 1.2 is now enabled." \
+	     "Breakpoint 1 now unconditional."] \
+	"reset the condition of bp 1"
+    check_bp_locations $bpnum1 {y y y} "after resetting the condition"
+
+    gdb_test_no_output "disable ${bpnum2}.2"
+    check_bp_locations $bpnum2 {n n y} "after disabling loc 2"
+
+    gdb_test "cond $bpnum2" ".*" "reset the condition of bp 2"
+    check_bp_locations $bpnum2 {y n y} "loc 2 should remain disabled"
+
+    gdb_test_no_output "disable ${bpnum2}.3"
+    check_bp_locations $bpnum2 {y n n} "after disabling loc 3"
+
+    gdb_test "cond $bpnum2 c == 30" \
+	[multi_line \
+	     "${warning} 2.1: No symbol \"c\" in current context." \
+	     "${warning} 2.2: No symbol \"c\" in current context."] \
+	"re-define a condition"
+    check_bp_locations $bpnum2 {n n n} "loc 3 should remain disabled"
+
+    gdb_test "enable ${bpnum2}.1" \
+	"Location is disabled because of the condition; cannot enable manually." \
+	"reject enabling a location that is disabled-by-cond"
+    check_bp_locations $bpnum2 {n n n} "after enable attempt"
+
+    gdb_test "cond $bpnum2 garbage" \
+	"No symbol \"garbage\" in current context." \
+	"reject condition if bad for all locations"
+
+    gdb_test_no_output "delete $bpnum1"
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_breakpoint "main"
+    gdb_run_cmd
+    gdb_test "" ".*reakpoint .*, main .*${srcfile}.*" "start"
+
+    # The second BP's locations are all disabled.  No more hits!
+    gdb_continue_to_end
+}
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-08-20 21:24 ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
  2020-08-20 21:24   ` [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
@ 2020-08-20 21:24   ` Tankut Baris Aktemur
  2020-09-04 11:02   ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-08-20 21:24 UTC (permalink / raw)
  To: gdb-patches

The previous patch made it possible to define a condition if it's
valid at some locations.  If the condition is invalid at all of the
locations, it's rejected.  However, there may be cases where the user
knows the condition *will* be valid at a location in the future,
e.g. due to a shared library load.

To make it possible that such condition can be defined, this patch
adds an optional '-force' flag to the 'condition' command, and,
respectively, a '-force-condition' flag to the 'break'command.  When
the force flag is passed, the condition is not rejected even when it
is invalid for all the current locations (note that all the locations
would be internally disabled in this case).

For instance:

  (gdb) break test.c:5
  Breakpoint 1 at 0x1155: file test.c, line 5.
  (gdb) cond 1 foo == 42
  No symbol "foo" in current context.

Defining the condition was not possible because 'foo' is not
available.  The user can override this behavior with the '-force'
flag:

  (gdb) cond -force 1 foo == 42
  warning: disabling breakpoint 1.1: No symbol "foo" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if foo == 42
  1.1                         n   0x0000000000001155 in main at test.c:5

Now the condition is accepted, but the location is automatically
disabled.  If a future location has a context in which 'foo' is
available, that location would be enabled.

For the 'break' command, -force-condition has the same result:

  (gdb) break test.c:5 -force-condition if foo == 42
  warning: disabling breakpoint location 1: No symbol "foo" in current context.
  Breakpoint 1 at 0x1169: file test.c, line 5.

gdb/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (set_breakpoint_condition): Add a new bool parameter.
	* breakpoint.c: Update the help text of the 'condition' and 'break'
	commands.
	(set_breakpoint_condition): Take a new bool parameter
	to control whether condition definition should be forced even when
	the condition expression is invalid in all of the current locations.
	(condition_command): Update the call to 'set_breakpoint_condition'.
	(find_condition_and_thread): Take the "-force-condition" flag into
	account.
        * linespec.c (linespec_keywords): Add "-force-condition" as an
	element.
        (FORCE_KEYWORD_INDEX): New #define.
        (linespec_lexer_lex_keyword): Update to consider "-force-condition"
	as a keyword.
	* ada-lang.c (create_ada_exception_catchpoint): Ditto.
	* guile/scm-breakpoint.c (gdbscm_set_breakpoint_condition_x): Ditto.
	* python/py-breakpoint.c (bppy_set_condition): Ditto.

gdb/testsuite/ChangeLog:
2020-08-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.base/condbreak-multi-context.exp: Expand to test forcing
	the condition.
	* gdb.linespec/cpcompletion.exp: Update to consider the
	'-force-condition' keyword.
	* gdb.linespec/explicit.exp: Ditto.
	* lib/completion-support.exp: Ditto.

gdb/doc/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo: Document the '-force-condition' flag of the 'break'
	command, and the '-force' flag of the 'condition' command.
---
 gdb/ada-lang.c                                |  2 +-
 gdb/breakpoint.c                              | 52 ++++++++++++++++---
 gdb/breakpoint.h                              |  6 ++-
 gdb/doc/gdb.texinfo                           | 50 ++++++++++++++++++
 gdb/guile/scm-breakpoint.c                    |  2 +-
 gdb/linespec.c                                | 18 +++++--
 gdb/python/py-breakpoint.c                    |  2 +-
 .../gdb.base/condbreak-multi-context.exp      | 22 ++++++++
 gdb/testsuite/gdb.linespec/cpcompletion.exp   | 12 +++--
 gdb/testsuite/gdb.linespec/explicit.exp       |  1 +
 gdb/testsuite/lib/completion-support.exp      |  2 +-
 11 files changed, 148 insertions(+), 21 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 29951528e5e..69b3c3c63cd 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12702,7 +12702,7 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
   c->excep_string = excep_string;
   create_excep_cond_exprs (c.get (), ex_kind);
   if (!cond_string.empty ())
-    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty);
+    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty, false);
   install_breakpoint (0, std::move (c), 1);
 }
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 7abfd510abc..239420f4c0f 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -874,7 +874,7 @@ set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
 
 void
 set_breakpoint_condition (struct breakpoint *b, const char *exp,
-			  int from_tty)
+			  int from_tty, bool force)
 {
   if (*exp == 0)
     {
@@ -941,9 +941,11 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	      catch (const gdb_exception_error &e)
 		{
 		  /* Condition string is invalid.  If this happens to
-		     be the last loc, abandon.  */
+		     be the last loc, abandon (if not forced) or continue
+		     (if forced).  */
 		  if (loc->next == nullptr)
-		    throw;
+		    if (!force)
+		      throw;
 		}
 	    }
 
@@ -1023,6 +1025,18 @@ condition_command (const char *arg, int from_tty)
     error_no_arg (_("breakpoint number"));
 
   p = arg;
+
+  /* Check if the "-force" flag was passed.  */
+  bool force = false;
+  const char *tok = skip_spaces (p);
+  const char *end_tok = skip_to_space (tok);
+  int toklen = end_tok - tok;
+  if (toklen >= 1 && strncmp (tok, "-force", toklen) == 0)
+    {
+      force = true;
+      p = end_tok + 1;
+    }
+
   bnum = get_number (&p);
   if (bnum == 0)
     error (_("Bad breakpoint argument: '%s'"), arg);
@@ -1042,7 +1056,7 @@ condition_command (const char *arg, int from_tty)
 		     " a %s stop condition defined for this breakpoint."),
 		   ext_lang_capitalized_name (extlang));
 	  }
-	set_breakpoint_condition (b, p, from_tty);
+	set_breakpoint_condition (b, p, from_tty, force);
 
 	if (is_breakpoint (b))
 	  update_global_location_list (UGLL_MAY_INSERT);
@@ -9150,6 +9164,7 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
   *thread = -1;
   *task = 0;
   *rest = NULL;
+  bool force = false;
 
   while (tok && *tok)
     {
@@ -9173,10 +9188,25 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
       if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
 	{
 	  tok = cond_start = end_tok + 1;
-	  parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
+	  try
+	    {
+	      parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
+	    }
+	  catch (const gdb_exception_error &)
+	    {
+	      if (!force)
+		throw;
+	      else
+		tok = tok + strlen (tok);
+	    }
 	  cond_end = tok;
 	  *cond_string = savestring (cond_start, cond_end - cond_start);
 	}
+      else if (toklen >= 1 && strncmp (tok, "-force-condition", toklen) == 0)
+	{
+	  tok = cond_start = end_tok + 1;
+	  force = true;
+	}
       else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
 	{
 	  const char *tmptok;
@@ -15242,7 +15272,8 @@ specified name as a complete fully-qualified name instead."
    command.  */
 
 #define BREAK_ARGS_HELP(command) \
-command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
+command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM]\n\
+\t[-force-condition] [if CONDITION]\n\
 PROBE_MODIFIER shall be present if the command is to be placed in a\n\
 probe point.  Accepted values are `-probe' (for a generic, automatically\n\
 guessed probe type), `-probe-stap' (for a SystemTap probe) or \n\
@@ -15255,6 +15286,9 @@ stack frame.  This is useful for breaking on return to a stack frame.\n\
 \n\
 THREADNUM is the number from \"info threads\".\n\
 CONDITION is a boolean expression.\n\
+\n\
+With the \"-force-condition\" flag, the condition is defined even when\n\
+it is invalid for all current locations.\n\
 \n" LOCATION_HELP_STRING "\n\n\
 Multiple breakpoints at one place are permitted, and useful if their\n\
 conditions are different.\n\
@@ -15576,8 +15610,10 @@ then no output is printed when it is hit, except what the commands print."));
 
   c = add_com ("condition", class_breakpoint, condition_command, _("\
 Specify breakpoint number N to break only if COND is true.\n\
-Usage is `condition N COND', where N is an integer and COND is an\n\
-expression to be evaluated whenever breakpoint N is reached."));
+Usage is `condition [-force] N COND', where N is an integer and COND\n\
+is an expression to be evaluated whenever breakpoint N is reached.\n\
+With the \"-force\" flag, the condition is defined even when it is\n\
+invalid for all current locations."));
   set_cmd_completer (c, condition_completer);
 
   c = add_com ("tbreak", class_breakpoint, tbreak_command, _("\
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 145bc8a397a..6acec428a9a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1617,9 +1617,11 @@ extern int breakpoints_should_be_inserted_now (void);
    in our opinion won't ever trigger.  */
 extern void breakpoint_retire_moribund (void);
 
-/* Set break condition of breakpoint B to EXP.  */
+/* Set break condition of breakpoint B to EXP.
+   If FORCE, define the condition even if it is invalid in
+   all of the breakpoint locations.  */
 extern void set_breakpoint_condition (struct breakpoint *b, const char *exp,
-				      int from_tty);
+				      int from_tty, bool force);
 
 /* Checks if we are catching syscalls or not.
    Returns 0 if not, greater than 0 if we are.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 77013648b2f..1d3c1f29f94 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4278,6 +4278,50 @@ value is nonzero---that is, if @var{cond} evaluates as true.
 above (or no argument) specifying where to break.  @xref{Conditions,
 ,Break Conditions}, for more information on breakpoint conditions.
 
+The breakpoint may be mapped to multiple locations.  If the breakpoint
+condition @var{cond} is invalid at some but not all of the locations,
+the locations for which the condition is invalid are disabled.  For
+example, @value{GDBN} reports below that two of the three locations
+are disabled.
+
+@smallexample
+(@value{GDBP}) break func if a == 42
+warning: disabling breakpoint location 2: No symbol "a" in current context.
+warning: disabling breakpoint location 3: No symbol "a" in current context.
+Breakpoint 1 at 0x401129: test.c:18. (3 locations)
+@end smallexample
+
+If the breakpoint condition @var{cond} is invalid in the context of
+@emph{all} the locations of the breakpoint, @value{GDBN} refuses to
+define the breakpoint.  For example, if variable @code{foo} is an
+undefined variable:
+
+@smallexample
+(@value{GDBP}) break func if foo
+No symbol "foo" in current context.
+@end smallexample
+
+@item break @dots{} -force-condition if @var{cond}
+There may be cases where the condition @var{cond} is invalid at all
+the current locations, but the user knows that it will be valid at a
+future location; for example, because of a library load.  In such
+cases, by using the @code{-force-condition} keyword before @samp{if},
+@value{GDBN} can be forced to define the breakpoint with the given
+condition expression instead of refusing it.
+
+@smallexample
+(@value{GDBP}) break func -force-condition if foo
+warning: disabling breakpoint location 1: No symbol "foo" in current context.
+warning: disabling breakpoint location 2: No symbol "foo" in current context.
+warning: disabling breakpoint location 3: No symbol "foo" in current context.
+Breakpoint 1 at 0x401129: test.c:18. (3 locations)
+@end smallexample
+
+This causes all the present locations where the breakpoint would
+otherwise be inserted, to be disabled, as seen in the example above.
+However, if there exist locations at which the condition is valid, the
+@code{-force-condition} keyword has no effect.
+
 @kindex tbreak
 @item tbreak @var{args}
 Set a breakpoint enabled only for one stop.  The @var{args} are the
@@ -5457,6 +5501,12 @@ prints an error message:
 No symbol "foo" in current context.
 @end smallexample
 
+@item condition -force @var{bnum} @var{expression}
+When the @code{-force} flag is used, define the condition even if
+@var{expression} is invalid in all the current locations of breakpoint
+@var{bpnum}.  This is similar to the @code{-force-condition} option
+of the @code{break} command.
+
 @noindent
 @value{GDBN} does
 not actually evaluate @var{expression} at the time the @code{condition}
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index 96b6ca91f8d..7c9707235ec 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -905,7 +905,7 @@ gdbscm_set_breakpoint_condition_x (SCM self, SCM newvalue)
 	   ? nullptr
 	   : gdbscm_scm_to_c_string (newvalue));
 
-      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0);
+      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0, false);
 
       return SCM_UNSPECIFIED;
     });
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 4a634e3aff9..3bfcf41ae06 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -72,7 +72,7 @@ enum class linespec_complete_what
   /* An expression.  E.g., "break foo if EXPR", or "break *EXPR".  */
   EXPRESSION,
 
-  /* A linespec keyword ("if"/"thread"/"task").
+  /* A linespec keyword ("if"/"thread"/"task"/"-force-condition").
      E.g., "break func threa<tab>".  */
   KEYWORD,
 };
@@ -254,8 +254,9 @@ typedef enum ls_token_type linespec_token_type;
 
 /* List of keywords.  This is NULL-terminated so that it can be used
    as enum completer.  */
-const char * const linespec_keywords[] = { "if", "thread", "task", NULL };
+const char * const linespec_keywords[] = { "if", "thread", "task", "-force-condition", NULL };
 #define IF_KEYWORD_INDEX 0
+#define FORCE_KEYWORD_INDEX 3
 
 /* A token of the linespec lexer  */
 
@@ -486,11 +487,22 @@ linespec_lexer_lex_keyword (const char *p)
 	    {
 	      int j;
 
+	      /* Special case: "-force" is always followed by an "if".  */
+	      if (i == FORCE_KEYWORD_INDEX)
+		{
+		  p += len;
+		  p = skip_spaces (p);
+		  int nextlen = strlen (linespec_keywords[IF_KEYWORD_INDEX]);
+		  if (!(strncmp (p, linespec_keywords[IF_KEYWORD_INDEX], nextlen) == 0
+			&& isspace (p[nextlen])))
+		    return NULL;
+		}
+
 	      /* Special case: "if" ALWAYS stops the lexer, since it
 		 is not possible to predict what is going to appear in
 		 the condition, which can only be parsed after SaLs have
 		 been found.  */
-	      if (i != IF_KEYWORD_INDEX)
+	      else if (i != IF_KEYWORD_INDEX)
 		{
 		  p += len;
 		  p = skip_spaces (p);
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 11345ad3052..56640421994 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -461,7 +461,7 @@ bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
 
   try
     {
-      set_breakpoint_condition (self_bp->bp, exp, 0);
+      set_breakpoint_condition (self_bp->bp, exp, 0, false);
     }
   catch (gdb_exception &ex)
     {
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
index b02a0a2e40c..30bde8adf7c 100644
--- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -216,3 +216,25 @@ with_test_prefix "scenario 3" {
     # The second BP's locations are all disabled.  No more hits!
     gdb_continue_to_end
 }
+
+# Scenario 4: Test the '-force'/'-force-condition' flag.
+
+with_test_prefix "force" {
+    clean_restart ${binfile}
+
+    gdb_breakpoint "$srcfile2:$bp_location"
+    # Pick a condition that is invalid at every location.
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+    gdb_test "cond -force $bpnum1 foo" \
+	[multi_line \
+	     "${warning} 1.1: No symbol \"foo\" in current context." \
+	     "${warning} 1.2: No symbol \"foo\" in current context." \
+	     "${warning} 1.3: No symbol \"foo\" in current context."] \
+	"force the condition of bp 1"
+    check_bp_locations $bpnum1 {n n n} "after forcing the condition"
+
+    # Now with the 'break' command.
+    gdb_breakpoint "$srcfile2:$bp_location -force-condition if baz"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+    check_bp_locations $bpnum2 {n n n} "set using the break command"
+}
diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp
index 2c95e2b4048..de96556f22d 100644
--- a/gdb/testsuite/gdb.linespec/cpcompletion.exp
+++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp
@@ -836,12 +836,14 @@ proc_with_prefix function-labels {} {
 }
 
 # Test that completion after a function name offers keyword
-# (if/task/thread) matches in linespec mode, and also the explicit
-# location options in explicit locations mode.
+# (if/task/thread/-force-condition) matches in linespec mode, and also
+# the explicit location options in explicit locations mode.
 
 proc_with_prefix keywords-after-function {} {
     set explicit_list \
-	[concat $completion::explicit_opts_list $completion::keyword_list]
+	[lsort [concat \
+		    $completion::explicit_opts_list \
+		    $completion::keyword_list]]
 
     # Test without a source file, with a known source file, and with
     # and unknown source file.
@@ -865,7 +867,9 @@ proc_with_prefix keywords-after-function {} {
 
 proc_with_prefix keywords-after-label {} {
     set explicit_list \
-	[concat $completion::explicit_opts_list $completion::keyword_list]
+	[lsort [concat \
+		    $completion::explicit_opts_list \
+		    $completion::keyword_list]]
 
     foreach_location_labels \
 	{ "" "cpls.cc" } \
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
index 4f457dc372f..5e3d352918e 100644
--- a/gdb/testsuite/gdb.linespec/explicit.exp
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -405,6 +405,7 @@ namespace eval $testfile {
 	# completion matches both the explicit location options and
 	# the linespec keywords.
 	set completions_list {
+	    "-force-condition"
 	    "-function"
 	    "-label"
 	    "-line"
diff --git a/gdb/testsuite/lib/completion-support.exp b/gdb/testsuite/lib/completion-support.exp
index 51436cc6713..dbb958157ed 100644
--- a/gdb/testsuite/lib/completion-support.exp
+++ b/gdb/testsuite/lib/completion-support.exp
@@ -27,7 +27,7 @@ namespace eval completion {
     # List of all quote chars, including no-quote at all.
     variable maybe_quoted_list {"" "'" "\""}
 
-    variable keyword_list {"if" "task" "thread"}
+    variable keyword_list {"-force-condition" "if" "task" "thread"}
 
     variable explicit_opts_list \
 	{"-function" "-label" "-line" "-qualified" "-source"}
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts
  2020-08-20 21:24 ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
  2020-08-20 21:24   ` [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
  2020-08-20 21:24   ` [PATCH v2 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
@ 2020-09-04 11:02   ` Tankut Baris Aktemur
  2020-09-11 11:56   ` Tankut Baris Aktemur
  2020-09-18 20:36   ` [PING][PATCH " Tankut Baris Aktemur
  4 siblings, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-09-04 11:02 UTC (permalink / raw)
  To: gdb-patches

> Hi,
>
> This is a follow-up of
>
>   https://sourceware.org/pipermail/gdb-patches/2020-July/170984.html
>
> which is a short series about conditional breakpoints where the
> condition may be invalid at some breakpoint locations because of their
> context.  Currently, GDB does not allow defining a condition if it's
> not valid at all locations.  This series aims at bringing more
> flexibility: the locations at which the condition expression is
> invalid are disabled automatically.
>
> Patch 1/2 is the same as in v1.  Patch 2/2 was previously an RFC.  Andrew
> Burgess commented on it at
>
>   https://sourceware.org/pipermail/gdb-patches/2020-August/171012.html
>
> In v2, I extend Patch 2/2 with the '-force-condition' flag for the break
> command, add test cases and more documentation.  It is no longer an RFC.

Kindly pinging for

  https://sourceware.org/pipermail/gdb-patches/2020-August/171387.html

Thanks.
Baris


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts
  2020-08-20 21:24 ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
                     ` (2 preceding siblings ...)
  2020-09-04 11:02   ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
@ 2020-09-11 11:56   ` Tankut Baris Aktemur
  2020-09-18 20:36   ` [PING][PATCH " Tankut Baris Aktemur
  4 siblings, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-09-11 11:56 UTC (permalink / raw)
  To: gdb-patches

> Hi,
>
> This is a follow-up of
>
>   https://sourceware.org/pipermail/gdb-patches/2020-July/170984.html
>
> which is a short series about conditional breakpoints where the
> condition may be invalid at some breakpoint locations because of their
> context.  Currently, GDB does not allow defining a condition if it's
> not valid at all locations.  This series aims at bringing more
> flexibility: the locations at which the condition expression is
> invalid are disabled automatically.
>
> Patch 1/2 is the same as in v1.  Patch 2/2 was previously an RFC.  Andrew
> Burgess commented on it at
>
>   https://sourceware.org/pipermail/gdb-patches/2020-August/171012.html
>
> In v2, I extend Patch 2/2 with the '-force-condition' flag for the break
> command, add test cases and more documentation.  It is no longer an RFC.

Kindly pinging for

  https://sourceware.org/pipermail/gdb-patches/2020-August/171387.html

Thanks.
Baris


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PING][PATCH v2 0/2] Breakpoint conditions at locations with differing contexts
  2020-08-20 21:24 ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
                     ` (3 preceding siblings ...)
  2020-09-11 11:56   ` Tankut Baris Aktemur
@ 2020-09-18 20:36   ` Tankut Baris Aktemur
  4 siblings, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-09-18 20:36 UTC (permalink / raw)
  To: gdb-patches

> Hi,
>
> This is a follow-up of
>
>   https://sourceware.org/pipermail/gdb-patches/2020-July/170984.html
>
> which is a short series about conditional breakpoints where the
> condition may be invalid at some breakpoint locations because of their
> context.  Currently, GDB does not allow defining a condition if it's
> not valid at all locations.  This series aims at bringing more
> flexibility: the locations at which the condition expression is
> invalid are disabled automatically.
>
> Patch 1/2 is the same as in v1.  Patch 2/2 was previously an RFC.  Andrew
> Burgess commented on it at
>
>   https://sourceware.org/pipermail/gdb-patches/2020-August/171012.html
>
> In v2, I extend Patch 2/2 with the '-force-condition' flag for the break
> command, add test cases and more documentation.  It is no longer an RFC.

Kindly pinging for

  https://sourceware.org/pipermail/gdb-patches/2020-August/171387.html

Thanks.
Baris


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-08-20 21:24   ` [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
@ 2020-09-19  3:05     ` Simon Marchi
  2020-09-25 15:49       ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2020-09-19  3:05 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches


Hi Baris,

I don't have much time right now, but I also don't want to delay looking
at this further, so here are a few comments.  Overall, I think that this
is very well thought through and I like the behavior.

On 2020-08-20 5:24 p.m., Tankut Baris Aktemur via Gdb-patches wrote:
> Currently, for a conditional breakpoint, GDB checks if the condition
> can be evaluated in the context of the first symtab and line (SAL).
> In case of an error, defining the conditional breakpoint is aborted.
> This prevents having a conditional breakpoint whose condition may
> actually be meaningful for some of the location contexts.  This patch
> makes it possible to define conditional BPs by checking all location
> contexts.  If the condition is meaningful for even one context, the
> breakpoint is defined.  The locations for which the condition gives
> errors are disabled.
>
> The bp_location struct is introduced a new field, 'disabled_by_cond'.
> This field denotes whether the location is disabled automatically
> because the condition was non-evaluatable.  Disabled-by-cond locations
> cannot be enabled by the user.  But locations that are not
> disabled-by-cond can be enabled/disabled by the user manually as
> before.
>
> For a concrete example, consider 3 contexts; func1, func2, and func3.
> Each context contains instructions coming from the same source.
> For instance:
>
>   void
>   func1 (int *value)
>   {
>     int a = 10;
>     value += a;
>     int b = 1;
>   #include "included.c"
>   }
>
>   void
>   func2 (int *value)
>   {
>     int b = 2;
>   #include "included.c"
>   }
>
>   void
>   func3 (int *value)
>   {
>     int c = 30;
>     value += c;
>     int b = 3;
>   #include "included.c"
>   }

A C++ example with overloaded functions would be simpler to understand,
I think.

>
> Note that
>
> * the variable 'a' is defined only in the context defined by func1.
> * the variable 'c' is defined only in the context defined by func3.
> * the variable 'b' is defined in all the three contexts.
>
> With the existing GDB, it's not possible to define a conditional
> breakpoint at "included.c:1" if the condition refers to 'a' or 'c':
>
>   (gdb) break included.c:1 if a == 10
>   No symbol "a" in current context.
>   (gdb) break included.c:1 if c == 30
>   No symbol "c" in current context.
>   (gdb) info breakpoints
>   No breakpoints or watchpoints.
>
> With this patch, it becomes possible:
>
>   (gdb) break included.c:1 if a == 10
>   warning: disabling breakpoint location 2: No symbol "a" in current context.
>   warning: disabling breakpoint location 3: No symbol "a" in current context.

Though it would make the message a bit longer, I think it would be
important to mention in it that the location is disabled because GDB
failed to resolve (is the right word?) the condition at this location.

Most of the time it will be obvious, but I'm sure that in some cases it
won't be, and the user will be wondering what that error on the right is
about.  Just one example, if the condition expression involves a macro
that hides some identifiers:

  #define SOME_EXPR s

and

  (gdb) b bar if SOME_EXPR
  warning: disabling breakpoint location 2: No symbol "s" in current context.
  Breakpoint 1 at 0x1120: bar. (2 locations)
  (gdb) i b
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if SOME_EXPR
  1.1                         n   0x0000000000001120 in bar(int) at test.c:11
  1.2                         y   0x000000000000112b in bar(char const*) at test.c:15

I'm not sure what format is better:

  warning: failed to resolve condition at location 2, disabing: No symbol "a" in current context.

vs

  disabling breakpoint location 2: failed to resolve condition: No symbol "a" in current context.

vs

  warning: failed to resolve condition at location 2: No symbol "a" in current context.
  warning: disabling breakpoint location 2.

It's a bit annoying that the exception message is capitalized and has a
period, otherwise this would have been a good candidate:

  warning: failed to resolve condition at location 2 (no symbol "a" in current context), disabling.

>   Breakpoint 1 at 0x117d: included.c:1. (3 locations)
>   (gdb) break included.c:1 if c == 30
>   Note: breakpoint 1 also set at pc 0x117d.
>   warning: disabling breakpoint location 1: No symbol "c" in current context.
>   Note: breakpoint 1 also set at pc 0x119c.
>   warning: disabling breakpoint location 2: No symbol "c" in current context.
>   Note: breakpoint 1 also set at pc 0x11cf.
>   Breakpoint 2 at 0x117d: included.c:1. (3 locations)
>   (gdb) info break
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if a == 10
>   1.1                         y   0x000000000000117d in func1 at included.c:1
>   1.2                         n   0x000000000000119c in func2 at included.c:1
>   1.3                         n   0x00000000000011cf in func3 at included.c:1
>   2       breakpoint     keep y   <MULTIPLE>
>           stop only if c == 30
>   2.1                         n   0x000000000000117d in func1 at included.c:1
>   2.2                         n   0x000000000000119c in func2 at included.c:1
>   2.3                         y   0x00000000000011cf in func3 at included.c:1

Should we somehow show in the listing that the locations disabled
because of the condition are disabled and can't be enabled?  For
example, a capital N in the "Enb" column?

>
> Executing the code hits the breakpoints 1.1 and 2.3 as expected.
>
> Defining a condition on an unconditional breakpoint gives the same
> behavior above:
>
>   (gdb) break included.c:1
>   Breakpoint 1 at 0x117d: included.c:1. (3 locations)
>   (gdb) cond 1 a == 10
>   warning: disabling breakpoint 1.2: No symbol "a" in current context.
>   warning: disabling breakpoint 1.3: No symbol "a" in current context.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if a == 10
>   1.1                         y   0x000000000000117d in func1 at included.c:1
>   1.2                         n   0x000000000000119c in func2 at included.c:1
>   1.3                         n   0x00000000000011cf in func3 at included.c:1
>
> Locations that are disabled because of a condition cannot be enabled
> by the user:
>
>   ...
>   (gdb) enable 1.2
>   Location is disabled because of the condition; cannot enable manually.

"because of the condition" does not sound clear to me.  It does not say
what about the condition prevents the location from getting enabled.
What about something like "Breakpoint condition is invalid at location
1.2, cannot enable".  Ideally, we should make sure that the messages we
output at different times should use the same vocabulary.

>
> Resetting the condition enables the locations back:
>
>   ...
>   (gdb) cond 1
>   Breakpoint 1.2 is now enabled.
>   Breakpoint 1.3 is now enabled.

Likewise, this doesn't say why these locations suddenly get enabled.
Should it?  Something like "Breakpoint condition now resolves at
location 1.2, enabling.".  Or is it obvious, because the user is already
using the "condition" command?

>   Breakpoint 1 now unconditional.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>   1.1                         y   0x000000000000117d in func1 at included.c:1
>   1.2                         y   0x000000000000119c in func2 at included.c:1
>   1.3                         y   0x00000000000011cf in func3 at included.c:1
>
> If a location is disabled by the user, a condition can still be defined
> but the location will remain disabled even if the condition is meaningful
> for the disabled location:
>
>   ...
>   (gdb) disable 1.1
>   (gdb) cond 1 a == 10
>   warning: disabling breakpoint 1.2: No symbol "a" in current context.
>   warning: disabling breakpoint 1.3: No symbol "a" in current context.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if a == 10
>   1.1                         n   0x000000000000117d in func1 at included.c:1
>   1.2                         n   0x000000000000119c in func2 at included.c:1
>   1.3                         n   0x00000000000011cf in func3 at included.c:1

If a location is already user-disabled and we install a condition that
condition-disables it, we print a "disabling" message:

    (gdb) b bar
    Breakpoint 1 at 0x1120: bar. (2 locations)
    (gdb) disable 1.1 1.2
    (gdb) i b
    Num     Type           Disp Enb Address            What
    1       breakpoint     keep y   <MULTIPLE>
    1.1                         n   0x0000000000001120 in bar(int) at test.c:9
    1.2                         n   0x000000000000112b in bar(char const*) at test.c:13
    (gdb) cond 1 s
    warning: disabling breakpoint 1.1: No symbol "s" in current context.
    (gdb) i b
    Num     Type           Disp Enb Address            What
    1       breakpoint     keep y   <MULTIPLE>
            stop only if s
    1.1                         n   0x0000000000001120 in bar(int) at test.c:9
    1.2                         n   0x000000000000112b in bar(char const*) at test.c:13

Should the "disabling breakpoint" message not be printed here, since it
doesn't really make sense to disable an already disabled breakpoint?  If
the user tries to enable it back, then they'll get the "can't enable"
message.

> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 977599db1db..7abfd510abc 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -830,6 +830,48 @@ get_first_locp_gte_addr (CORE_ADDR address)
>    return locp_found;
>  }
>
> +/* Parse COND_STRING in the context of LOC and set as the condition
> +   expression of LOC.  BP_NUM is the number of LOC's owner, LOC_NUM is
> +   the number of LOC within its owner.  In case of parsing error, mark
> +   LOC as DISABLED_BY_COND.  In case of success, unset DISABLED_BY_COND.  */
> +
> +static void
> +set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
> +				   int bp_num, int loc_num)
> +{
> +  bool has_junk = false;
> +  try
> +    {
> +      expression_up new_exp = parse_exp_1 (&cond_string, loc->address,
> +					   block_for_pc (loc->address), 0);
> +      if (*cond_string != 0)
> +	has_junk = true;
> +      else
> +	{
> +	  loc->cond = std::move (new_exp);
> +	  if (loc->disabled_by_cond && loc->enabled)
> +	    printf_filtered (_("Breakpoint %d.%d is now enabled.\n"),
> +			     bp_num, loc_num);
> +
> +	  loc->disabled_by_cond = false;
> +	}
> +    }
> +  catch (const gdb_exception_error &e)
> +    {
> +      if (bp_num != 0)
> +	warning (_("disabling breakpoint %d.%d: %s"),
> +		 bp_num, loc_num, e.what ());
> +      else
> +	warning (_("disabling breakpoint location %d: %s"),
> +		 loc_num, e.what ());

When is bp_num 0?

> @@ -14157,6 +14258,10 @@ enable_disable_bp_num_loc (int bp_num, int loc_num, bool enable)
>    struct bp_location *loc = find_location_by_number (bp_num, loc_num);
>    if (loc != NULL)
>      {
> +      if (loc->disabled_by_cond && enable)
> +	error(_("Location is disabled because of the condition; "

Space after "error".

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-09-19  3:05     ` Simon Marchi
@ 2020-09-25 15:49       ` Aktemur, Tankut Baris
  2020-09-25 16:10         ` Simon Marchi
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-09-25 15:49 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Saturday, September 19, 2020 5:06 AM, Simon Marchi wrote:
> Hi Baris,
> 
> I don't have much time right now, but I also don't want to delay looking
> at this further, so here are a few comments.  Overall, I think that this
> is very well thought through and I like the behavior.
> 
> On 2020-08-20 5:24 p.m., Tankut Baris Aktemur via Gdb-patches wrote:
> > Currently, for a conditional breakpoint, GDB checks if the condition
> > can be evaluated in the context of the first symtab and line (SAL).
> > In case of an error, defining the conditional breakpoint is aborted.
> > This prevents having a conditional breakpoint whose condition may
> > actually be meaningful for some of the location contexts.  This patch
> > makes it possible to define conditional BPs by checking all location
> > contexts.  If the condition is meaningful for even one context, the
> > breakpoint is defined.  The locations for which the condition gives
> > errors are disabled.
> >
> > The bp_location struct is introduced a new field, 'disabled_by_cond'.
> > This field denotes whether the location is disabled automatically
> > because the condition was non-evaluatable.  Disabled-by-cond locations
> > cannot be enabled by the user.  But locations that are not
> > disabled-by-cond can be enabled/disabled by the user manually as
> > before.
> >
> > For a concrete example, consider 3 contexts; func1, func2, and func3.
> > Each context contains instructions coming from the same source.
> > For instance:
> >
> >   void
> >   func1 (int *value)
> >   {
> >     int a = 10;
> >     value += a;
> >     int b = 1;
> >   #include "included.c"
> >   }
> >
> >   void
> >   func2 (int *value)
> >   {
> >     int b = 2;
> >   #include "included.c"
> >   }
> >
> >   void
> >   func3 (int *value)
> >   {
> >     int c = 30;
> >     value += c;
> >     int b = 3;
> >   #include "included.c"
> >   }
> 
> A C++ example with overloaded functions would be simpler to understand,
> I think.

I changed the example in the commit message and the test to use the following:

  class Base
  {
  public:
    int b = 20;

    void func () {}
  };

  class A : public Base
  {
  public:
    int a = 10;

    void func () {}
  };

  class C : public Base
  {
  public:
    int c = 30;

    void func () {}
  };

> 
> >
> > Note that
> >
> > * the variable 'a' is defined only in the context defined by func1.
> > * the variable 'c' is defined only in the context defined by func3.
> > * the variable 'b' is defined in all the three contexts.
> >
> > With the existing GDB, it's not possible to define a conditional
> > breakpoint at "included.c:1" if the condition refers to 'a' or 'c':
> >
> >   (gdb) break included.c:1 if a == 10
> >   No symbol "a" in current context.
> >   (gdb) break included.c:1 if c == 30
> >   No symbol "c" in current context.
> >   (gdb) info breakpoints
> >   No breakpoints or watchpoints.
> >
> > With this patch, it becomes possible:
> >
> >   (gdb) break included.c:1 if a == 10
> >   warning: disabling breakpoint location 2: No symbol "a" in current context.
> >   warning: disabling breakpoint location 3: No symbol "a" in current context.
> 
> Though it would make the message a bit longer, I think it would be
> important to mention in it that the location is disabled because GDB
> failed to resolve (is the right word?) the condition at this location.
> 
> Most of the time it will be obvious, but I'm sure that in some cases it
> won't be, and the user will be wondering what that error on the right is
> about.  Just one example, if the condition expression involves a macro
> that hides some identifiers:
> 
>   #define SOME_EXPR s
> 
> and
> 
>   (gdb) b bar if SOME_EXPR
>   warning: disabling breakpoint location 2: No symbol "s" in current context.
>   Breakpoint 1 at 0x1120: bar. (2 locations)
>   (gdb) i b
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if SOME_EXPR
>   1.1                         n   0x0000000000001120 in bar(int) at test.c:11
>   1.2                         y   0x000000000000112b in bar(char const*) at test.c:15
> 
> I'm not sure what format is better:
> 
>   warning: failed to resolve condition at location 2, disabing: No symbol "a" in current
> context.
> 
> vs
> 
>   disabling breakpoint location 2: failed to resolve condition: No symbol "a" in current
> context.
> 
> vs
> 
>   warning: failed to resolve condition at location 2: No symbol "a" in current context.
>   warning: disabling breakpoint location 2.
> 
> It's a bit annoying that the exception message is capitalized and has a
> period, otherwise this would have been a good candidate:
> 
>   warning: failed to resolve condition at location 2 (no symbol "a" in current context),
> disabling.

While revising the code, I noticed that when the breakpoint is being defined for 
the first time using "break" command, the locations are re-ordered according to
their addresses.  So, tracking and reporting the location number as we iterate over
SALs is useless.  Instead, we can report the location address.

Based on this, how about the first option you gave above, but using "validate" instead
of "resolve"?  For the "break" command, it reports the address in hex:

  warning: failed to validate condition at location 0x1120, disabling: No symbol "a" in current context.

But for the "cond" command, the location number is used because it's stable.

  warning: failed to validate condition at location 2, disabling: No symbol "a" in current context.

Perhaps we can break the message at the comma to avoid this long line.

> >   Breakpoint 1 at 0x117d: included.c:1. (3 locations)
> >   (gdb) break included.c:1 if c == 30
> >   Note: breakpoint 1 also set at pc 0x117d.
> >   warning: disabling breakpoint location 1: No symbol "c" in current context.
> >   Note: breakpoint 1 also set at pc 0x119c.
> >   warning: disabling breakpoint location 2: No symbol "c" in current context.
> >   Note: breakpoint 1 also set at pc 0x11cf.
> >   Breakpoint 2 at 0x117d: included.c:1. (3 locations)
> >   (gdb) info break
> >   Num     Type           Disp Enb Address            What
> >   1       breakpoint     keep y   <MULTIPLE>
> >           stop only if a == 10
> >   1.1                         y   0x000000000000117d in func1 at included.c:1
> >   1.2                         n   0x000000000000119c in func2 at included.c:1
> >   1.3                         n   0x00000000000011cf in func3 at included.c:1
> >   2       breakpoint     keep y   <MULTIPLE>
> >           stop only if c == 30
> >   2.1                         n   0x000000000000117d in func1 at included.c:1
> >   2.2                         n   0x000000000000119c in func2 at included.c:1
> >   2.3                         y   0x00000000000011cf in func3 at included.c:1
> 
> Should we somehow show in the listing that the locations disabled
> because of the condition are disabled and can't be enabled?  For
> example, a capital N in the "Enb" column?

I like the capital N notation.  Patch is updated.
 
> >
> > Executing the code hits the breakpoints 1.1 and 2.3 as expected.
> >
> > Defining a condition on an unconditional breakpoint gives the same
> > behavior above:
> >
> >   (gdb) break included.c:1
> >   Breakpoint 1 at 0x117d: included.c:1. (3 locations)
> >   (gdb) cond 1 a == 10
> >   warning: disabling breakpoint 1.2: No symbol "a" in current context.
> >   warning: disabling breakpoint 1.3: No symbol "a" in current context.
> >   (gdb) info breakpoints
> >   Num     Type           Disp Enb Address            What
> >   1       breakpoint     keep y   <MULTIPLE>
> >           stop only if a == 10
> >   1.1                         y   0x000000000000117d in func1 at included.c:1
> >   1.2                         n   0x000000000000119c in func2 at included.c:1
> >   1.3                         n   0x00000000000011cf in func3 at included.c:1
> >
> > Locations that are disabled because of a condition cannot be enabled
> > by the user:
> >
> >   ...
> >   (gdb) enable 1.2
> >   Location is disabled because of the condition; cannot enable manually.
> 
> "because of the condition" does not sound clear to me.  It does not say
> what about the condition prevents the location from getting enabled.
> What about something like "Breakpoint condition is invalid at location
> 1.2, cannot enable".  Ideally, we should make sure that the messages we
> output at different times should use the same vocabulary.

Done, with a small change:

  Breakpoint 1's condition is invalid at location 2, cannot enable.

OK with this?
 
> >
> > Resetting the condition enables the locations back:
> >
> >   ...
> >   (gdb) cond 1
> >   Breakpoint 1.2 is now enabled.
> >   Breakpoint 1.3 is now enabled.
> 
> Likewise, this doesn't say why these locations suddenly get enabled.
> Should it?  Something like "Breakpoint condition now resolves at
> location 1.2, enabling.".  Or is it obvious, because the user is already
> using the "condition" command?

I think it's useful to say a bit more because the user may have forgotten about
the condition.  To be consistent with the message above, how about this:

  Breakpoint 1's condition is now valid at location 2, enabling.

One additional note: I noticed that the existing "Breakpoint N is now unconditional"
message is guarded by 'from_tty'.  I added the same guard to the "...enabling"
messages, too.

> >   Breakpoint 1 now unconditional.
> >   (gdb) info breakpoints
> >   Num     Type           Disp Enb Address            What
> >   1       breakpoint     keep y   <MULTIPLE>
> >   1.1                         y   0x000000000000117d in func1 at included.c:1
> >   1.2                         y   0x000000000000119c in func2 at included.c:1
> >   1.3                         y   0x00000000000011cf in func3 at included.c:1
> >
> > If a location is disabled by the user, a condition can still be defined
> > but the location will remain disabled even if the condition is meaningful
> > for the disabled location:
> >
> >   ...
> >   (gdb) disable 1.1
> >   (gdb) cond 1 a == 10
> >   warning: disabling breakpoint 1.2: No symbol "a" in current context.
> >   warning: disabling breakpoint 1.3: No symbol "a" in current context.
> >   (gdb) info breakpoints
> >   Num     Type           Disp Enb Address            What
> >   1       breakpoint     keep y   <MULTIPLE>
> >           stop only if a == 10
> >   1.1                         n   0x000000000000117d in func1 at included.c:1
> >   1.2                         n   0x000000000000119c in func2 at included.c:1
> >   1.3                         n   0x00000000000011cf in func3 at included.c:1
> 
> If a location is already user-disabled and we install a condition that
> condition-disables it, we print a "disabling" message:
> 
>     (gdb) b bar
>     Breakpoint 1 at 0x1120: bar. (2 locations)
>     (gdb) disable 1.1 1.2
>     (gdb) i b
>     Num     Type           Disp Enb Address            What
>     1       breakpoint     keep y   <MULTIPLE>
>     1.1                         n   0x0000000000001120 in bar(int) at test.c:9
>     1.2                         n   0x000000000000112b in bar(char const*) at test.c:13
>     (gdb) cond 1 s
>     warning: disabling breakpoint 1.1: No symbol "s" in current context.
>     (gdb) i b
>     Num     Type           Disp Enb Address            What
>     1       breakpoint     keep y   <MULTIPLE>
>             stop only if s
>     1.1                         n   0x0000000000001120 in bar(int) at test.c:9
>     1.2                         n   0x000000000000112b in bar(char const*) at test.c:13
> 
> Should the "disabling breakpoint" message not be printed here, since it
> doesn't really make sense to disable an already disabled breakpoint?  If
> the user tries to enable it back, then they'll get the "can't enable"
> message.

OK, sure. That makes sense.

> > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> > index 977599db1db..7abfd510abc 100644
> > --- a/gdb/breakpoint.c
> > +++ b/gdb/breakpoint.c
> > @@ -830,6 +830,48 @@ get_first_locp_gte_addr (CORE_ADDR address)
> >    return locp_found;
> >  }
> >
> > +/* Parse COND_STRING in the context of LOC and set as the condition
> > +   expression of LOC.  BP_NUM is the number of LOC's owner, LOC_NUM is
> > +   the number of LOC within its owner.  In case of parsing error, mark
> > +   LOC as DISABLED_BY_COND.  In case of success, unset DISABLED_BY_COND.  */
> > +
> > +static void
> > +set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
> > +				   int bp_num, int loc_num)
> > +{
> > +  bool has_junk = false;
> > +  try
> > +    {
> > +      expression_up new_exp = parse_exp_1 (&cond_string, loc->address,
> > +					   block_for_pc (loc->address), 0);
> > +      if (*cond_string != 0)
> > +	has_junk = true;
> > +      else
> > +	{
> > +	  loc->cond = std::move (new_exp);
> > +	  if (loc->disabled_by_cond && loc->enabled)
> > +	    printf_filtered (_("Breakpoint %d.%d is now enabled.\n"),
> > +			     bp_num, loc_num);
> > +
> > +	  loc->disabled_by_cond = false;
> > +	}
> > +    }
> > +  catch (const gdb_exception_error &e)
> > +    {
> > +      if (bp_num != 0)
> > +	warning (_("disabling breakpoint %d.%d: %s"),
> > +		 bp_num, loc_num, e.what ());
> > +      else
> > +	warning (_("disabling breakpoint location %d: %s"),
> > +		 loc_num, e.what ());
> 
> When is bp_num 0?

It's 0 if the breakpoint is being defined for the first time using the
"break ... if ..." command.  It's non-zero if defined previously and is now
becoming conditional.
 
> > @@ -14157,6 +14258,10 @@ enable_disable_bp_num_loc (int bp_num, int loc_num, bool enable)
> >    struct bp_location *loc = find_location_by_number (bp_num, loc_num);
> >    if (loc != NULL)
> >      {
> > +      if (loc->disabled_by_cond && enable)
> > +	error(_("Location is disabled because of the condition; "
> 
> Space after "error".

Fixed.
 
Thank you.
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v3 0/2] Breakpoint conditions at locations with differing contexts
  2020-07-31 15:42 [PATCH 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
       [not found] ` <cover.1596209606.git.tankut.baris.aktemur@intel.com>
  2020-08-20 21:24 ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
@ 2020-09-25 15:51 ` Tankut Baris Aktemur
  2020-09-25 15:51   ` [PATCH v3 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
  2020-09-25 15:51   ` [PATCH v3 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
  2020-10-13 12:25 ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
  2021-04-05 17:45 ` [PATCH " Jonah Graham
  4 siblings, 2 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-09-25 15:51 UTC (permalink / raw)
  To: gdb-patches; +Cc: simark

Hi,

This is a follow-up of

  https://sourceware.org/pipermail/gdb-patches/2020-July/170984.html

which is a short series about conditional breakpoints where the
condition may be invalid at some breakpoint locations because of their
context.  Currently, GDB does not allow defining a condition if it's
not valid at all locations.  This series aims at bringing more
flexibility: the locations at which the condition expression is
invalid are disabled automatically.

In v2, I extended Patch 2/2 with the '-force-condition' flag for the break
command, added test cases and more documentation.

In this revision (v3), warning messages are updated based on Simon Marchi's
comments at https://sourceware.org/pipermail/gdb-patches/2020-September/171970.html.
I also revised the documentation changes.

Regards.
Baris

Tankut Baris Aktemur (2):
  gdb/breakpoint: disable a bp location if condition is invalid at that
    location
  gdb/breakpoint: add flags to 'condition' and 'break' commands to force
    condition

 gdb/ada-lang.c                                |   2 +-
 gdb/breakpoint.c                              | 260 ++++++++++++++----
 gdb/breakpoint.h                              |  12 +-
 gdb/doc/gdb.texinfo                           |  64 +++++
 gdb/guile/scm-breakpoint.c                    |   2 +-
 gdb/linespec.c                                |  18 +-
 gdb/python/py-breakpoint.c                    |   2 +-
 .../gdb.base/condbreak-multi-context.cc       |  54 ++++
 .../gdb.base/condbreak-multi-context.exp      | 237 ++++++++++++++++
 gdb/testsuite/gdb.linespec/cpcompletion.exp   |  12 +-
 gdb/testsuite/gdb.linespec/explicit.exp       |   1 +
 gdb/testsuite/lib/completion-support.exp      |   2 +-
 12 files changed, 599 insertions(+), 67 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.cc
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v3 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-09-25 15:51 ` [PATCH v3 " Tankut Baris Aktemur
@ 2020-09-25 15:51   ` Tankut Baris Aktemur
  2020-09-25 15:51   ` [PATCH v3 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
  1 sibling, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-09-25 15:51 UTC (permalink / raw)
  To: gdb-patches; +Cc: simark

Currently, for a conditional breakpoint, GDB checks if the condition
can be evaluated in the context of the first symtab and line (SAL).
In case of an error, defining the conditional breakpoint is aborted.
This prevents having a conditional breakpoint whose condition may
actually be meaningful for some of the location contexts.  This patch
makes it possible to define conditional BPs by checking all location
contexts.  If the condition is meaningful for even one context, the
breakpoint is defined.  The locations for which the condition gives
errors are disabled.

The bp_location struct is introduced a new field, 'disabled_by_cond'.
This field denotes whether the location is disabled automatically
because the condition was non-evaluatable.  Disabled-by-cond locations
cannot be enabled by the user.  But locations that are not
disabled-by-cond can be enabled/disabled by the user manually as
before.

For a concrete example, consider 3 contexts of a function 'func'.

  class Base
  {
  public:
    int b = 20;

    void func () {}
  };

  class A : public Base
  {
  public:
    int a = 10;

    void func () {}
  };

  class C : public Base
  {
  public:
    int c = 30;

    void func () {}
  };

Note that

* the variable 'a' is defined only in the context of A::func.
* the variable 'c' is defined only in the context of C::func.
* the variable 'b' is defined in all the three contexts.

With the existing GDB, it's not possible to define a conditional
breakpoint at 'func' if the condition refers to 'a' or 'c':

  (gdb) break func if a == 10
  No symbol "a" in current context.
  (gdb) break func if c == 30
  No symbol "c" in current context.
  (gdb) info breakpoints
  No breakpoints or watchpoints.

With this patch, it becomes possible:

  (gdb) break func if a == 10
  warning: failed to validate condition at location 0x11ce, disabling: No symbol "a" in current context.
  warning: failed to validate condition at location 0x11b6, disabling: No symbol "a" in current context.
  Breakpoint 1 at 0x11b6: func. (3 locations)
  (gdb) break func if c == 30
  Note: breakpoint 1 also set at pc 0x11ce.
  Note: breakpoint 1 also set at pc 0x11c2.
  warning: failed to validate condition at location 0x11c2, disabling: No symbol "c" in current context.
  Note: breakpoint 1 also set at pc 0x11b6.
  warning: failed to validate condition at location 0x11b6, disabling: No symbol "c" in current context.
  Breakpoint 2 at 0x11b6: func. (3 locations)
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         N   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         N   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
  2       breakpoint     keep y   <MULTIPLE>
          stop only if c == 30
  2.1                         N   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  2.2                         N   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  2.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39

Here, uppercase 'N' denotes that the location is disabled because of
the invalid condition.  Locations that are disabled by the user are
still denoted with lowercase 'n'.  Executing the code hits the
breakpoints 1.2 and 2.3 as expected.

Defining a condition on an unconditional breakpoint gives the same
behavior above:

  (gdb) break func
  Breakpoint 1 at 0x11b6: func. (3 locations)
  (gdb) cond 1 a == 10
  warning: failed to validate condition at location 1.1, disabling: No symbol "a" in current context.
  warning: failed to validate condition at location 1.3, disabling: No symbol "a" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         N   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         N   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39

Locations that are disabled because of a condition cannot be enabled
by the user:

  ...
  (gdb) enable 1.1
  Breakpoint 1's condition is invalid at location 1, cannot enable.

Resetting the condition enables the locations back:

  ...
  (gdb) cond 1
  Breakpoint 1's condition is now valid at location 1, enabling.
  Breakpoint 1's condition is now valid at location 3, enabling.
  Breakpoint 1 now unconditional.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
  1.1                         y   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39

If a location is disabled by the user, a condition can still be defined
but the location will remain disabled even if the condition is meaningful
for the disabled location:

  ...
  (gdb) disable 1.2
  (gdb) cond 1 a == 10
  warning: failed to validate condition at location 1.1, disabling: No symbol "a" in current context.
  warning: failed to validate condition at location 1.3, disabling: No symbol "a" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         N   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         n   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         N   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39

The condition of a breakpoint can be changed.  Locations'
enable/disable states are updated accordingly.

  ...
  (gdb) cond 1 c == 30
  warning: failed to validate condition at location 1.1, disabling: No symbol "c" in current context.
  Breakpoint 1's condition is now valid at location 3, enabling.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if c == 30
  1.1                         N   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         N   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39

  (gdb) cond 1 b == 20
  Breakpoint 1's condition is now valid at location 1, enabling.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if b == 20
  1.1                         y   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         n   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
  # Note that location 1.2 was disabled by the user previously.

If the condition expression is bad for all the locations, it will be
rejected.

  (gdb) cond 1 garbage
  No symbol "garbage" in current context.

For conditions that are invalid or valid for all the locations of a
breakpoint, the existing behavior is preserved.

Regression-tested on X86_64 Linux.

gdb/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (class bp_location) <disabled_by_cond>: New field.
	* breakpoint.c (set_breakpoint_location_condition): New function.
	(set_breakpoint_condition): Disable a breakpoint
	location if parsing the condition string gives an error.
	(should_be_inserted): Update to consider the 'disabled_by_cond' field.
	(build_target_condition_list): Ditto.
	(build_target_command_list): Ditto.
	(build_bpstat_chain): Ditto.
	(print_one_breakpoint_location): Ditto.
	(print_one_breakpoint): Ditto.
	(bp_location::bp_location): Ditto.
	(locations_are_equal): Ditto.
	(update_breakpoint_locations): Ditto.
	(enable_disable_bp_num_loc): Ditto.
	(init_breakpoint_sal): Use set_breakpoint_location_condition.
	(find_condition_and_thread_for_sals): New static function.
	(create_breakpoint): Call find_condition_and_thread_for_sals.
	(location_to_sals): Call find_condition_and_thread_for_sals instead
	of find_condition_and_thread.

gdb/testsuite/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.base/condbreak-multi-context.cc: New file.
	* gdb.base/condbreak-multi-context.exp: New file.

gdb/doc/ChangeLog:
2020-09-25  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo: Document disabling of breakpoint locations for which
	the breakpoint condition is invalid.
---
 gdb/breakpoint.c                              | 212 +++++++++++++----
 gdb/breakpoint.h                              |   6 +
 gdb/doc/gdb.texinfo                           |  37 +++
 .../gdb.base/condbreak-multi-context.cc       |  54 +++++
 .../gdb.base/condbreak-multi-context.exp      | 215 ++++++++++++++++++
 5 files changed, 476 insertions(+), 48 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.cc
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index e0712b2ea9d..37f673603b2 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -830,6 +830,59 @@ get_first_locp_gte_addr (CORE_ADDR address)
   return locp_found;
 }
 
+/* Parse COND_STRING in the context of LOC and set as the condition
+   expression of LOC.  BP_NUM is the number of LOC's owner, LOC_NUM is
+   the number of LOC within its owner.  In case of parsing error, mark
+   LOC as DISABLED_BY_COND.  In case of success, unset DISABLED_BY_COND.  */
+
+static void
+set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
+				   int bp_num, int loc_num, bool from_tty)
+{
+  bool has_junk = false;
+  try
+    {
+      expression_up new_exp = parse_exp_1 (&cond_string, loc->address,
+					   block_for_pc (loc->address), 0);
+      if (*cond_string != 0)
+	has_junk = true;
+      else
+	{
+	  loc->cond = std::move (new_exp);
+	  if (from_tty && loc->disabled_by_cond && loc->enabled)
+	    printf_filtered (_("Breakpoint %d's condition is now valid at "
+			       "location %d, enabling.\n"),
+			     bp_num, loc_num);
+
+	  loc->disabled_by_cond = false;
+	}
+    }
+  catch (const gdb_exception_error &e)
+    {
+      if (loc->enabled)
+	{
+	  /* Warn if a user-enabled location is now becoming disabled-by-cond.
+	     BP_NUM is 0 if the breakpoint is being defined for the first
+	     time using the "break ... if ..." command, and non-zero if
+	     already defined.  If former, do not use LOC_NUM, because
+	     as the locations are being inserted, they are re-ordered.  */
+	  if (bp_num != 0)
+	    warning (_("failed to validate condition at location %d.%d, "
+		       "disabling: %s"),
+		     bp_num, loc_num, e.what ());
+	  else
+	    warning (_("failed to validate condition at location %s, "
+		       "disabling: %s"),
+		     paddress (loc->gdbarch, loc->address), e.what ());
+	}
+
+      loc->disabled_by_cond = true;
+    }
+
+  if (has_junk)
+    error (_("Garbage '%s' follows condition"), cond_string);
+}
+
 void
 set_breakpoint_condition (struct breakpoint *b, const char *exp,
 			  int from_tty)
@@ -843,9 +896,16 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	static_cast<watchpoint *> (b)->cond_exp.reset ();
       else
 	{
+	  int loc_num = 1;
 	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
 	    {
 	      loc->cond.reset ();
+	      if (from_tty && loc->disabled_by_cond && loc->enabled)
+		printf_filtered (_("Breakpoint %d's condition is now valid at "
+				   "location %d, enabling.\n"),
+				 b->number, loc_num);
+	      loc->disabled_by_cond = false;
+	      loc_num++;
 
 	      /* No need to free the condition agent expression
 		 bytecode (if we have one).  We will handle this
@@ -873,29 +933,38 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	{
 	  /* Parse and set condition expressions.  We make two passes.
 	     In the first, we parse the condition string to see if it
-	     is valid in all locations.  If so, the condition would be
-	     accepted.  So we go ahead and set the locations'
-	     conditions.  In case a failing case is found, we throw
+	     is valid in at least one location.  If so, the condition
+	     would be accepted.  So we go ahead and set the locations'
+	     conditions.  In case no valid case is found, we throw
 	     the error and the condition string will be rejected.
 	     This two-pass approach is taken to avoid setting the
 	     state of locations in case of a reject.  */
 	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
 	    {
-	      const char *arg = exp;
-	      parse_exp_1 (&arg, loc->address,
-			   block_for_pc (loc->address), 0);
-	      if (*arg != 0)
-		error (_("Junk at end of expression"));
+	      try
+		{
+		  const char *arg = exp;
+		  parse_exp_1 (&arg, loc->address,
+			       block_for_pc (loc->address), 0);
+		  if (*arg != 0)
+		    error (_("Junk at end of expression"));
+		  break;
+		}
+	      catch (const gdb_exception_error &e)
+		{
+		  /* Condition string is invalid.  If this happens to
+		     be the last loc, abandon.  */
+		  if (loc->next == nullptr)
+		    throw;
+		}
 	    }
 
-	  /* If we reach here, the condition is valid at all locations.  */
-	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
-	    {
-	      const char *arg = exp;
-	      loc->cond =
-		parse_exp_1 (&arg, loc->address,
-			     block_for_pc (loc->address), 0);
-	    }
+	  /* If we reach here, the condition is valid at some locations.  */
+          int loc_num = 1;
+          for (bp_location *loc = b->loc; loc != nullptr;
+               loc = loc->next, loc_num++)
+            set_breakpoint_location_condition (exp, loc, b->number, loc_num,
+					       from_tty);
 	}
 
       /* We know that the new condition parsed successfully.  The
@@ -2010,7 +2079,8 @@ should_be_inserted (struct bp_location *bl)
   if (bl->owner->disposition == disp_del_at_next_stop)
     return 0;
 
-  if (!bl->enabled || bl->shlib_disabled || bl->duplicate)
+  if (!bl->enabled || bl->disabled_by_cond
+      || bl->shlib_disabled || bl->duplicate)
     return 0;
 
   if (user_breakpoint_p (bl->owner) && bl->pspace->executing_startup)
@@ -2205,7 +2275,8 @@ build_target_condition_list (struct bp_location *bl)
 	  && is_breakpoint (loc->owner)
 	  && loc->pspace->num == bl->pspace->num
 	  && loc->owner->enable_state == bp_enabled
-	  && loc->enabled)
+	  && loc->enabled
+	  && !loc->disabled_by_cond)
 	{
 	  /* Add the condition to the vector.  This will be used later
 	     to send the conditions to the target.  */
@@ -2395,7 +2466,8 @@ build_target_command_list (struct bp_location *bl)
 	  && is_breakpoint (loc->owner)
 	  && loc->pspace->num == bl->pspace->num
 	  && loc->owner->enable_state == bp_enabled
-	  && loc->enabled)
+	  && loc->enabled
+	  && !loc->disabled_by_cond)
 	{
 	  /* Add the command to the vector.  This will be used later
 	     to send the commands to the target.  */
@@ -5278,7 +5350,7 @@ build_bpstat_chain (const address_space *aspace, CORE_ADDR bp_addr,
 	  if (b->type == bp_hardware_watchpoint && bl != b->loc)
 	    break;
 
-	  if (!bl->enabled || bl->shlib_disabled)
+	  if (!bl->enabled || bl->disabled_by_cond || bl->shlib_disabled)
 	    continue;
 
 	  if (!bpstat_check_location (bl, aspace, bp_addr, ws))
@@ -5984,7 +6056,8 @@ print_one_breakpoint_location (struct breakpoint *b,
      breakpoints with single disabled location.  */
   if (loc == NULL 
       && (b->loc != NULL 
-	  && (b->loc->next != NULL || !b->loc->enabled)))
+	  && (b->loc->next != NULL
+	      || !b->loc->enabled || b->loc->disabled_by_cond)))
     header_of_multiple = 1;
   if (loc == NULL)
     loc = b->loc;
@@ -6015,7 +6088,8 @@ print_one_breakpoint_location (struct breakpoint *b,
   /* 4 */
   annotate_field (3);
   if (part_of_multiple)
-    uiout->field_string ("enabled", loc->enabled ? "y" : "n");
+    uiout->field_string ("enabled", (loc->disabled_by_cond ? "N"
+				     : (loc->enabled ? "y" : "n")));
   else
     uiout->field_fmt ("enabled", "%c", bpenables[(int) b->enable_state]);
 
@@ -6315,7 +6389,9 @@ print_one_breakpoint (struct breakpoint *b,
 	  && (!is_catchpoint (b) || is_exception_catchpoint (b)
 	      || is_ada_exception_catchpoint (b))
 	  && (allflag
-	      || (b->loc && (b->loc->next || !b->loc->enabled))))
+	      || (b->loc && (b->loc->next
+			     || !b->loc->enabled
+			     || b->loc->disabled_by_cond))))
 	{
 	  gdb::optional<ui_out_emit_list> locations_list;
 
@@ -6957,6 +7033,7 @@ bp_location::bp_location (breakpoint *owner, bp_loc_type type)
   this->cond_bytecode = NULL;
   this->shlib_disabled = 0;
   this->enabled = 1;
+  this->disabled_by_cond = false;
 
   this->loc_type = type;
 
@@ -8830,14 +8907,8 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 	}
 
       if (b->cond_string)
-	{
-	  const char *arg = b->cond_string;
-
-	  loc->cond = parse_exp_1 (&arg, loc->address,
-				   block_for_pc (loc->address), 0);
-	  if (*arg)
-              error (_("Garbage '%s' follows condition"), arg);
-	}
+	set_breakpoint_location_condition (b->cond_string, loc,
+					   b->number, 0, from_tty);
 
       /* Dynamic printf requires and uses additional arguments on the
 	 command line, otherwise it's an error.  */
@@ -9140,6 +9211,50 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
     }
 }
 
+/* Call 'find_condition_and_thread' for each sal in SALS until a parse
+   succeeds.  The parsed values are written to COND_STRING, THREAD,
+   TASK, and REST.  See the comment of 'find_condition_and_thread'
+   for the description of these parameters and INPUT.  */
+
+static void
+find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
+				    const char *input, char **cond_string,
+				    int *thread, int *task, char **rest)
+{
+  int num_failures = 0;
+  for (auto &sal : sals)
+    {
+      char *cond = nullptr;
+      int thread_id = 0;
+      int task_id = 0;
+      char *remaining = nullptr;
+
+      /* Here we want to parse 'arg' to separate condition from thread
+	 number.  But because parsing happens in a context and the
+	 contexts of sals might be different, try each until there is
+	 success.  Finding one successful parse is sufficient for our
+	 goal.  When setting the breakpoint we'll re-parse the
+	 condition in the context of each sal.  */
+      try
+	{
+	  find_condition_and_thread (input, sal.pc, &cond, &thread_id,
+				     &task_id, &remaining);
+	  *cond_string = cond;
+	  *thread = thread_id;
+	  *task = task_id;
+	  *rest = remaining;
+	  break;
+	}
+      catch (const gdb_exception_error &e)
+	{
+	  num_failures++;
+	  /* If no sal remains, do not continue.  */
+	  if (num_failures == sals.size ())
+	    throw;
+	}
+    }
+}
+
 /* Decode a static tracepoint marker spec.  */
 
 static std::vector<symtab_and_line>
@@ -9303,13 +9418,8 @@ create_breakpoint (struct gdbarch *gdbarch,
 
 	  const linespec_sals &lsal = canonical.lsals[0];
 
-	  /* Here we only parse 'arg' to separate condition
-	     from thread number, so parsing in context of first
-	     sal is OK.  When setting the breakpoint we'll
-	     re-parse it in context of each sal.  */
-
-	  find_condition_and_thread (extra_string, lsal.sals[0].pc,
-				     &cond, &thread, &task, &rest);
+	  find_condition_and_thread_for_sals (lsal.sals, extra_string,
+					      &cond, &thread, &task, &rest);
 	  cond_string_copy.reset (cond);
 	  extra_string_copy.reset (rest);
         }
@@ -13411,6 +13521,9 @@ locations_are_equal (struct bp_location *a, struct bp_location *b)
       if (a->enabled != b->enabled)
 	return 0;
 
+      if (a->disabled_by_cond != b->disabled_by_cond)
+	return 0;
+
       a = a->next;
       b = b->next;
     }
@@ -13518,10 +13631,7 @@ update_breakpoint_locations (struct breakpoint *b,
 	    }
 	  catch (const gdb_exception_error &e)
 	    {
-	      warning (_("failed to reevaluate condition "
-			 "for breakpoint %d: %s"), 
-		       b->number, e.what ());
-	      new_loc->enabled = 0;
+	      new_loc->disabled_by_cond = true;
 	    }
 	}
 
@@ -13546,7 +13656,7 @@ update_breakpoint_locations (struct breakpoint *b,
 
     for (; e; e = e->next)
       {
-	if (!e->enabled && e->function_name)
+	if ((!e->enabled || e->disabled_by_cond) && e->function_name)
 	  {
 	    struct bp_location *l = b->loc;
 	    if (have_ambiguous_names)
@@ -13562,7 +13672,8 @@ update_breakpoint_locations (struct breakpoint *b,
 		       enough.  */
 		    if (breakpoint_locations_match (e, l, true))
 		      {
-			l->enabled = 0;
+			l->enabled = e->enabled;
+			l->disabled_by_cond = e->disabled_by_cond;
 			break;
 		      }
 		  }
@@ -13573,7 +13684,8 @@ update_breakpoint_locations (struct breakpoint *b,
 		  if (l->function_name
 		      && strcmp (e->function_name, l->function_name) == 0)
 		    {
-		      l->enabled = 0;
+		      l->enabled = e->enabled;
+		      l->disabled_by_cond = e->disabled_by_cond;
 		      break;
 		    }
 	      }
@@ -13647,9 +13759,9 @@ location_to_sals (struct breakpoint *b, struct event_location *location,
 	  char *cond_string, *extra_string;
 	  int thread, task;
 
-	  find_condition_and_thread (b->extra_string, sals[0].pc,
-				     &cond_string, &thread, &task,
-				     &extra_string);
+	  find_condition_and_thread_for_sals (sals, b->extra_string,
+					      &cond_string, &thread,
+					      &task, &extra_string);
 	  gdb_assert (b->cond_string == NULL);
 	  if (cond_string)
 	    b->cond_string = cond_string;
@@ -14134,6 +14246,10 @@ enable_disable_bp_num_loc (int bp_num, int loc_num, bool enable)
   struct bp_location *loc = find_location_by_number (bp_num, loc_num);
   if (loc != NULL)
     {
+      if (loc->disabled_by_cond && enable)
+	error (_("Breakpoint %d's condition is invalid at location %d, "
+		 "cannot enable."), bp_num, loc_num);
+
       if (loc->enabled != enable)
 	{
 	  loc->enabled = enable;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index b9a605e6119..7d02cedf2fa 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -387,6 +387,12 @@ class bp_location
   /* Is this particular location enabled.  */
   bool enabled = false;
   
+  /* Is this particular location disabled because the condition
+     expression is invalid at this location.  For a location to be
+     reported as enabled, the ENABLED field above has to be true *and*
+     the DISABLED_BY_COND field has to be false.  */
+  bool disabled_by_cond = false;
+
   /* True if this breakpoint is now inserted.  */
   bool inserted = false;
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8bff27c940d..976bb1d4d60 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4278,6 +4278,43 @@ value is nonzero---that is, if @var{cond} evaluates as true.
 above (or no argument) specifying where to break.  @xref{Conditions,
 ,Break Conditions}, for more information on breakpoint conditions.
 
+The breakpoint may be mapped to multiple locations.  If the breakpoint
+condition @var{cond} is invalid at some but not all of the locations,
+the locations for which the condition is invalid are disabled.  For
+example, @value{GDBN} reports below that two of the three locations
+are disabled.
+
+@smallexample
+(@value{GDBP}) break func if a == 10
+warning: failed to validate condition at location 0x11ce, disabling: No symbol "a" in current context.
+warning: failed to validate condition at location 0x11b6, disabling: No symbol "a" in current context.
+Breakpoint 1 at 0x11b6: func. (3 locations)
+@end smallexample
+
+Locations that are disabled because of the condition are denoted by an
+uppercase @code{N} in the output of the @code{info breakpoints}
+command:
+
+@smallexample
+(@value{GDBP}) info breakpoints
+Num     Type           Disp Enb Address            What
+1       breakpoint     keep y   <MULTIPLE>
+        stop only if a == 10
+1.1                         N   0x00000000000011b6 in ...
+1.2                         y   0x00000000000011c2 in ...
+1.3                         N   0x00000000000011ce in ...
+@end smallexample
+
+If the breakpoint condition @var{cond} is invalid in the context of
+@emph{all} the locations of the breakpoint, @value{GDBN} refuses to
+define the breakpoint.  For example, if variable @code{foo} is an
+undefined variable:
+
+@smallexample
+(@value{GDBP}) break func if foo
+No symbol "foo" in current context.
+@end smallexample
+
 @kindex tbreak
 @item tbreak @var{args}
 Set a breakpoint enabled only for one stop.  The @var{args} are the
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.cc b/gdb/testsuite/gdb.base/condbreak-multi-context.cc
new file mode 100644
index 00000000000..5e994e2428e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.cc
@@ -0,0 +1,54 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class Base
+{
+public:
+  int b = 20;
+
+  void func () {}
+};
+
+class A : public Base
+{
+public:
+  int a = 10;
+
+  void func () {}
+};
+
+class C : public Base
+{
+public:
+  int c = 30;
+
+  void func () {}
+};
+
+int
+main ()
+{
+  Base bobj;
+  A aobj;
+  C cobj;
+
+  aobj.func ();
+  bobj.func ();
+  cobj.func ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
new file mode 100644
index 00000000000..fee770eb23d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -0,0 +1,215 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test defining a conditional breakpoint that applies to multiple
+# locations with different contexts (e.g. different set of local vars).
+
+standard_testfile .cc
+
+if {[prepare_for_testing "failed to prepare" ${binfile} ${srcfile}]} {
+    return
+}
+
+set warning "warning: failed to validate condition"
+set fill "\[^\r\n\]*"
+
+# Check that breakpoints are as expected.
+
+proc test_info_break {suffix} {
+    global bpnum1 bpnum2 fill
+
+    set bp_hit_info "${fill}(\r\n${fill}breakpoint already hit 1 time)?"
+
+    gdb_test "info break ${bpnum1} ${bpnum2}" \
+	[multi_line \
+	     "Num${fill}" \
+	     "${bpnum1}${fill}breakpoint${fill}keep y${fill}MULTIPLE${fill}" \
+	     "${fill}stop only if a == 10${bp_hit_info}" \
+	     "${bpnum1}.1${fill}N${fill}Base::func${fill}" \
+	     "${bpnum1}.2${fill}y${fill}A::func${fill}" \
+	     "${bpnum1}.3${fill}N${fill}C::func${fill}" \
+	     "${bpnum2}${fill}breakpoint${fill}keep y${fill}MULTIPLE${fill}" \
+	     "${fill}stop only if c == 30${bp_hit_info}" \
+	     "${bpnum2}.1${fill}N${fill}Base::func${fill}" \
+	     "${bpnum2}.2${fill}N${fill}A::func${fill}" \
+	     "${bpnum2}.3${fill}y${fill}C::func${fill}"] \
+	"info break $suffix"
+}
+
+# Scenario 1: Define breakpoints conditionally, using the "break N if
+# cond" syntax.  Run the program, check that we hit those locations
+# only.
+
+with_test_prefix "scenario 1" {
+    # Define the conditional breakpoints.
+    gdb_test "break func if a == 10" \
+	[multi_line \
+	     "${warning} at location $hex, disabling: No symbol \"a\" in current context." \
+	     "${warning} at location $hex, disabling: No symbol \"a\" in current context." \
+	     "Breakpoint $decimal at $fill .3 locations."] \
+	"define bp with condition a == 10"
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+
+    gdb_test "break func if c == 30" \
+	[multi_line \
+	     ".*${warning} at location $hex, disabling: No symbol \"c\" in current context." \
+	     ".*${warning} at location $hex, disabling: No symbol \"c\" in current context." \
+	     ".*Breakpoint $decimal at $fill .3 locations."] \
+	"define bp with condition c == 30"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+
+    test_info_break 1
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_run_cmd
+
+    # Check our conditional breakpoints.
+    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
+	"run until A::func"
+    gdb_test "print a" " = 10"
+
+    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
+	"run until C::func"
+    gdb_test "print c" " = 30"
+
+    # No more hits!
+    gdb_continue_to_end
+
+    test_info_break 2
+}
+
+# Start GDB with two breakpoints and define the conditions separately.
+
+proc setup_bps {} {
+    global srcfile binfile srcfile2
+    global bpnum1 bpnum2 bp_location warning
+
+    clean_restart ${binfile}
+
+    # Define the breakpoints.
+    gdb_breakpoint "func"
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+
+    gdb_breakpoint "func"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+
+    # Defining a condition on 'a' disables 2 locations.
+    gdb_test "cond $bpnum1 a == 10" \
+	[multi_line \
+	     "$warning at location ${bpnum1}.1, disabling: No symbol \"a\" in current context." \
+	     "$warning at location ${bpnum1}.3, disabling: No symbol \"a\" in current context."]
+
+    # Defining a condition on 'c' disables 2 locations.
+    gdb_test "cond $bpnum2 c == 30" \
+	[multi_line \
+	     "$warning at location ${bpnum2}.1, disabling: No symbol \"c\" in current context." \
+	     "$warning at location ${bpnum2}.2, disabling: No symbol \"c\" in current context."]
+}
+
+# Scenario 2: Define breakpoints unconditionally, and then define
+# conditions using the "cond N <cond>" syntax.  Expect that the
+# locations where <cond> is not evaluatable are disabled.  Run the
+# program, check that we hit the enabled locations only.
+
+with_test_prefix "scenario 2" {
+    setup_bps
+
+    test_info_break 1
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_run_cmd
+
+    # Check that we hit enabled locations only.
+    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
+	"run until A::func"
+    gdb_test "print a" " = 10"
+
+    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
+	"run until C::func"
+    gdb_test "print c" " = 30"
+
+    # No more hits!
+    gdb_continue_to_end
+
+    test_info_break 2
+}
+
+# Test the breakpoint location enabled states.
+
+proc check_bp_locations {bpnum states msg} {
+    global fill
+
+    set expected  ".*${bpnum}.1${fill} [lindex $states 0] ${fill}\r\n"
+    append expected "${bpnum}.2${fill} [lindex $states 1] ${fill}\r\n"
+    append expected "${bpnum}.3${fill} [lindex $states 2] ${fill}"
+
+    gdb_test "info break $bpnum" $expected "check bp $bpnum $msg"
+}
+
+# Scenario 3: Apply misc. checks on the already-defined breakpoints.
+
+with_test_prefix "scenario 3" {
+    setup_bps
+
+    gdb_test "cond $bpnum1 c == 30" \
+	[multi_line \
+	     "${warning} at location ${bpnum1}.1, disabling: No symbol \"c\" in current context." \
+	     "${warning} at location ${bpnum1}.2, disabling: No symbol \"c\" in current context." \
+	     "Breakpoint ${bpnum1}'s condition is now valid at location 3, enabling."] \
+	"change the condition of bp 1"
+    check_bp_locations $bpnum1 {N N y} "after changing the condition"
+
+    gdb_test "cond $bpnum1" \
+	[multi_line \
+	     "Breakpoint ${bpnum1}'s condition is now valid at location 1, enabling." \
+	     "Breakpoint ${bpnum1}'s condition is now valid at location 2, enabling." \
+	     "Breakpoint ${bpnum1} now unconditional."] \
+	"reset the condition of bp 1"
+    check_bp_locations $bpnum1 {y y y} "after resetting the condition"
+
+    gdb_test_no_output "disable ${bpnum2}.2"
+    check_bp_locations $bpnum2 {N N y} "after disabling loc 2"
+
+    gdb_test "cond $bpnum2" ".*" "reset the condition of bp 2"
+    check_bp_locations $bpnum2 {y n y} "loc 2 should remain disabled"
+
+    gdb_test_no_output "disable ${bpnum2}.3"
+    check_bp_locations $bpnum2 {y n n} "after disabling loc 3"
+
+    gdb_test "cond $bpnum2 c == 30" \
+	[multi_line \
+	     "${warning} at location ${bpnum2}.1, disabling: No symbol \"c\" in current context."] \
+	"re-define a condition"
+    check_bp_locations $bpnum2 {N N n} "loc 3 should remain disabled"
+
+    gdb_test "enable ${bpnum2}.1" \
+	"Breakpoint ${bpnum2}'s condition is invalid at location 1, cannot enable." \
+	"reject enabling a location that is disabled-by-cond"
+    check_bp_locations $bpnum2 {N N n} "after enable attempt"
+
+    gdb_test "cond $bpnum2 garbage" \
+	"No symbol \"garbage\" in current context." \
+	"reject condition if bad for all locations"
+
+    gdb_test_no_output "delete $bpnum1"
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_breakpoint "main"
+    gdb_run_cmd
+    gdb_test "" ".*reakpoint .*, main .*${srcfile}.*" "start"
+
+    # The second BP's locations are all disabled.  No more hits!
+    gdb_continue_to_end
+}
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v3 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-09-25 15:51 ` [PATCH v3 " Tankut Baris Aktemur
  2020-09-25 15:51   ` [PATCH v3 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
@ 2020-09-25 15:51   ` Tankut Baris Aktemur
  1 sibling, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-09-25 15:51 UTC (permalink / raw)
  To: gdb-patches; +Cc: simark

The previous patch made it possible to define a condition if it's
valid at some locations.  If the condition is invalid at all of the
locations, it's rejected.  However, there may be cases where the user
knows the condition *will* be valid at a location in the future,
e.g. due to a shared library load.

To make it possible that such condition can be defined, this patch
adds an optional '-force' flag to the 'condition' command, and,
respectively, a '-force-condition' flag to the 'break'command.  When
the force flag is passed, the condition is not rejected even when it
is invalid for all the current locations (note that all the locations
would be internally disabled in this case).

For instance:

  (gdb) break test.c:5
  Breakpoint 1 at 0x1155: file test.c, line 5.
  (gdb) cond 1 foo == 42
  No symbol "foo" in current context.

Defining the condition was not possible because 'foo' is not
available.  The user can override this behavior with the '-force'
flag:

  (gdb) cond -force 1 foo == 42
  warning: failed to validate condition at location 1.1, disabling: No symbol "foo" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if foo == 42
  1.1                         N   0x0000000000001155 in main at test.c:5

Now the condition is accepted, but the location is automatically
disabled.  If a future location has a context in which 'foo' is
available, that location would be enabled.

For the 'break' command, -force-condition has the same result:

  (gdb) break test.c:5 -force-condition if foo == 42
  warning: failed to validate condition at location 0x1169, disabling: No symbol "foo" in current context.
  Breakpoint 1 at 0x1169: file test.c, line 5.

gdb/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (set_breakpoint_condition): Add a new bool parameter.
	* breakpoint.c: Update the help text of the 'condition' and 'break'
	commands.
	(set_breakpoint_condition): Take a new bool parameter
	to control whether condition definition should be forced even when
	the condition expression is invalid in all of the current locations.
	(condition_command): Update the call to 'set_breakpoint_condition'.
	(find_condition_and_thread): Take the "-force-condition" flag into
	account.
        * linespec.c (linespec_keywords): Add "-force-condition" as an
	element.
        (FORCE_KEYWORD_INDEX): New #define.
        (linespec_lexer_lex_keyword): Update to consider "-force-condition"
	as a keyword.
	* ada-lang.c (create_ada_exception_catchpoint): Ditto.
	* guile/scm-breakpoint.c (gdbscm_set_breakpoint_condition_x): Ditto.
	* python/py-breakpoint.c (bppy_set_condition): Ditto.

gdb/testsuite/ChangeLog:
2020-08-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.base/condbreak-multi-context.exp: Expand to test forcing
	the condition.
	* gdb.linespec/cpcompletion.exp: Update to consider the
	'-force-condition' keyword.
	* gdb.linespec/explicit.exp: Ditto.
	* lib/completion-support.exp: Ditto.

gdb/doc/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo: Document the '-force-condition' flag of the 'break'
	command, and the '-force' flag of the 'condition' command.
---
 gdb/ada-lang.c                                |  2 +-
 gdb/breakpoint.c                              | 52 ++++++++++++++++---
 gdb/breakpoint.h                              |  6 ++-
 gdb/doc/gdb.texinfo                           | 27 ++++++++++
 gdb/guile/scm-breakpoint.c                    |  2 +-
 gdb/linespec.c                                | 18 +++++--
 gdb/python/py-breakpoint.c                    |  2 +-
 .../gdb.base/condbreak-multi-context.exp      | 22 ++++++++
 gdb/testsuite/gdb.linespec/cpcompletion.exp   | 12 +++--
 gdb/testsuite/gdb.linespec/explicit.exp       |  1 +
 gdb/testsuite/lib/completion-support.exp      |  2 +-
 11 files changed, 125 insertions(+), 21 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 0df406bff48..f973d656a33 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12702,7 +12702,7 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
   c->excep_string = excep_string;
   create_excep_cond_exprs (c.get (), ex_kind);
   if (!cond_string.empty ())
-    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty);
+    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty, false);
   install_breakpoint (0, std::move (c), 1);
 }
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 37f673603b2..90cedea344a 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -885,7 +885,7 @@ set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
 
 void
 set_breakpoint_condition (struct breakpoint *b, const char *exp,
-			  int from_tty)
+			  int from_tty, bool force)
 {
   if (*exp == 0)
     {
@@ -953,9 +953,11 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	      catch (const gdb_exception_error &e)
 		{
 		  /* Condition string is invalid.  If this happens to
-		     be the last loc, abandon.  */
+		     be the last loc, abandon (if not forced) or continue
+		     (if forced).  */
 		  if (loc->next == nullptr)
-		    throw;
+		    if (!force)
+		      throw;
 		}
 	    }
 
@@ -1036,6 +1038,18 @@ condition_command (const char *arg, int from_tty)
     error_no_arg (_("breakpoint number"));
 
   p = arg;
+
+  /* Check if the "-force" flag was passed.  */
+  bool force = false;
+  const char *tok = skip_spaces (p);
+  const char *end_tok = skip_to_space (tok);
+  int toklen = end_tok - tok;
+  if (toklen >= 1 && strncmp (tok, "-force", toklen) == 0)
+    {
+      force = true;
+      p = end_tok + 1;
+    }
+
   bnum = get_number (&p);
   if (bnum == 0)
     error (_("Bad breakpoint argument: '%s'"), arg);
@@ -1055,7 +1069,7 @@ condition_command (const char *arg, int from_tty)
 		     " a %s stop condition defined for this breakpoint."),
 		   ext_lang_capitalized_name (extlang));
 	  }
-	set_breakpoint_condition (b, p, from_tty);
+	set_breakpoint_condition (b, p, from_tty, force);
 
 	if (is_breakpoint (b))
 	  update_global_location_list (UGLL_MAY_INSERT);
@@ -9150,6 +9164,7 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
   *thread = -1;
   *task = 0;
   *rest = NULL;
+  bool force = false;
 
   while (tok && *tok)
     {
@@ -9173,10 +9188,25 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
       if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
 	{
 	  tok = cond_start = end_tok + 1;
-	  parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
+	  try
+	    {
+	      parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
+	    }
+	  catch (const gdb_exception_error &)
+	    {
+	      if (!force)
+		throw;
+	      else
+		tok = tok + strlen (tok);
+	    }
 	  cond_end = tok;
 	  *cond_string = savestring (cond_start, cond_end - cond_start);
 	}
+      else if (toklen >= 1 && strncmp (tok, "-force-condition", toklen) == 0)
+	{
+	  tok = cond_start = end_tok + 1;
+	  force = true;
+	}
       else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
 	{
 	  const char *tmptok;
@@ -15230,7 +15260,8 @@ specified name as a complete fully-qualified name instead."
    command.  */
 
 #define BREAK_ARGS_HELP(command) \
-command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
+command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM]\n\
+\t[-force-condition] [if CONDITION]\n\
 PROBE_MODIFIER shall be present if the command is to be placed in a\n\
 probe point.  Accepted values are `-probe' (for a generic, automatically\n\
 guessed probe type), `-probe-stap' (for a SystemTap probe) or \n\
@@ -15243,6 +15274,9 @@ stack frame.  This is useful for breaking on return to a stack frame.\n\
 \n\
 THREADNUM is the number from \"info threads\".\n\
 CONDITION is a boolean expression.\n\
+\n\
+With the \"-force-condition\" flag, the condition is defined even when\n\
+it is invalid for all current locations.\n\
 \n" LOCATION_HELP_STRING "\n\n\
 Multiple breakpoints at one place are permitted, and useful if their\n\
 conditions are different.\n\
@@ -15564,8 +15598,10 @@ then no output is printed when it is hit, except what the commands print."));
 
   c = add_com ("condition", class_breakpoint, condition_command, _("\
 Specify breakpoint number N to break only if COND is true.\n\
-Usage is `condition N COND', where N is an integer and COND is an\n\
-expression to be evaluated whenever breakpoint N is reached."));
+Usage is `condition [-force] N COND', where N is an integer and COND\n\
+is an expression to be evaluated whenever breakpoint N is reached.\n\
+With the \"-force\" flag, the condition is defined even when it is\n\
+invalid for all current locations."));
   set_cmd_completer (c, condition_completer);
 
   c = add_com ("tbreak", class_breakpoint, tbreak_command, _("\
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7d02cedf2fa..7845dd7f88f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1627,9 +1627,11 @@ extern int breakpoints_should_be_inserted_now (void);
    in our opinion won't ever trigger.  */
 extern void breakpoint_retire_moribund (void);
 
-/* Set break condition of breakpoint B to EXP.  */
+/* Set break condition of breakpoint B to EXP.
+   If FORCE, define the condition even if it is invalid in
+   all of the breakpoint locations.  */
 extern void set_breakpoint_condition (struct breakpoint *b, const char *exp,
-				      int from_tty);
+				      int from_tty, bool force);
 
 /* Checks if we are catching syscalls or not.
    Returns 0 if not, greater than 0 if we are.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 976bb1d4d60..dbbac462d7d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4315,6 +4315,27 @@ undefined variable:
 No symbol "foo" in current context.
 @end smallexample
 
+@item break @dots{} -force-condition if @var{cond}
+There may be cases where the condition @var{cond} is invalid at all
+the current locations, but the user knows that it will be valid at a
+future location; for example, because of a library load.  In such
+cases, by using the @code{-force-condition} keyword before @samp{if},
+@value{GDBN} can be forced to define the breakpoint with the given
+condition expression instead of refusing it.
+
+@smallexample
+(@value{GDBP}) break func -force-condition if foo
+warning: failed to validate condition at location 1, disabling: No symbol "foo" in current context.
+warning: failed to validate condition at location 2, disabling: No symbol "foo" in current context.
+warning: failed to validate condition at location 3, disabling: No symbol "foo" in current context.
+Breakpoint 1 at 0x1158: test.c:18. (3 locations)
+@end smallexample
+
+This causes all the present locations where the breakpoint would
+otherwise be inserted, to be disabled, as seen in the example above.
+However, if there exist locations at which the condition is valid, the
+@code{-force-condition} keyword has no effect.
+
 @kindex tbreak
 @item tbreak @var{args}
 Set a breakpoint enabled only for one stop.  The @var{args} are the
@@ -5494,6 +5515,12 @@ prints an error message:
 No symbol "foo" in current context.
 @end smallexample
 
+@item condition -force @var{bnum} @var{expression}
+When the @code{-force} flag is used, define the condition even if
+@var{expression} is invalid in all the current locations of breakpoint
+@var{bpnum}.  This is similar to the @code{-force-condition} option
+of the @code{break} command.
+
 @noindent
 @value{GDBN} does
 not actually evaluate @var{expression} at the time the @code{condition}
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index 96b6ca91f8d..7c9707235ec 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -905,7 +905,7 @@ gdbscm_set_breakpoint_condition_x (SCM self, SCM newvalue)
 	   ? nullptr
 	   : gdbscm_scm_to_c_string (newvalue));
 
-      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0);
+      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0, false);
 
       return SCM_UNSPECIFIED;
     });
diff --git a/gdb/linespec.c b/gdb/linespec.c
index b05b8ad89a8..3ee299f5f0e 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -72,7 +72,7 @@ enum class linespec_complete_what
   /* An expression.  E.g., "break foo if EXPR", or "break *EXPR".  */
   EXPRESSION,
 
-  /* A linespec keyword ("if"/"thread"/"task").
+  /* A linespec keyword ("if"/"thread"/"task"/"-force-condition").
      E.g., "break func threa<tab>".  */
   KEYWORD,
 };
@@ -254,8 +254,9 @@ typedef enum ls_token_type linespec_token_type;
 
 /* List of keywords.  This is NULL-terminated so that it can be used
    as enum completer.  */
-const char * const linespec_keywords[] = { "if", "thread", "task", NULL };
+const char * const linespec_keywords[] = { "if", "thread", "task", "-force-condition", NULL };
 #define IF_KEYWORD_INDEX 0
+#define FORCE_KEYWORD_INDEX 3
 
 /* A token of the linespec lexer  */
 
@@ -486,11 +487,22 @@ linespec_lexer_lex_keyword (const char *p)
 	    {
 	      int j;
 
+	      /* Special case: "-force" is always followed by an "if".  */
+	      if (i == FORCE_KEYWORD_INDEX)
+		{
+		  p += len;
+		  p = skip_spaces (p);
+		  int nextlen = strlen (linespec_keywords[IF_KEYWORD_INDEX]);
+		  if (!(strncmp (p, linespec_keywords[IF_KEYWORD_INDEX], nextlen) == 0
+			&& isspace (p[nextlen])))
+		    return NULL;
+		}
+
 	      /* Special case: "if" ALWAYS stops the lexer, since it
 		 is not possible to predict what is going to appear in
 		 the condition, which can only be parsed after SaLs have
 		 been found.  */
-	      if (i != IF_KEYWORD_INDEX)
+	      else if (i != IF_KEYWORD_INDEX)
 		{
 		  p += len;
 		  p = skip_spaces (p);
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 7369c91ad90..8099b06531b 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -461,7 +461,7 @@ bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
 
   try
     {
-      set_breakpoint_condition (self_bp->bp, exp, 0);
+      set_breakpoint_condition (self_bp->bp, exp, 0, false);
     }
   catch (gdb_exception &ex)
     {
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
index fee770eb23d..eb4385fe929 100644
--- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -213,3 +213,25 @@ with_test_prefix "scenario 3" {
     # The second BP's locations are all disabled.  No more hits!
     gdb_continue_to_end
 }
+
+# Scenario 4: Test the '-force'/'-force-condition' flag.
+
+with_test_prefix "force" {
+    clean_restart ${binfile}
+
+    gdb_breakpoint "func"
+    # Pick a condition that is invalid at every location.
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+    gdb_test "cond -force $bpnum1 foo" \
+	[multi_line \
+	     "${warning} at location ${bpnum1}.1, disabling: No symbol \"foo\" in current context." \
+	     "${warning} at location ${bpnum1}.2, disabling: No symbol \"foo\" in current context." \
+	     "${warning} at location ${bpnum1}.3, disabling: No symbol \"foo\" in current context."] \
+	"force the condition of bp 1"
+    check_bp_locations $bpnum1 {N N N} "after forcing the condition"
+
+    # Now with the 'break' command.
+    gdb_breakpoint "func -force-condition if baz"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+    check_bp_locations $bpnum2 {N N N} "set using the break command"
+}
diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp
index 2c95e2b4048..de96556f22d 100644
--- a/gdb/testsuite/gdb.linespec/cpcompletion.exp
+++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp
@@ -836,12 +836,14 @@ proc_with_prefix function-labels {} {
 }
 
 # Test that completion after a function name offers keyword
-# (if/task/thread) matches in linespec mode, and also the explicit
-# location options in explicit locations mode.
+# (if/task/thread/-force-condition) matches in linespec mode, and also
+# the explicit location options in explicit locations mode.
 
 proc_with_prefix keywords-after-function {} {
     set explicit_list \
-	[concat $completion::explicit_opts_list $completion::keyword_list]
+	[lsort [concat \
+		    $completion::explicit_opts_list \
+		    $completion::keyword_list]]
 
     # Test without a source file, with a known source file, and with
     # and unknown source file.
@@ -865,7 +867,9 @@ proc_with_prefix keywords-after-function {} {
 
 proc_with_prefix keywords-after-label {} {
     set explicit_list \
-	[concat $completion::explicit_opts_list $completion::keyword_list]
+	[lsort [concat \
+		    $completion::explicit_opts_list \
+		    $completion::keyword_list]]
 
     foreach_location_labels \
 	{ "" "cpls.cc" } \
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
index 4f457dc372f..5e3d352918e 100644
--- a/gdb/testsuite/gdb.linespec/explicit.exp
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -405,6 +405,7 @@ namespace eval $testfile {
 	# completion matches both the explicit location options and
 	# the linespec keywords.
 	set completions_list {
+	    "-force-condition"
 	    "-function"
 	    "-label"
 	    "-line"
diff --git a/gdb/testsuite/lib/completion-support.exp b/gdb/testsuite/lib/completion-support.exp
index 51436cc6713..dbb958157ed 100644
--- a/gdb/testsuite/lib/completion-support.exp
+++ b/gdb/testsuite/lib/completion-support.exp
@@ -27,7 +27,7 @@ namespace eval completion {
     # List of all quote chars, including no-quote at all.
     variable maybe_quoted_list {"" "'" "\""}
 
-    variable keyword_list {"if" "task" "thread"}
+    variable keyword_list {"-force-condition" "if" "task" "thread"}
 
     variable explicit_opts_list \
 	{"-function" "-label" "-line" "-qualified" "-source"}
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-09-25 15:49       ` Aktemur, Tankut Baris
@ 2020-09-25 16:10         ` Simon Marchi
  2020-09-25 18:15           ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2020-09-25 16:10 UTC (permalink / raw)
  To: Aktemur, Tankut Baris, gdb-patches

On 2020-09-25 11:49 a.m., Aktemur, Tankut Baris via Gdb-patches wrote:
> While revising the code, I noticed that when the breakpoint is being defined for
> the first time using "break" command, the locations are re-ordered according to
> their addresses.  So, tracking and reporting the location number as we iterate over
> SALs is useless.  Instead, we can report the location address.
>
> Based on this, how about the first option you gave above, but using "validate" instead
> of "resolve"?  For the "break" command, it reports the address in hex:
>
>   warning: failed to validate condition at location 0x1120, disabling: No symbol "a" in current context.

Ok, it would be nicer if we could refer to location numbers at the point
where we validate the conditions, it would make a more consistent
experience, but that works for now.

> But for the "cond" command, the location number is used because it's stable.
>
>   warning: failed to validate condition at location 2, disabling: No symbol "a" in current context.
>
> Perhaps we can break the message at the comma to avoid this long line.

I don't mind... as long as it's clear that it's one message broken on
two lines, not two message.

>>>   Breakpoint 1 at 0x117d: included.c:1. (3 locations)
>>>   (gdb) break included.c:1 if c == 30
>>>   Note: breakpoint 1 also set at pc 0x117d.
>>>   warning: disabling breakpoint location 1: No symbol "c" in current context.
>>>   Note: breakpoint 1 also set at pc 0x119c.
>>>   warning: disabling breakpoint location 2: No symbol "c" in current context.
>>>   Note: breakpoint 1 also set at pc 0x11cf.
>>>   Breakpoint 2 at 0x117d: included.c:1. (3 locations)
>>>   (gdb) info break
>>>   Num     Type           Disp Enb Address            What
>>>   1       breakpoint     keep y   <MULTIPLE>
>>>           stop only if a == 10
>>>   1.1                         y   0x000000000000117d in func1 at included.c:1
>>>   1.2                         n   0x000000000000119c in func2 at included.c:1
>>>   1.3                         n   0x00000000000011cf in func3 at included.c:1
>>>   2       breakpoint     keep y   <MULTIPLE>
>>>           stop only if c == 30
>>>   2.1                         n   0x000000000000117d in func1 at included.c:1
>>>   2.2                         n   0x000000000000119c in func2 at included.c:1
>>>   2.3                         y   0x00000000000011cf in func3 at included.c:1
>>
>> Should we somehow show in the listing that the locations disabled
>> because of the condition are disabled and can't be enabled?  For
>> example, a capital N in the "Enb" column?
>
> I like the capital N notation.  Patch is updated.

Ok.  Honestly, I find it a bit a bit cryptic, but I don't see a better
way without being overly verbose.  Perhaps a legend like we have on info
shared would help?

  (*): Shared library is missing debugging information.

> Done, with a small change:
>
>   Breakpoint 1's condition is invalid at location 2, cannot enable.
>
> OK with this?

Sounds good!

>>>
>>> Resetting the condition enables the locations back:
>>>
>>>   ...
>>>   (gdb) cond 1
>>>   Breakpoint 1.2 is now enabled.
>>>   Breakpoint 1.3 is now enabled.
>>
>> Likewise, this doesn't say why these locations suddenly get enabled.
>> Should it?  Something like "Breakpoint condition now resolves at
>> location 1.2, enabling.".  Or is it obvious, because the user is already
>> using the "condition" command?
>
> I think it's useful to say a bit more because the user may have forgotten about
> the condition.  To be consistent with the message above, how about this:
>
>   Breakpoint 1's condition is now valid at location 2, enabling.

Sounds good too.

> One additional note: I noticed that the existing "Breakpoint N is now unconditional"
> message is guarded by 'from_tty'.  I added the same guard to the "...enabling"
> messages, too.

Do you see any reason for that?  Even if these commands are executed in
a script, I'd like to be notified about these changes.  What do you
think?

>>> +static void
>>> +set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
>>> +				   int bp_num, int loc_num)
>>> +{
>>> +  bool has_junk = false;
>>> +  try
>>> +    {
>>> +      expression_up new_exp = parse_exp_1 (&cond_string, loc->address,
>>> +					   block_for_pc (loc->address), 0);
>>> +      if (*cond_string != 0)
>>> +	has_junk = true;
>>> +      else
>>> +	{
>>> +	  loc->cond = std::move (new_exp);
>>> +	  if (loc->disabled_by_cond && loc->enabled)
>>> +	    printf_filtered (_("Breakpoint %d.%d is now enabled.\n"),
>>> +			     bp_num, loc_num);
>>> +
>>> +	  loc->disabled_by_cond = false;
>>> +	}
>>> +    }
>>> +  catch (const gdb_exception_error &e)
>>> +    {
>>> +      if (bp_num != 0)
>>> +	warning (_("disabling breakpoint %d.%d: %s"),
>>> +		 bp_num, loc_num, e.what ());
>>> +      else
>>> +	warning (_("disabling breakpoint location %d: %s"),
>>> +		 loc_num, e.what ());
>>
>> When is bp_num 0?
>
> It's 0 if the breakpoint is being defined for the first time using the
> "break ... if ..." command.  It's non-zero if defined previously and is now
> becoming conditional.

Ok.  And is this warning (when bp_num is 0) exercised in the tests?  I
don't remember seeing it as a test expected output, but maybe I just
missed it.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-09-25 16:10         ` Simon Marchi
@ 2020-09-25 18:15           ` Aktemur, Tankut Baris
  2020-10-13 12:24             ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-09-25 18:15 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Friday, September 25, 2020 6:10 PM, Simon Marchi wrote:
> On 2020-09-25 11:49 a.m., Aktemur, Tankut Baris via Gdb-patches wrote:
> > While revising the code, I noticed that when the breakpoint is being defined for
> > the first time using "break" command, the locations are re-ordered according to
> > their addresses.  So, tracking and reporting the location number as we iterate over
> > SALs is useless.  Instead, we can report the location address.
> >
> > Based on this, how about the first option you gave above, but using "validate" instead
> > of "resolve"?  For the "break" command, it reports the address in hex:
> >
> >   warning: failed to validate condition at location 0x1120, disabling: No symbol "a" in
> current context.
> 
> Ok, it would be nicer if we could refer to location numbers at the point
> where we validate the conditions, it would make a more consistent
> experience, but that works for now.

We can skip printing the warning but save the exception message inside the loc object.
Once we are done iterating the locations, we can go over the now-ordered list to print
the warnings together with the location numbers.  How does that sound?
 
> > But for the "cond" command, the location number is used because it's stable.
> >
> >   warning: failed to validate condition at location 2, disabling: No symbol "a" in current
> context.
> >
> > Perhaps we can break the message at the comma to avoid this long line.
> 
> I don't mind... as long as it's clear that it's one message broken on
> two lines, not two message.

OK, I'll check the GDB doc to see how it looks and will break the line
if necessary.
 
> >>>   Breakpoint 1 at 0x117d: included.c:1. (3 locations)
> >>>   (gdb) break included.c:1 if c == 30
> >>>   Note: breakpoint 1 also set at pc 0x117d.
> >>>   warning: disabling breakpoint location 1: No symbol "c" in current context.
> >>>   Note: breakpoint 1 also set at pc 0x119c.
> >>>   warning: disabling breakpoint location 2: No symbol "c" in current context.
> >>>   Note: breakpoint 1 also set at pc 0x11cf.
> >>>   Breakpoint 2 at 0x117d: included.c:1. (3 locations)
> >>>   (gdb) info break
> >>>   Num     Type           Disp Enb Address            What
> >>>   1       breakpoint     keep y   <MULTIPLE>
> >>>           stop only if a == 10
> >>>   1.1                         y   0x000000000000117d in func1 at included.c:1
> >>>   1.2                         n   0x000000000000119c in func2 at included.c:1
> >>>   1.3                         n   0x00000000000011cf in func3 at included.c:1
> >>>   2       breakpoint     keep y   <MULTIPLE>
> >>>           stop only if c == 30
> >>>   2.1                         n   0x000000000000117d in func1 at included.c:1
> >>>   2.2                         n   0x000000000000119c in func2 at included.c:1
> >>>   2.3                         y   0x00000000000011cf in func3 at included.c:1
> >>
> >> Should we somehow show in the listing that the locations disabled
> >> because of the condition are disabled and can't be enabled?  For
> >> example, a capital N in the "Enb" column?
> >
> > I like the capital N notation.  Patch is updated.
> 
> Ok.  Honestly, I find it a bit a bit cryptic, but I don't see a better
> way without being overly verbose.  Perhaps a legend like we have on info
> shared would help?
> 
>   (*): Shared library is missing debugging information.

I don't have a strong preference.  The legend approach would be fine, too.
 
> > Done, with a small change:
> >
> >   Breakpoint 1's condition is invalid at location 2, cannot enable.
> >
> > OK with this?
> 
> Sounds good!
> 
> >>>
> >>> Resetting the condition enables the locations back:
> >>>
> >>>   ...
> >>>   (gdb) cond 1
> >>>   Breakpoint 1.2 is now enabled.
> >>>   Breakpoint 1.3 is now enabled.
> >>
> >> Likewise, this doesn't say why these locations suddenly get enabled.
> >> Should it?  Something like "Breakpoint condition now resolves at
> >> location 1.2, enabling.".  Or is it obvious, because the user is already
> >> using the "condition" command?
> >
> > I think it's useful to say a bit more because the user may have forgotten about
> > the condition.  To be consistent with the message above, how about this:
> >
> >   Breakpoint 1's condition is now valid at location 2, enabling.
> 
> Sounds good too.
> 
> > One additional note: I noticed that the existing "Breakpoint N is now unconditional"
> > message is guarded by 'from_tty'.  I added the same guard to the "...enabling"
> > messages, too.
> 
> Do you see any reason for that?  Even if these commands are executed in
> a script, I'd like to be notified about these changes.  What do you
> think?

I had aimed to be consistent with the "... now unconditional" message, but I agree.
When hidden, such messages sometimes cost valuable time loss.  I'll remove the from_tty
guards I added.

> >>> +static void
> >>> +set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
> >>> +				   int bp_num, int loc_num)
> >>> +{
> >>> +  bool has_junk = false;
> >>> +  try
> >>> +    {
> >>> +      expression_up new_exp = parse_exp_1 (&cond_string, loc->address,
> >>> +					   block_for_pc (loc->address), 0);
> >>> +      if (*cond_string != 0)
> >>> +	has_junk = true;
> >>> +      else
> >>> +	{
> >>> +	  loc->cond = std::move (new_exp);
> >>> +	  if (loc->disabled_by_cond && loc->enabled)
> >>> +	    printf_filtered (_("Breakpoint %d.%d is now enabled.\n"),
> >>> +			     bp_num, loc_num);
> >>> +
> >>> +	  loc->disabled_by_cond = false;
> >>> +	}
> >>> +    }
> >>> +  catch (const gdb_exception_error &e)
> >>> +    {
> >>> +      if (bp_num != 0)
> >>> +	warning (_("disabling breakpoint %d.%d: %s"),
> >>> +		 bp_num, loc_num, e.what ());
> >>> +      else
> >>> +	warning (_("disabling breakpoint location %d: %s"),
> >>> +		 loc_num, e.what ());
> >>
> >> When is bp_num 0?
> >
> > It's 0 if the breakpoint is being defined for the first time using the
> > "break ... if ..." command.  It's non-zero if defined previously and is now
> > becoming conditional.
> 
> Ok.  And is this warning (when bp_num is 0) exercised in the tests?  I
> don't remember seeing it as a test expected output, but maybe I just
> missed it.
> 
> Simon

Yes, it is exercised as one of the first tests.  The "break func if a == 10"
command goes through this path, while "cond 1 a == 10" goes through the bp_num != 0
path.

Thanks
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-09-25 18:15           ` Aktemur, Tankut Baris
@ 2020-10-13 12:24             ` Aktemur, Tankut Baris
  0 siblings, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-10-13 12:24 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Friday, September 25, 2020 8:15 PM, Aktemur, Tankut Baris wrote:
> On Friday, September 25, 2020 6:10 PM, Simon Marchi wrote:
> > On 2020-09-25 11:49 a.m., Aktemur, Tankut Baris via Gdb-patches wrote:
> > > While revising the code, I noticed that when the breakpoint is being defined for
> > > the first time using "break" command, the locations are re-ordered according to
> > > their addresses.  So, tracking and reporting the location number as we iterate over
> > > SALs is useless.  Instead, we can report the location address.
> > >
> > > Based on this, how about the first option you gave above, but using "validate" instead
> > > of "resolve"?  For the "break" command, it reports the address in hex:
> > >
> > >   warning: failed to validate condition at location 0x1120, disabling: No symbol "a" in
> > current context.
> >
> > Ok, it would be nicer if we could refer to location numbers at the point
> > where we validate the conditions, it would make a more consistent
> > experience, but that works for now.
> 
> We can skip printing the warning but save the exception message inside the loc object.
> Once we are done iterating the locations, we can go over the now-ordered list to print
> the warnings together with the location numbers.  How does that sound?

In the next revision (v4), I moved the part that sets the location's condition out of the
loop that iterates the `sals`, and added a second loop over the locations.  This way, we
will be iterating a stabilized list of locations where the positional numbers are correct.
So, the next revision does not print hex addresses anymore.
 
> > > But for the "cond" command, the location number is used because it's stable.
> > >
> > >   warning: failed to validate condition at location 2, disabling: No symbol "a" in
> current
> > context.
> > >
> > > Perhaps we can break the message at the comma to avoid this long line.
> >
> > I don't mind... as long as it's clear that it's one message broken on
> > two lines, not two message.
> 
> OK, I'll check the GDB doc to see how it looks and will break the line
> if necessary.

It did not look nice in gdb.pdf.  I broke the line and indented the error
message.  It looks like this in v4:

  warning: failed to validate condition at location 2, disabling:
    No symbol "a" in current context.
 
> > >>>   Breakpoint 1 at 0x117d: included.c:1. (3 locations)
> > >>>   (gdb) break included.c:1 if c == 30
> > >>>   Note: breakpoint 1 also set at pc 0x117d.
> > >>>   warning: disabling breakpoint location 1: No symbol "c" in current context.
> > >>>   Note: breakpoint 1 also set at pc 0x119c.
> > >>>   warning: disabling breakpoint location 2: No symbol "c" in current context.
> > >>>   Note: breakpoint 1 also set at pc 0x11cf.
> > >>>   Breakpoint 2 at 0x117d: included.c:1. (3 locations)
> > >>>   (gdb) info break
> > >>>   Num     Type           Disp Enb Address            What
> > >>>   1       breakpoint     keep y   <MULTIPLE>
> > >>>           stop only if a == 10
> > >>>   1.1                         y   0x000000000000117d in func1 at included.c:1
> > >>>   1.2                         n   0x000000000000119c in func2 at included.c:1
> > >>>   1.3                         n   0x00000000000011cf in func3 at included.c:1
> > >>>   2       breakpoint     keep y   <MULTIPLE>
> > >>>           stop only if c == 30
> > >>>   2.1                         n   0x000000000000117d in func1 at included.c:1
> > >>>   2.2                         n   0x000000000000119c in func2 at included.c:1
> > >>>   2.3                         y   0x00000000000011cf in func3 at included.c:1
> > >>
> > >> Should we somehow show in the listing that the locations disabled
> > >> because of the condition are disabled and can't be enabled?  For
> > >> example, a capital N in the "Enb" column?
> > >
> > > I like the capital N notation.  Patch is updated.
> >
> > Ok.  Honestly, I find it a bit a bit cryptic, but I don't see a better
> > way without being overly verbose.  Perhaps a legend like we have on info
> > shared would help?
> >
> >   (*): Shared library is missing debugging information.
> 
> I don't have a strong preference.  The legend approach would be fine, too.

I went with this legend approach in v4.
 
> > > Done, with a small change:
> > >
> > >   Breakpoint 1's condition is invalid at location 2, cannot enable.
> > >
> > > OK with this?
> >
> > Sounds good!
> >
> > >>>
> > >>> Resetting the condition enables the locations back:
> > >>>
> > >>>   ...
> > >>>   (gdb) cond 1
> > >>>   Breakpoint 1.2 is now enabled.
> > >>>   Breakpoint 1.3 is now enabled.
> > >>
> > >> Likewise, this doesn't say why these locations suddenly get enabled.
> > >> Should it?  Something like "Breakpoint condition now resolves at
> > >> location 1.2, enabling.".  Or is it obvious, because the user is already
> > >> using the "condition" command?
> > >
> > > I think it's useful to say a bit more because the user may have forgotten about
> > > the condition.  To be consistent with the message above, how about this:
> > >
> > >   Breakpoint 1's condition is now valid at location 2, enabling.
> >
> > Sounds good too.
> >
> > > One additional note: I noticed that the existing "Breakpoint N is now unconditional"
> > > message is guarded by 'from_tty'.  I added the same guard to the "...enabling"
> > > messages, too.
> >
> > Do you see any reason for that?  Even if these commands are executed in
> > a script, I'd like to be notified about these changes.  What do you
> > think?
> 
> I had aimed to be consistent with the "... now unconditional" message, but I agree.
> When hidden, such messages sometimes cost valuable time loss.  I'll remove the from_tty
> guards I added.

from_tty is removed in v4.
 
Thanks
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts
  2020-07-31 15:42 [PATCH 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
                   ` (2 preceding siblings ...)
  2020-09-25 15:51 ` [PATCH v3 " Tankut Baris Aktemur
@ 2020-10-13 12:25 ` Tankut Baris Aktemur
  2020-10-13 12:25   ` [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
                     ` (2 more replies)
  2021-04-05 17:45 ` [PATCH " Jonah Graham
  4 siblings, 3 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-10-13 12:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: simark

Hi,

This is a follow-up of

  https://sourceware.org/pipermail/gdb-patches/2020-July/170984.html

which is a short series about conditional breakpoints where the
condition may be invalid at some breakpoint locations because of their
context.  Currently, GDB does not allow defining a condition if it's
not valid at all locations.  This series aims at bringing more
flexibility: the locations at which the condition expression is
invalid are disabled automatically.

In v2, I extended Patch 2/2 with the '-force-condition' flag for the break
command, added test cases and more documentation.

In v3, warning messages are updated based on Simon Marchi's
comments at https://sourceware.org/pipermail/gdb-patches/2020-September/171970.html.
I also revised the documentation changes.

In this revision (v4), the updates are as follows:

* Rebased on the current master.

* Correct location number is printed if a location is disabled
  because of the invalid condition when the breakpoint is being
  defined for the first time.

* A legend is shown at the bottom of the breakpoint table to explain
  the meaning of "N*".

* A long warning message is broken into two lines.

Regards.
Baris

Tankut Baris Aktemur (2):
  gdb/breakpoint: disable a bp location if condition is invalid at that
    location
  gdb/breakpoint: add flags to 'condition' and 'break' commands to force
    condition

 gdb/ada-lang.c                                |   2 +-
 gdb/breakpoint.c                              | 283 ++++++++++++++----
 gdb/breakpoint.h                              |  12 +-
 gdb/doc/gdb.texinfo                           |  70 +++++
 gdb/guile/scm-breakpoint.c                    |   2 +-
 gdb/linespec.c                                |  18 +-
 gdb/python/py-breakpoint.c                    |   2 +-
 .../gdb.base/condbreak-multi-context.cc       |  54 ++++
 .../gdb.base/condbreak-multi-context.exp      | 255 ++++++++++++++++
 gdb/testsuite/gdb.linespec/cpcompletion.exp   |  12 +-
 gdb/testsuite/gdb.linespec/explicit.exp       |   1 +
 gdb/testsuite/lib/completion-support.exp      |   2 +-
 12 files changed, 644 insertions(+), 69 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.cc
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-10-13 12:25 ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
@ 2020-10-13 12:25   ` Tankut Baris Aktemur
  2020-10-13 15:06     ` Eli Zaretskii
  2020-10-16 22:20     ` Simon Marchi
  2020-10-13 12:25   ` [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
  2020-10-28 16:57   ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Gary Benson
  2 siblings, 2 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-10-13 12:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: simark

Currently, for a conditional breakpoint, GDB checks if the condition
can be evaluated in the context of the first symtab and line (SAL).
In case of an error, defining the conditional breakpoint is aborted.
This prevents having a conditional breakpoint whose condition may
actually be meaningful for some of the location contexts.  This patch
makes it possible to define conditional BPs by checking all location
contexts.  If the condition is meaningful for even one context, the
breakpoint is defined.  The locations for which the condition gives
errors are disabled.

The bp_location struct is introduced a new field, 'disabled_by_cond'.
This field denotes whether the location is disabled automatically
because the condition was non-evaluatable.  Disabled-by-cond locations
cannot be enabled by the user.  But locations that are not
disabled-by-cond can be enabled/disabled by the user manually as
before.

For a concrete example, consider 3 contexts of a function 'func'.

  class Base
  {
  public:
    int b = 20;

    void func () {}
  };

  class A : public Base
  {
  public:
    int a = 10;

    void func () {}
  };

  class C : public Base
  {
  public:
    int c = 30;

    void func () {}
  };

Note that

* the variable 'a' is defined only in the context of A::func.
* the variable 'c' is defined only in the context of C::func.
* the variable 'b' is defined in all the three contexts.

With the existing GDB, it's not possible to define a conditional
breakpoint at 'func' if the condition refers to 'a' or 'c':

  (gdb) break func if a == 10
  No symbol "a" in current context.
  (gdb) break func if c == 30
  No symbol "c" in current context.
  (gdb) info breakpoints
  No breakpoints or watchpoints.

With this patch, it becomes possible:

  (gdb) break func if a == 10
  warning: failed to validate condition at location 1, disabling:
    No symbol "a" in current context.
  warning: failed to validate condition at location 3, disabling:
    No symbol "a" in current context.
  Breakpoint 1 at 0x11b6: func. (3 locations)
  (gdb) break func if c == 30
  Note: breakpoint 1 also set at pc 0x11ce.
  Note: breakpoint 1 also set at pc 0x11c2.
  Note: breakpoint 1 also set at pc 0x11b6.
  warning: failed to validate condition at location 1, disabling:
    No symbol "c" in current context.
  warning: failed to validate condition at location 2, disabling:
    No symbol "c" in current context.
  Breakpoint 2 at 0x11b6: func. (3 locations)
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         N*  0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
  2       breakpoint     keep y   <MULTIPLE>
          stop only if c == 30
  2.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  2.2                         N*  0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  2.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
  (*): Breakpoint condition is invalid at this location.

Here, uppercase 'N' denotes that the location is disabled because of
the invalid condition, as mentioned with a footnote in the legend of
the table.  Locations that are disabled by the user are still denoted
with lowercase 'n'.  Executing the code hits the breakpoints 1.2 and
2.3 as expected.

Defining a condition on an unconditional breakpoint gives the same
behavior above:

  (gdb) break func
  Breakpoint 1 at 0x11b6: func. (3 locations)
  (gdb) cond 1 a == 10
  warning: failed to validate condition at location 1.1, disabling:
    No symbol "a" in current context.
  warning: failed to validate condition at location 1.3, disabling:
    No symbol "a" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         N*  0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
  (*): Breakpoint condition is invalid at this location.

Locations that are disabled because of a condition cannot be enabled
by the user:

  ...
  (gdb) enable 1.1
  Breakpoint 1's condition is invalid at location 1, cannot enable.

Resetting the condition enables the locations back:

  ...
  (gdb) cond 1
  Breakpoint 1's condition is now valid at location 1, enabling.
  Breakpoint 1's condition is now valid at location 3, enabling.
  Breakpoint 1 now unconditional.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
  1.1                         y   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39

If a location is disabled by the user, a condition can still be defined
but the location will remain disabled even if the condition is meaningful
for the disabled location:

  ...
  (gdb) disable 1.2
  (gdb) cond 1 a == 10
  warning: failed to validate condition at location 1.1, disabling:
    No symbol "a" in current context.
  warning: failed to validate condition at location 1.3, disabling:
    No symbol "a" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if a == 10
  1.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         n   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         N*  0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
  (*): Breakpoint condition is invalid at this location.

The condition of a breakpoint can be changed.  Locations'
enable/disable states are updated accordingly.

  ...
  (gdb) cond 1 c == 30
  warning: failed to validate condition at location 1.1, disabling:
    No symbol "c" in current context.
  Breakpoint 1's condition is now valid at location 3, enabling.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if c == 30
  1.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         N*  0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
  (*): Breakpoint condition is invalid at this location.

  (gdb) cond 1 b == 20
  Breakpoint 1's condition is now valid at location 1, enabling.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if b == 20
  1.1                         y   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
  1.2                         n   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
  1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
  # Note that location 1.2 was disabled by the user previously.

If the condition expression is bad for all the locations, it will be
rejected.

  (gdb) cond 1 garbage
  No symbol "garbage" in current context.

For conditions that are invalid or valid for all the locations of a
breakpoint, the existing behavior is preserved.

Regression-tested on X86_64 Linux.

gdb/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (class bp_location) <disabled_by_cond>: New field.
	* breakpoint.c (set_breakpoint_location_condition): New function.
	(set_breakpoint_condition): Disable a breakpoint
	location if parsing the condition string gives an error.
	(should_be_inserted): Update to consider the 'disabled_by_cond' field.
	(build_target_condition_list): Ditto.
	(build_target_command_list): Ditto.
	(build_bpstat_chain): Ditto.
	(print_one_breakpoint_location): Ditto.
	(print_one_breakpoint): Ditto.
	(breakpoint_1): Ditto.
	(bp_location::bp_location): Ditto.
	(locations_are_equal): Ditto.
	(update_breakpoint_locations): Ditto.
	(enable_disable_bp_num_loc): Ditto.
	(init_breakpoint_sal): Use set_breakpoint_location_condition.
	(find_condition_and_thread_for_sals): New static function.
	(create_breakpoint): Call find_condition_and_thread_for_sals.
	(location_to_sals): Call find_condition_and_thread_for_sals instead
	of find_condition_and_thread.

gdb/testsuite/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.base/condbreak-multi-context.cc: New file.
	* gdb.base/condbreak-multi-context.exp: New file.

gdb/doc/ChangeLog:
2020-09-25  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (Set Breaks): Document disabling of breakpoint
	locations for which the breakpoint condition is invalid.
---
 gdb/breakpoint.c                              | 235 ++++++++++++++----
 gdb/breakpoint.h                              |   6 +
 gdb/doc/gdb.texinfo                           |  40 +++
 .../gdb.base/condbreak-multi-context.cc       |  54 ++++
 .../gdb.base/condbreak-multi-context.exp      | 230 +++++++++++++++++
 5 files changed, 515 insertions(+), 50 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.cc
 create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 296b08c0afc..8e41b4bab14 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -830,6 +830,56 @@ get_first_locp_gte_addr (CORE_ADDR address)
   return locp_found;
 }
 
+/* Parse COND_STRING in the context of LOC and set as the condition
+   expression of LOC.  BP_NUM is the number of LOC's owner, LOC_NUM is
+   the number of LOC within its owner.  In case of parsing error, mark
+   LOC as DISABLED_BY_COND.  In case of success, unset DISABLED_BY_COND.  */
+
+static void
+set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
+				   int bp_num, int loc_num)
+{
+  bool has_junk = false;
+  try
+    {
+      expression_up new_exp = parse_exp_1 (&cond_string, loc->address,
+					   block_for_pc (loc->address), 0);
+      if (*cond_string != 0)
+	has_junk = true;
+      else
+	{
+	  loc->cond = std::move (new_exp);
+	  if (loc->disabled_by_cond && loc->enabled)
+	    printf_filtered (_("Breakpoint %d's condition is now valid at "
+			       "location %d, enabling.\n"),
+			     bp_num, loc_num);
+
+	  loc->disabled_by_cond = false;
+	}
+    }
+  catch (const gdb_exception_error &e)
+    {
+      if (loc->enabled)
+	{
+	  /* Warn if a user-enabled location is now becoming disabled-by-cond.
+	     BP_NUM is 0 if the breakpoint is being defined for the first
+	     time using the "break ... if ..." command, and non-zero if
+	     already defined.  */
+	  if (bp_num != 0)
+	    warning (_("failed to validate condition at location %d.%d, "
+		       "disabling:\n  %s"), bp_num, loc_num, e.what ());
+	  else
+	    warning (_("failed to validate condition at location %d, "
+		       "disabling:\n  %s"), loc_num, e.what ());
+	}
+
+      loc->disabled_by_cond = true;
+    }
+
+  if (has_junk)
+    error (_("Garbage '%s' follows condition"), cond_string);
+}
+
 void
 set_breakpoint_condition (struct breakpoint *b, const char *exp,
 			  int from_tty)
@@ -843,9 +893,16 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	static_cast<watchpoint *> (b)->cond_exp.reset ();
       else
 	{
+	  int loc_num = 1;
 	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
 	    {
 	      loc->cond.reset ();
+	      if (loc->disabled_by_cond && loc->enabled)
+		printf_filtered (_("Breakpoint %d's condition is now valid at "
+				   "location %d, enabling.\n"),
+				 b->number, loc_num);
+	      loc->disabled_by_cond = false;
+	      loc_num++;
 
 	      /* No need to free the condition agent expression
 		 bytecode (if we have one).  We will handle this
@@ -873,29 +930,37 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	{
 	  /* Parse and set condition expressions.  We make two passes.
 	     In the first, we parse the condition string to see if it
-	     is valid in all locations.  If so, the condition would be
-	     accepted.  So we go ahead and set the locations'
-	     conditions.  In case a failing case is found, we throw
+	     is valid in at least one location.  If so, the condition
+	     would be accepted.  So we go ahead and set the locations'
+	     conditions.  In case no valid case is found, we throw
 	     the error and the condition string will be rejected.
 	     This two-pass approach is taken to avoid setting the
 	     state of locations in case of a reject.  */
 	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
 	    {
-	      const char *arg = exp;
-	      parse_exp_1 (&arg, loc->address,
-			   block_for_pc (loc->address), 0);
-	      if (*arg != 0)
-		error (_("Junk at end of expression"));
+	      try
+		{
+		  const char *arg = exp;
+		  parse_exp_1 (&arg, loc->address,
+			       block_for_pc (loc->address), 0);
+		  if (*arg != 0)
+		    error (_("Junk at end of expression"));
+		  break;
+		}
+	      catch (const gdb_exception_error &e)
+		{
+		  /* Condition string is invalid.  If this happens to
+		     be the last loc, abandon.  */
+		  if (loc->next == nullptr)
+		    throw;
+		}
 	    }
 
-	  /* If we reach here, the condition is valid at all locations.  */
-	  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
-	    {
-	      const char *arg = exp;
-	      loc->cond =
-		parse_exp_1 (&arg, loc->address,
-			     block_for_pc (loc->address), 0);
-	    }
+	  /* If we reach here, the condition is valid at some locations.  */
+          int loc_num = 1;
+          for (bp_location *loc = b->loc; loc != nullptr;
+               loc = loc->next, loc_num++)
+            set_breakpoint_location_condition (exp, loc, b->number, loc_num);
 	}
 
       /* We know that the new condition parsed successfully.  The
@@ -2010,7 +2075,8 @@ should_be_inserted (struct bp_location *bl)
   if (bl->owner->disposition == disp_del_at_next_stop)
     return 0;
 
-  if (!bl->enabled || bl->shlib_disabled || bl->duplicate)
+  if (!bl->enabled || bl->disabled_by_cond
+      || bl->shlib_disabled || bl->duplicate)
     return 0;
 
   if (user_breakpoint_p (bl->owner) && bl->pspace->executing_startup)
@@ -2205,7 +2271,8 @@ build_target_condition_list (struct bp_location *bl)
 	  && is_breakpoint (loc->owner)
 	  && loc->pspace->num == bl->pspace->num
 	  && loc->owner->enable_state == bp_enabled
-	  && loc->enabled)
+	  && loc->enabled
+	  && !loc->disabled_by_cond)
 	{
 	  /* Add the condition to the vector.  This will be used later
 	     to send the conditions to the target.  */
@@ -2395,7 +2462,8 @@ build_target_command_list (struct bp_location *bl)
 	  && is_breakpoint (loc->owner)
 	  && loc->pspace->num == bl->pspace->num
 	  && loc->owner->enable_state == bp_enabled
-	  && loc->enabled)
+	  && loc->enabled
+	  && !loc->disabled_by_cond)
 	{
 	  /* Add the command to the vector.  This will be used later
 	     to send the commands to the target.  */
@@ -5278,7 +5346,7 @@ build_bpstat_chain (const address_space *aspace, CORE_ADDR bp_addr,
 	  if (b->type == bp_hardware_watchpoint && bl != b->loc)
 	    break;
 
-	  if (!bl->enabled || bl->shlib_disabled)
+	  if (!bl->enabled || bl->disabled_by_cond || bl->shlib_disabled)
 	    continue;
 
 	  if (!bpstat_check_location (bl, aspace, bp_addr, ws))
@@ -5984,7 +6052,8 @@ print_one_breakpoint_location (struct breakpoint *b,
      breakpoints with single disabled location.  */
   if (loc == NULL 
       && (b->loc != NULL 
-	  && (b->loc->next != NULL || !b->loc->enabled)))
+	  && (b->loc->next != NULL
+	      || !b->loc->enabled || b->loc->disabled_by_cond)))
     header_of_multiple = 1;
   if (loc == NULL)
     loc = b->loc;
@@ -6015,7 +6084,8 @@ print_one_breakpoint_location (struct breakpoint *b,
   /* 4 */
   annotate_field (3);
   if (part_of_multiple)
-    uiout->field_string ("enabled", loc->enabled ? "y" : "n");
+    uiout->field_string ("enabled", (loc->disabled_by_cond ? "N*"
+				     : (loc->enabled ? "y" : "n")));
   else
     uiout->field_fmt ("enabled", "%c", bpenables[(int) b->enable_state]);
 
@@ -6315,7 +6385,9 @@ print_one_breakpoint (struct breakpoint *b,
 	  && (!is_catchpoint (b) || is_exception_catchpoint (b)
 	      || is_ada_exception_catchpoint (b))
 	  && (allflag
-	      || (b->loc && (b->loc->next || !b->loc->enabled))))
+	      || (b->loc && (b->loc->next
+			     || !b->loc->enabled
+			     || b->loc->disabled_by_cond))))
 	{
 	  gdb::optional<ui_out_emit_list> locations_list;
 
@@ -6409,6 +6481,7 @@ breakpoint_1 (const char *bp_num_list, bool show_internal,
   int print_address_bits = 0;
   int print_type_col_width = 14;
   struct ui_out *uiout = current_uiout;
+  bool has_disabled_by_cond_location = false;
 
   get_user_print_options (&opts);
 
@@ -6509,7 +6582,12 @@ breakpoint_1 (const char *bp_num_list, bool show_internal,
 	/* We only print out user settable breakpoints unless the
 	   show_internal is set.  */
 	if (show_internal || user_breakpoint_p (b))
-	  print_one_breakpoint (b, &last_loc, show_internal);
+	  {
+	    print_one_breakpoint (b, &last_loc, show_internal);
+	    for (bp_location *loc = b->loc; loc != NULL; loc = loc->next)
+	      if (loc->disabled_by_cond)
+		has_disabled_by_cond_location = true;
+	  }
       }
   }
 
@@ -6530,6 +6608,10 @@ breakpoint_1 (const char *bp_num_list, bool show_internal,
     {
       if (last_loc && !server_command)
 	set_next_address (last_loc->gdbarch, last_loc->address);
+
+      if (has_disabled_by_cond_location)
+	uiout->message (_("(*): Breakpoint condition is invalid at this "
+			  "location.\n"));
     }
 
   /* FIXME?  Should this be moved up so that it is only called when
@@ -6957,6 +7039,7 @@ bp_location::bp_location (breakpoint *owner, bp_loc_type type)
   this->cond_bytecode = NULL;
   this->shlib_disabled = 0;
   this->enabled = 1;
+  this->disabled_by_cond = false;
 
   this->loc_type = type;
 
@@ -8829,15 +8912,9 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 	    loc->inserted = 1;
 	}
 
-      if (b->cond_string)
-	{
-	  const char *arg = b->cond_string;
-
-	  loc->cond = parse_exp_1 (&arg, loc->address,
-				   block_for_pc (loc->address), 0);
-	  if (*arg)
-              error (_("Garbage '%s' follows condition"), arg);
-	}
+      /* Do not set breakpoint locations conditions yet.  As locations
+	 are inserted, they get sorted based on their addresses.  Let
+	 the list stabilize to have reliable location numbers.  */
 
       /* Dynamic printf requires and uses additional arguments on the
 	 command line, otherwise it's an error.  */
@@ -8852,6 +8929,19 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 	error (_("Garbage '%s' at end of command"), b->extra_string);
     }
 
+
+  /* The order of the locations is now stable.  Set the location
+     condition using the location's number.  */
+  int loc_num = 1;
+  for (bp_location *loc = b->loc; loc != nullptr; loc = loc->next)
+    {
+      if (b->cond_string != nullptr)
+	set_breakpoint_location_condition (b->cond_string, loc, b->number,
+					   loc_num);
+
+      ++loc_num;
+    }
+
   b->display_canonical = display_canonical;
   if (location != NULL)
     b->location = std::move (location);
@@ -9140,6 +9230,50 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
     }
 }
 
+/* Call 'find_condition_and_thread' for each sal in SALS until a parse
+   succeeds.  The parsed values are written to COND_STRING, THREAD,
+   TASK, and REST.  See the comment of 'find_condition_and_thread'
+   for the description of these parameters and INPUT.  */
+
+static void
+find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
+				    const char *input, char **cond_string,
+				    int *thread, int *task, char **rest)
+{
+  int num_failures = 0;
+  for (auto &sal : sals)
+    {
+      char *cond = nullptr;
+      int thread_id = 0;
+      int task_id = 0;
+      char *remaining = nullptr;
+
+      /* Here we want to parse 'arg' to separate condition from thread
+	 number.  But because parsing happens in a context and the
+	 contexts of sals might be different, try each until there is
+	 success.  Finding one successful parse is sufficient for our
+	 goal.  When setting the breakpoint we'll re-parse the
+	 condition in the context of each sal.  */
+      try
+	{
+	  find_condition_and_thread (input, sal.pc, &cond, &thread_id,
+				     &task_id, &remaining);
+	  *cond_string = cond;
+	  *thread = thread_id;
+	  *task = task_id;
+	  *rest = remaining;
+	  break;
+	}
+      catch (const gdb_exception_error &e)
+	{
+	  num_failures++;
+	  /* If no sal remains, do not continue.  */
+	  if (num_failures == sals.size ())
+	    throw;
+	}
+    }
+}
+
 /* Decode a static tracepoint marker spec.  */
 
 static std::vector<symtab_and_line>
@@ -9303,13 +9437,8 @@ create_breakpoint (struct gdbarch *gdbarch,
 
 	  const linespec_sals &lsal = canonical.lsals[0];
 
-	  /* Here we only parse 'arg' to separate condition
-	     from thread number, so parsing in context of first
-	     sal is OK.  When setting the breakpoint we'll
-	     re-parse it in context of each sal.  */
-
-	  find_condition_and_thread (extra_string, lsal.sals[0].pc,
-				     &cond, &thread, &task, &rest);
+	  find_condition_and_thread_for_sals (lsal.sals, extra_string,
+					      &cond, &thread, &task, &rest);
 	  cond_string_copy.reset (cond);
 	  extra_string_copy.reset (rest);
         }
@@ -13411,6 +13540,9 @@ locations_are_equal (struct bp_location *a, struct bp_location *b)
       if (a->enabled != b->enabled)
 	return 0;
 
+      if (a->disabled_by_cond != b->disabled_by_cond)
+	return 0;
+
       a = a->next;
       b = b->next;
     }
@@ -13518,10 +13650,7 @@ update_breakpoint_locations (struct breakpoint *b,
 	    }
 	  catch (const gdb_exception_error &e)
 	    {
-	      warning (_("failed to reevaluate condition "
-			 "for breakpoint %d: %s"), 
-		       b->number, e.what ());
-	      new_loc->enabled = 0;
+	      new_loc->disabled_by_cond = true;
 	    }
 	}
 
@@ -13546,7 +13675,7 @@ update_breakpoint_locations (struct breakpoint *b,
 
     for (; e; e = e->next)
       {
-	if (!e->enabled && e->function_name)
+	if ((!e->enabled || e->disabled_by_cond) && e->function_name)
 	  {
 	    struct bp_location *l = b->loc;
 	    if (have_ambiguous_names)
@@ -13562,7 +13691,8 @@ update_breakpoint_locations (struct breakpoint *b,
 		       enough.  */
 		    if (breakpoint_locations_match (e, l, true))
 		      {
-			l->enabled = 0;
+			l->enabled = e->enabled;
+			l->disabled_by_cond = e->disabled_by_cond;
 			break;
 		      }
 		  }
@@ -13573,7 +13703,8 @@ update_breakpoint_locations (struct breakpoint *b,
 		  if (l->function_name
 		      && strcmp (e->function_name, l->function_name) == 0)
 		    {
-		      l->enabled = 0;
+		      l->enabled = e->enabled;
+		      l->disabled_by_cond = e->disabled_by_cond;
 		      break;
 		    }
 	      }
@@ -13647,9 +13778,9 @@ location_to_sals (struct breakpoint *b, struct event_location *location,
 	  char *cond_string, *extra_string;
 	  int thread, task;
 
-	  find_condition_and_thread (b->extra_string, sals[0].pc,
-				     &cond_string, &thread, &task,
-				     &extra_string);
+	  find_condition_and_thread_for_sals (sals, b->extra_string,
+					      &cond_string, &thread,
+					      &task, &extra_string);
 	  gdb_assert (b->cond_string == NULL);
 	  if (cond_string)
 	    b->cond_string = cond_string;
@@ -14134,6 +14265,10 @@ enable_disable_bp_num_loc (int bp_num, int loc_num, bool enable)
   struct bp_location *loc = find_location_by_number (bp_num, loc_num);
   if (loc != NULL)
     {
+      if (loc->disabled_by_cond && enable)
+	error (_("Breakpoint %d's condition is invalid at location %d, "
+		 "cannot enable."), bp_num, loc_num);
+
       if (loc->enabled != enable)
 	{
 	  loc->enabled = enable;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index b9a605e6119..7d02cedf2fa 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -387,6 +387,12 @@ class bp_location
   /* Is this particular location enabled.  */
   bool enabled = false;
   
+  /* Is this particular location disabled because the condition
+     expression is invalid at this location.  For a location to be
+     reported as enabled, the ENABLED field above has to be true *and*
+     the DISABLED_BY_COND field has to be false.  */
+  bool disabled_by_cond = false;
+
   /* True if this breakpoint is now inserted.  */
   bool inserted = false;
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2636b6f9903..9da79ed5cde 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4278,6 +4278,46 @@ value is nonzero---that is, if @var{cond} evaluates as true.
 above (or no argument) specifying where to break.  @xref{Conditions,
 ,Break Conditions}, for more information on breakpoint conditions.
 
+The breakpoint may be mapped to multiple locations.  If the breakpoint
+condition @var{cond} is invalid at some but not all of the locations,
+the locations for which the condition is invalid are disabled.  For
+example, @value{GDBN} reports below that two of the three locations
+are disabled.
+
+@smallexample
+(@value{GDBP}) break func if a == 10
+warning: failed to validate condition at location 0x11ce, disabling:
+  No symbol "a" in current context.
+warning: failed to validate condition at location 0x11b6, disabling:
+  No symbol "a" in current context.
+Breakpoint 1 at 0x11b6: func. (3 locations)
+@end smallexample
+
+Locations that are disabled because of the condition are denoted by an
+uppercase @code{N} in the output of the @code{info breakpoints}
+command:
+
+@smallexample
+(@value{GDBP}) info breakpoints
+Num     Type           Disp Enb Address            What
+1       breakpoint     keep y   <MULTIPLE>
+        stop only if a == 10
+1.1                         N*  0x00000000000011b6 in ...
+1.2                         y   0x00000000000011c2 in ...
+1.3                         N*  0x00000000000011ce in ...
+(*): Breakpoint condition is invalid at this location.
+@end smallexample
+
+If the breakpoint condition @var{cond} is invalid in the context of
+@emph{all} the locations of the breakpoint, @value{GDBN} refuses to
+define the breakpoint.  For example, if variable @code{foo} is an
+undefined variable:
+
+@smallexample
+(@value{GDBP}) break func if foo
+No symbol "foo" in current context.
+@end smallexample
+
 @kindex tbreak
 @item tbreak @var{args}
 Set a breakpoint enabled only for one stop.  The @var{args} are the
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.cc b/gdb/testsuite/gdb.base/condbreak-multi-context.cc
new file mode 100644
index 00000000000..5e994e2428e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.cc
@@ -0,0 +1,54 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class Base
+{
+public:
+  int b = 20;
+
+  void func () {}
+};
+
+class A : public Base
+{
+public:
+  int a = 10;
+
+  void func () {}
+};
+
+class C : public Base
+{
+public:
+  int c = 30;
+
+  void func () {}
+};
+
+int
+main ()
+{
+  Base bobj;
+  A aobj;
+  C cobj;
+
+  aobj.func ();
+  bobj.func ();
+  cobj.func ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
new file mode 100644
index 00000000000..4e56d36fb43
--- /dev/null
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -0,0 +1,230 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test defining a conditional breakpoint that applies to multiple
+# locations with different contexts (e.g. different set of local vars).
+
+standard_testfile .cc
+
+if {[prepare_for_testing "failed to prepare" ${binfile} ${srcfile}]} {
+    return
+}
+
+set warning "warning: failed to validate condition"
+set fill "\[^\r\n\]*"
+
+# Check that breakpoints are as expected.
+
+proc test_info_break {suffix} {
+    global bpnum1 bpnum2 fill
+
+    set bp_hit_info "${fill}(\r\n${fill}breakpoint already hit 1 time)?"
+
+    gdb_test "info break ${bpnum1} ${bpnum2}" \
+	[multi_line \
+	     "Num${fill}" \
+	     "${bpnum1}${fill}breakpoint${fill}keep y${fill}MULTIPLE${fill}" \
+	     "${fill}stop only if a == 10${bp_hit_info}" \
+	     "${bpnum1}.1${fill}N\\*${fill}Base::func${fill}" \
+	     "${bpnum1}.2${fill}y${fill}A::func${fill}" \
+	     "${bpnum1}.3${fill}N\\*${fill}C::func${fill}" \
+	     "${bpnum2}${fill}breakpoint${fill}keep y${fill}MULTIPLE${fill}" \
+	     "${fill}stop only if c == 30${bp_hit_info}" \
+	     "${bpnum2}.1${fill}N\\*${fill}Base::func${fill}" \
+	     "${bpnum2}.2${fill}N\\*${fill}A::func${fill}" \
+	     "${bpnum2}.3${fill}y${fill}C::func${fill}" \
+	     "\\(\\*\\): Breakpoint condition is invalid at this location."] \
+	"info break $suffix"
+}
+
+# Scenario 1: Define breakpoints conditionally, using the "break N if
+# cond" syntax.  Run the program, check that we hit those locations
+# only.
+
+with_test_prefix "scenario 1" {
+    # Define the conditional breakpoints.
+    gdb_test "break func if a == 10" \
+	[multi_line \
+	     "${warning} at location 1, disabling:" \
+	     "  No symbol \"a\" in current context." \
+	     "${warning} at location 3, disabling:" \
+	     "  No symbol \"a\" in current context." \
+	     "Breakpoint $decimal at $fill .3 locations."] \
+	"define bp with condition a == 10"
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+
+    gdb_test "break func if c == 30" \
+	[multi_line \
+	     ".*${warning} at location 1, disabling:" \
+	     "  No symbol \"c\" in current context." \
+	     ".*${warning} at location 2, disabling:" \
+	     "  No symbol \"c\" in current context." \
+	     ".*Breakpoint $decimal at $fill .3 locations."] \
+	"define bp with condition c == 30"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+
+    test_info_break 1
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_run_cmd
+
+    # Check our conditional breakpoints.
+    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
+	"run until A::func"
+    gdb_test "print a" " = 10"
+
+    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
+	"run until C::func"
+    gdb_test "print c" " = 30"
+
+    # No more hits!
+    gdb_continue_to_end
+
+    test_info_break 2
+}
+
+# Start GDB with two breakpoints and define the conditions separately.
+
+proc setup_bps {} {
+    global srcfile binfile srcfile2
+    global bpnum1 bpnum2 bp_location warning
+
+    clean_restart ${binfile}
+
+    # Define the breakpoints.
+    gdb_breakpoint "func"
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+
+    gdb_breakpoint "func"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+
+    # Defining a condition on 'a' disables 2 locations.
+    gdb_test "cond $bpnum1 a == 10" \
+	[multi_line \
+	     "$warning at location ${bpnum1}.1, disabling:" \
+	     "  No symbol \"a\" in current context." \
+	     "$warning at location ${bpnum1}.3, disabling:" \
+	     "  No symbol \"a\" in current context."]
+
+    # Defining a condition on 'c' disables 2 locations.
+    gdb_test "cond $bpnum2 c == 30" \
+	[multi_line \
+	     "$warning at location ${bpnum2}.1, disabling:" \
+	     "  No symbol \"c\" in current context." \
+	     "$warning at location ${bpnum2}.2, disabling:" \
+	     "  No symbol \"c\" in current context."]
+}
+
+# Scenario 2: Define breakpoints unconditionally, and then define
+# conditions using the "cond N <cond>" syntax.  Expect that the
+# locations where <cond> is not evaluatable are disabled.  Run the
+# program, check that we hit the enabled locations only.
+
+with_test_prefix "scenario 2" {
+    setup_bps
+
+    test_info_break 1
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_run_cmd
+
+    # Check that we hit enabled locations only.
+    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
+	"run until A::func"
+    gdb_test "print a" " = 10"
+
+    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
+	"run until C::func"
+    gdb_test "print c" " = 30"
+
+    # No more hits!
+    gdb_continue_to_end
+
+    test_info_break 2
+}
+
+# Test the breakpoint location enabled states.
+
+proc check_bp_locations {bpnum states msg} {
+    global fill
+
+    set expected  ".*${bpnum}.1${fill} [lindex $states 0] ${fill}\r\n"
+    append expected "${bpnum}.2${fill} [lindex $states 1] ${fill}\r\n"
+    append expected "${bpnum}.3${fill} [lindex $states 2] ${fill}"
+    if {[lsearch $states N*] >= 0} {
+	append expected "\r\n\\(\\*\\): Breakpoint condition is invalid at this location."
+    }
+
+    gdb_test "info break $bpnum" $expected "check bp $bpnum $msg"
+}
+
+# Scenario 3: Apply misc. checks on the already-defined breakpoints.
+
+with_test_prefix "scenario 3" {
+    setup_bps
+
+    gdb_test "cond $bpnum1 c == 30" \
+	[multi_line \
+	     "${warning} at location ${bpnum1}.1, disabling:" \
+	     "  No symbol \"c\" in current context." \
+	     "${warning} at location ${bpnum1}.2, disabling:" \
+	     "  No symbol \"c\" in current context." \
+	     "Breakpoint ${bpnum1}'s condition is now valid at location 3, enabling."] \
+	"change the condition of bp 1"
+    check_bp_locations $bpnum1 {N* N* y} "after changing the condition"
+
+    gdb_test "cond $bpnum1" \
+	[multi_line \
+	     "Breakpoint ${bpnum1}'s condition is now valid at location 1, enabling." \
+	     "Breakpoint ${bpnum1}'s condition is now valid at location 2, enabling." \
+	     "Breakpoint ${bpnum1} now unconditional."] \
+	"reset the condition of bp 1"
+    check_bp_locations $bpnum1 {y y y} "after resetting the condition"
+
+    gdb_test_no_output "disable ${bpnum2}.2"
+    check_bp_locations $bpnum2 {N* N* y} "after disabling loc 2"
+
+    gdb_test "cond $bpnum2" ".*" "reset the condition of bp 2"
+    check_bp_locations $bpnum2 {y n y} "loc 2 should remain disabled"
+
+    gdb_test_no_output "disable ${bpnum2}.3"
+    check_bp_locations $bpnum2 {y n n} "after disabling loc 3"
+
+    gdb_test "cond $bpnum2 c == 30" \
+	[multi_line \
+	     "${warning} at location ${bpnum2}.1, disabling:" \
+	     "  No symbol \"c\" in current context."] \
+	"re-define a condition"
+    check_bp_locations $bpnum2 {N* N* n} "loc 3 should remain disabled"
+
+    gdb_test "enable ${bpnum2}.1" \
+	"Breakpoint ${bpnum2}'s condition is invalid at location 1, cannot enable." \
+	"reject enabling a location that is disabled-by-cond"
+    check_bp_locations $bpnum2 {N* N* n} "after enable attempt"
+
+    gdb_test "cond $bpnum2 garbage" \
+	"No symbol \"garbage\" in current context." \
+	"reject condition if bad for all locations"
+
+    gdb_test_no_output "delete $bpnum1"
+
+    # Do not use runto_main, it deletes all breakpoints.
+    gdb_breakpoint "main"
+    gdb_run_cmd
+    gdb_test "" ".*reakpoint .*, main .*${srcfile}.*" "start"
+
+    # The second BP's locations are all disabled.  No more hits!
+    gdb_continue_to_end
+}
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-13 12:25 ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
  2020-10-13 12:25   ` [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
@ 2020-10-13 12:25   ` Tankut Baris Aktemur
  2020-10-13 15:08     ` Eli Zaretskii
                       ` (2 more replies)
  2020-10-28 16:57   ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Gary Benson
  2 siblings, 3 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2020-10-13 12:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: simark

The previous patch made it possible to define a condition if it's
valid at some locations.  If the condition is invalid at all of the
locations, it's rejected.  However, there may be cases where the user
knows the condition *will* be valid at a location in the future,
e.g. due to a shared library load.

To make it possible that such condition can be defined, this patch
adds an optional '-force' flag to the 'condition' command, and,
respectively, a '-force-condition' flag to the 'break'command.  When
the force flag is passed, the condition is not rejected even when it
is invalid for all the current locations (note that all the locations
would be internally disabled in this case).

For instance:

  (gdb) break test.c:5
  Breakpoint 1 at 0x1155: file test.c, line 5.
  (gdb) cond 1 foo == 42
  No symbol "foo" in current context.

Defining the condition was not possible because 'foo' is not
available.  The user can override this behavior with the '-force'
flag:

  (gdb) cond -force 1 foo == 42
  warning: failed to validate condition at location 1.1, disabling:
    No symbol "foo" in current context.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
          stop only if foo == 42
  1.1                         N   0x0000000000001155 in main at test.c:5

Now the condition is accepted, but the location is automatically
disabled.  If a future location has a context in which 'foo' is
available, that location would be enabled.

For the 'break' command, -force-condition has the same result:

  (gdb) break test.c:5 -force-condition if foo == 42
  warning: failed to validate condition at location 0x1169, disabling:
    No symbol "foo" in current context.
  Breakpoint 1 at 0x1169: file test.c, line 5.

gdb/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (set_breakpoint_condition): Add a new bool parameter.
	* breakpoint.c: Update the help text of the 'condition' and 'break'
	commands.
	(set_breakpoint_condition): Take a new bool parameter
	to control whether condition definition should be forced even when
	the condition expression is invalid in all of the current locations.
	(condition_command): Update the call to 'set_breakpoint_condition'.
	(find_condition_and_thread): Take the "-force-condition" flag into
	account.
        * linespec.c (linespec_keywords): Add "-force-condition" as an
	element.
        (FORCE_KEYWORD_INDEX): New #define.
        (linespec_lexer_lex_keyword): Update to consider "-force-condition"
	as a keyword.
	* ada-lang.c (create_ada_exception_catchpoint): Ditto.
	* guile/scm-breakpoint.c (gdbscm_set_breakpoint_condition_x): Ditto.
	* python/py-breakpoint.c (bppy_set_condition): Ditto.

gdb/testsuite/ChangeLog:
2020-08-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.base/condbreak-multi-context.exp: Expand to test forcing
	the condition.
	* gdb.linespec/cpcompletion.exp: Update to consider the
	'-force-condition' keyword.
	* gdb.linespec/explicit.exp: Ditto.
	* lib/completion-support.exp: Ditto.

gdb/doc/ChangeLog:
2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (Set Breaks): Document the '-force-condition' flag
	of the 'break'command.
	* gdb.texinfo (Conditions): Document the '-force' flag of the
	'condition' command.
---
 gdb/ada-lang.c                                |  2 +-
 gdb/breakpoint.c                              | 52 ++++++++++++++++---
 gdb/breakpoint.h                              |  6 ++-
 gdb/doc/gdb.texinfo                           | 30 +++++++++++
 gdb/guile/scm-breakpoint.c                    |  2 +-
 gdb/linespec.c                                | 18 +++++--
 gdb/python/py-breakpoint.c                    |  2 +-
 .../gdb.base/condbreak-multi-context.exp      | 25 +++++++++
 gdb/testsuite/gdb.linespec/cpcompletion.exp   | 12 +++--
 gdb/testsuite/gdb.linespec/explicit.exp       |  1 +
 gdb/testsuite/lib/completion-support.exp      |  2 +-
 11 files changed, 131 insertions(+), 21 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index be6d0e1d019..4a2936f4c3f 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12684,7 +12684,7 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
   c->excep_string = excep_string;
   create_excep_cond_exprs (c.get (), ex_kind);
   if (!cond_string.empty ())
-    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty);
+    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty, false);
   install_breakpoint (0, std::move (c), 1);
 }
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8e41b4bab14..4611e8fb294 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -882,7 +882,7 @@ set_breakpoint_location_condition (const char *cond_string, bp_location *loc,
 
 void
 set_breakpoint_condition (struct breakpoint *b, const char *exp,
-			  int from_tty)
+			  int from_tty, bool force)
 {
   if (*exp == 0)
     {
@@ -950,9 +950,11 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 	      catch (const gdb_exception_error &e)
 		{
 		  /* Condition string is invalid.  If this happens to
-		     be the last loc, abandon.  */
+		     be the last loc, abandon (if not forced) or continue
+		     (if forced).  */
 		  if (loc->next == nullptr)
-		    throw;
+		    if (!force)
+		      throw;
 		}
 	    }
 
@@ -1032,6 +1034,18 @@ condition_command (const char *arg, int from_tty)
     error_no_arg (_("breakpoint number"));
 
   p = arg;
+
+  /* Check if the "-force" flag was passed.  */
+  bool force = false;
+  const char *tok = skip_spaces (p);
+  const char *end_tok = skip_to_space (tok);
+  int toklen = end_tok - tok;
+  if (toklen >= 1 && strncmp (tok, "-force", toklen) == 0)
+    {
+      force = true;
+      p = end_tok + 1;
+    }
+
   bnum = get_number (&p);
   if (bnum == 0)
     error (_("Bad breakpoint argument: '%s'"), arg);
@@ -1051,7 +1065,7 @@ condition_command (const char *arg, int from_tty)
 		     " a %s stop condition defined for this breakpoint."),
 		   ext_lang_capitalized_name (extlang));
 	  }
-	set_breakpoint_condition (b, p, from_tty);
+	set_breakpoint_condition (b, p, from_tty, force);
 
 	if (is_breakpoint (b))
 	  update_global_location_list (UGLL_MAY_INSERT);
@@ -9169,6 +9183,7 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
   *thread = -1;
   *task = 0;
   *rest = NULL;
+  bool force = false;
 
   while (tok && *tok)
     {
@@ -9192,10 +9207,25 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
       if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
 	{
 	  tok = cond_start = end_tok + 1;
-	  parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
+	  try
+	    {
+	      parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
+	    }
+	  catch (const gdb_exception_error &)
+	    {
+	      if (!force)
+		throw;
+	      else
+		tok = tok + strlen (tok);
+	    }
 	  cond_end = tok;
 	  *cond_string = savestring (cond_start, cond_end - cond_start);
 	}
+      else if (toklen >= 1 && strncmp (tok, "-force-condition", toklen) == 0)
+	{
+	  tok = cond_start = end_tok + 1;
+	  force = true;
+	}
       else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
 	{
 	  const char *tmptok;
@@ -15249,7 +15279,8 @@ specified name as a complete fully-qualified name instead."
    command.  */
 
 #define BREAK_ARGS_HELP(command) \
-command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
+command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM]\n\
+\t[-force-condition] [if CONDITION]\n\
 PROBE_MODIFIER shall be present if the command is to be placed in a\n\
 probe point.  Accepted values are `-probe' (for a generic, automatically\n\
 guessed probe type), `-probe-stap' (for a SystemTap probe) or \n\
@@ -15262,6 +15293,9 @@ stack frame.  This is useful for breaking on return to a stack frame.\n\
 \n\
 THREADNUM is the number from \"info threads\".\n\
 CONDITION is a boolean expression.\n\
+\n\
+With the \"-force-condition\" flag, the condition is defined even when\n\
+it is invalid for all current locations.\n\
 \n" LOCATION_HELP_STRING "\n\n\
 Multiple breakpoints at one place are permitted, and useful if their\n\
 conditions are different.\n\
@@ -15583,8 +15617,10 @@ then no output is printed when it is hit, except what the commands print."));
 
   c = add_com ("condition", class_breakpoint, condition_command, _("\
 Specify breakpoint number N to break only if COND is true.\n\
-Usage is `condition N COND', where N is an integer and COND is an\n\
-expression to be evaluated whenever breakpoint N is reached."));
+Usage is `condition [-force] N COND', where N is an integer and COND\n\
+is an expression to be evaluated whenever breakpoint N is reached.\n\
+With the \"-force\" flag, the condition is defined even when it is\n\
+invalid for all current locations."));
   set_cmd_completer (c, condition_completer);
 
   c = add_com ("tbreak", class_breakpoint, tbreak_command, _("\
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7d02cedf2fa..7845dd7f88f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1627,9 +1627,11 @@ extern int breakpoints_should_be_inserted_now (void);
    in our opinion won't ever trigger.  */
 extern void breakpoint_retire_moribund (void);
 
-/* Set break condition of breakpoint B to EXP.  */
+/* Set break condition of breakpoint B to EXP.
+   If FORCE, define the condition even if it is invalid in
+   all of the breakpoint locations.  */
 extern void set_breakpoint_condition (struct breakpoint *b, const char *exp,
-				      int from_tty);
+				      int from_tty, bool force);
 
 /* Checks if we are catching syscalls or not.
    Returns 0 if not, greater than 0 if we are.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9da79ed5cde..d779d4a84f1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4318,6 +4318,30 @@ undefined variable:
 No symbol "foo" in current context.
 @end smallexample
 
+@item break @dots{} -force-condition if @var{cond}
+There may be cases where the condition @var{cond} is invalid at all
+the current locations, but the user knows that it will be valid at a
+future location; for example, because of a library load.  In such
+cases, by using the @code{-force-condition} keyword before @samp{if},
+@value{GDBN} can be forced to define the breakpoint with the given
+condition expression instead of refusing it.
+
+@smallexample
+(@value{GDBP}) break func -force-condition if foo
+warning: failed to validate condition at location 1, disabling:
+  No symbol "foo" in current context.
+warning: failed to validate condition at location 2, disabling:
+  No symbol "foo" in current context.
+warning: failed to validate condition at location 3, disabling:
+  No symbol "foo" in current context.
+Breakpoint 1 at 0x1158: test.c:18. (3 locations)
+@end smallexample
+
+This causes all the present locations where the breakpoint would
+otherwise be inserted, to be disabled, as seen in the example above.
+However, if there exist locations at which the condition is valid, the
+@code{-force-condition} keyword has no effect.
+
 @kindex tbreak
 @item tbreak @var{args}
 Set a breakpoint enabled only for one stop.  The @var{args} are the
@@ -5503,6 +5527,12 @@ not actually evaluate @var{expression} at the time the @code{condition}
 command (or a command that sets a breakpoint with a condition, like
 @code{break if @dots{}}) is given, however.  @xref{Expressions, ,Expressions}.
 
+@item condition -force @var{bnum} @var{expression}
+When the @code{-force} flag is used, define the condition even if
+@var{expression} is invalid at all the current locations of breakpoint
+@var{bnum}.  This is similar to the @code{-force-condition} option
+of the @code{break} command.
+
 @item condition @var{bnum}
 Remove the condition from breakpoint number @var{bnum}.  It becomes
 an ordinary unconditional breakpoint.
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index 96b6ca91f8d..7c9707235ec 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -905,7 +905,7 @@ gdbscm_set_breakpoint_condition_x (SCM self, SCM newvalue)
 	   ? nullptr
 	   : gdbscm_scm_to_c_string (newvalue));
 
-      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0);
+      set_breakpoint_condition (bp_smob->bp, exp ? exp.get () : "", 0, false);
 
       return SCM_UNSPECIFIED;
     });
diff --git a/gdb/linespec.c b/gdb/linespec.c
index b05b8ad89a8..3ee299f5f0e 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -72,7 +72,7 @@ enum class linespec_complete_what
   /* An expression.  E.g., "break foo if EXPR", or "break *EXPR".  */
   EXPRESSION,
 
-  /* A linespec keyword ("if"/"thread"/"task").
+  /* A linespec keyword ("if"/"thread"/"task"/"-force-condition").
      E.g., "break func threa<tab>".  */
   KEYWORD,
 };
@@ -254,8 +254,9 @@ typedef enum ls_token_type linespec_token_type;
 
 /* List of keywords.  This is NULL-terminated so that it can be used
    as enum completer.  */
-const char * const linespec_keywords[] = { "if", "thread", "task", NULL };
+const char * const linespec_keywords[] = { "if", "thread", "task", "-force-condition", NULL };
 #define IF_KEYWORD_INDEX 0
+#define FORCE_KEYWORD_INDEX 3
 
 /* A token of the linespec lexer  */
 
@@ -486,11 +487,22 @@ linespec_lexer_lex_keyword (const char *p)
 	    {
 	      int j;
 
+	      /* Special case: "-force" is always followed by an "if".  */
+	      if (i == FORCE_KEYWORD_INDEX)
+		{
+		  p += len;
+		  p = skip_spaces (p);
+		  int nextlen = strlen (linespec_keywords[IF_KEYWORD_INDEX]);
+		  if (!(strncmp (p, linespec_keywords[IF_KEYWORD_INDEX], nextlen) == 0
+			&& isspace (p[nextlen])))
+		    return NULL;
+		}
+
 	      /* Special case: "if" ALWAYS stops the lexer, since it
 		 is not possible to predict what is going to appear in
 		 the condition, which can only be parsed after SaLs have
 		 been found.  */
-	      if (i != IF_KEYWORD_INDEX)
+	      else if (i != IF_KEYWORD_INDEX)
 		{
 		  p += len;
 		  p = skip_spaces (p);
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 7369c91ad90..8099b06531b 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -461,7 +461,7 @@ bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
 
   try
     {
-      set_breakpoint_condition (self_bp->bp, exp, 0);
+      set_breakpoint_condition (self_bp->bp, exp, 0, false);
     }
   catch (gdb_exception &ex)
     {
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
index 4e56d36fb43..cef4280a81c 100644
--- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -228,3 +228,28 @@ with_test_prefix "scenario 3" {
     # The second BP's locations are all disabled.  No more hits!
     gdb_continue_to_end
 }
+
+# Scenario 4: Test the '-force'/'-force-condition' flag.
+
+with_test_prefix "force" {
+    clean_restart ${binfile}
+
+    gdb_breakpoint "func"
+    # Pick a condition that is invalid at every location.
+    set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
+    gdb_test "cond -force $bpnum1 foo" \
+	[multi_line \
+	     "${warning} at location ${bpnum1}.1, disabling:" \
+	     "  No symbol \"foo\" in current context." \
+	     "${warning} at location ${bpnum1}.2, disabling:" \
+	     "  No symbol \"foo\" in current context." \
+	     "${warning} at location ${bpnum1}.3, disabling:" \
+	     "  No symbol \"foo\" in current context."] \
+	"force the condition of bp 1"
+    check_bp_locations $bpnum1 {N* N* N*} "after forcing the condition"
+
+    # Now with the 'break' command.
+    gdb_breakpoint "func -force-condition if baz"
+    set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
+    check_bp_locations $bpnum2 {N* N* N*} "set using the break command"
+}
diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp
index 2c95e2b4048..de96556f22d 100644
--- a/gdb/testsuite/gdb.linespec/cpcompletion.exp
+++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp
@@ -836,12 +836,14 @@ proc_with_prefix function-labels {} {
 }
 
 # Test that completion after a function name offers keyword
-# (if/task/thread) matches in linespec mode, and also the explicit
-# location options in explicit locations mode.
+# (if/task/thread/-force-condition) matches in linespec mode, and also
+# the explicit location options in explicit locations mode.
 
 proc_with_prefix keywords-after-function {} {
     set explicit_list \
-	[concat $completion::explicit_opts_list $completion::keyword_list]
+	[lsort [concat \
+		    $completion::explicit_opts_list \
+		    $completion::keyword_list]]
 
     # Test without a source file, with a known source file, and with
     # and unknown source file.
@@ -865,7 +867,9 @@ proc_with_prefix keywords-after-function {} {
 
 proc_with_prefix keywords-after-label {} {
     set explicit_list \
-	[concat $completion::explicit_opts_list $completion::keyword_list]
+	[lsort [concat \
+		    $completion::explicit_opts_list \
+		    $completion::keyword_list]]
 
     foreach_location_labels \
 	{ "" "cpls.cc" } \
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
index 4f457dc372f..5e3d352918e 100644
--- a/gdb/testsuite/gdb.linespec/explicit.exp
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -405,6 +405,7 @@ namespace eval $testfile {
 	# completion matches both the explicit location options and
 	# the linespec keywords.
 	set completions_list {
+	    "-force-condition"
 	    "-function"
 	    "-label"
 	    "-line"
diff --git a/gdb/testsuite/lib/completion-support.exp b/gdb/testsuite/lib/completion-support.exp
index 51436cc6713..dbb958157ed 100644
--- a/gdb/testsuite/lib/completion-support.exp
+++ b/gdb/testsuite/lib/completion-support.exp
@@ -27,7 +27,7 @@ namespace eval completion {
     # List of all quote chars, including no-quote at all.
     variable maybe_quoted_list {"" "'" "\""}
 
-    variable keyword_list {"if" "task" "thread"}
+    variable keyword_list {"-force-condition" "if" "task" "thread"}
 
     variable explicit_opts_list \
 	{"-function" "-label" "-line" "-qualified" "-source"}
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-10-13 12:25   ` [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
@ 2020-10-13 15:06     ` Eli Zaretskii
  2020-10-13 15:17       ` Aktemur, Tankut Baris
  2020-10-16 22:20     ` Simon Marchi
  1 sibling, 1 reply; 103+ messages in thread
From: Eli Zaretskii @ 2020-10-13 15:06 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches, simark

> Date: Tue, 13 Oct 2020 14:25:02 +0200
> From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> Cc: simark@simark.ca
> 
> gdb/ChangeLog:
> 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* breakpoint.h (class bp_location) <disabled_by_cond>: New field.
> 	* breakpoint.c (set_breakpoint_location_condition): New function.
> 	(set_breakpoint_condition): Disable a breakpoint
> 	location if parsing the condition string gives an error.
> 	(should_be_inserted): Update to consider the 'disabled_by_cond' field.
> 	(build_target_condition_list): Ditto.
> 	(build_target_command_list): Ditto.
> 	(build_bpstat_chain): Ditto.
> 	(print_one_breakpoint_location): Ditto.
> 	(print_one_breakpoint): Ditto.
> 	(breakpoint_1): Ditto.
> 	(bp_location::bp_location): Ditto.
> 	(locations_are_equal): Ditto.
> 	(update_breakpoint_locations): Ditto.
> 	(enable_disable_bp_num_loc): Ditto.
> 	(init_breakpoint_sal): Use set_breakpoint_location_condition.
> 	(find_condition_and_thread_for_sals): New static function.
> 	(create_breakpoint): Call find_condition_and_thread_for_sals.
> 	(location_to_sals): Call find_condition_and_thread_for_sals instead
> 	of find_condition_and_thread.
> 
> gdb/testsuite/ChangeLog:
> 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.base/condbreak-multi-context.cc: New file.
> 	* gdb.base/condbreak-multi-context.exp: New file.
> 
> gdb/doc/ChangeLog:
> 2020-09-25  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.texinfo (Set Breaks): Document disabling of breakpoint
> 	locations for which the breakpoint condition is invalid.

OK for the documentation part.

But I have to wonder: GDB can automatically disable some conditional
breakpoints, but it leaves enabling them to the user?

Thanks.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-13 12:25   ` [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
@ 2020-10-13 15:08     ` Eli Zaretskii
  2020-10-13 15:46       ` Aktemur, Tankut Baris
  2020-10-16 22:45     ` Simon Marchi
  2020-10-29 17:30     ` Pedro Alves
  2 siblings, 1 reply; 103+ messages in thread
From: Eli Zaretskii @ 2020-10-13 15:08 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches, simark

> Date: Tue, 13 Oct 2020 14:25:03 +0200
> From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> Cc: simark@simark.ca
> 
> gdb/ChangeLog:
> 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* breakpoint.h (set_breakpoint_condition): Add a new bool parameter.
> 	* breakpoint.c: Update the help text of the 'condition' and 'break'
> 	commands.
> 	(set_breakpoint_condition): Take a new bool parameter
> 	to control whether condition definition should be forced even when
> 	the condition expression is invalid in all of the current locations.
> 	(condition_command): Update the call to 'set_breakpoint_condition'.
> 	(find_condition_and_thread): Take the "-force-condition" flag into
> 	account.
>         * linespec.c (linespec_keywords): Add "-force-condition" as an
> 	element.
>         (FORCE_KEYWORD_INDEX): New #define.
>         (linespec_lexer_lex_keyword): Update to consider "-force-condition"
> 	as a keyword.
> 	* ada-lang.c (create_ada_exception_catchpoint): Ditto.
> 	* guile/scm-breakpoint.c (gdbscm_set_breakpoint_condition_x): Ditto.
> 	* python/py-breakpoint.c (bppy_set_condition): Ditto.
> 
> gdb/testsuite/ChangeLog:
> 2020-08-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.base/condbreak-multi-context.exp: Expand to test forcing
> 	the condition.
> 	* gdb.linespec/cpcompletion.exp: Update to consider the
> 	'-force-condition' keyword.
> 	* gdb.linespec/explicit.exp: Ditto.
> 	* lib/completion-support.exp: Ditto.
> 
> gdb/doc/ChangeLog:
> 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.texinfo (Set Breaks): Document the '-force-condition' flag
> 	of the 'break'command.
> 	* gdb.texinfo (Conditions): Document the '-force' flag of the
> 	'condition' command.

OK for the documentation part.

What about the NEWS?

Thanks.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-10-13 15:06     ` Eli Zaretskii
@ 2020-10-13 15:17       ` Aktemur, Tankut Baris
  0 siblings, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-10-13 15:17 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, simark

On Tuesday, October 13, 2020 5:07 PM, Eli Zaretskii wrote:
> > Date: Tue, 13 Oct 2020 14:25:02 +0200
> > From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> > Cc: simark@simark.ca
> >
> > gdb/ChangeLog:
> > 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> >
> > 	* breakpoint.h (class bp_location) <disabled_by_cond>: New field.
> > 	* breakpoint.c (set_breakpoint_location_condition): New function.
> > 	(set_breakpoint_condition): Disable a breakpoint
> > 	location if parsing the condition string gives an error.
> > 	(should_be_inserted): Update to consider the 'disabled_by_cond' field.
> > 	(build_target_condition_list): Ditto.
> > 	(build_target_command_list): Ditto.
> > 	(build_bpstat_chain): Ditto.
> > 	(print_one_breakpoint_location): Ditto.
> > 	(print_one_breakpoint): Ditto.
> > 	(breakpoint_1): Ditto.
> > 	(bp_location::bp_location): Ditto.
> > 	(locations_are_equal): Ditto.
> > 	(update_breakpoint_locations): Ditto.
> > 	(enable_disable_bp_num_loc): Ditto.
> > 	(init_breakpoint_sal): Use set_breakpoint_location_condition.
> > 	(find_condition_and_thread_for_sals): New static function.
> > 	(create_breakpoint): Call find_condition_and_thread_for_sals.
> > 	(location_to_sals): Call find_condition_and_thread_for_sals instead
> > 	of find_condition_and_thread.
> >
> > gdb/testsuite/ChangeLog:
> > 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> >
> > 	* gdb.base/condbreak-multi-context.cc: New file.
> > 	* gdb.base/condbreak-multi-context.exp: New file.
> >
> > gdb/doc/ChangeLog:
> > 2020-09-25  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> >
> > 	* gdb.texinfo (Set Breaks): Document disabling of breakpoint
> > 	locations for which the breakpoint condition is invalid.
> 
> OK for the documentation part.
> 
> But I have to wonder: GDB can automatically disable some conditional
> breakpoints, but it leaves enabling them to the user?

If the condition is invalid at a location, GDB will disable that location.
The user cannot enable it manually, unless they change the condition and
the new condition is validated at the location.  In that case the location
automatically becomes enabled again. 

Thanks
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-13 15:08     ` Eli Zaretskii
@ 2020-10-13 15:46       ` Aktemur, Tankut Baris
  2020-10-13 16:12         ` Eli Zaretskii
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-10-13 15:46 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, simark

On Tuesday, October 13, 2020 5:09 PM, Eli Zaretskii wrote:
> > Date: Tue, 13 Oct 2020 14:25:03 +0200
> > From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> > Cc: simark@simark.ca
> >
> > gdb/ChangeLog:
> > 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> >
> > 	* breakpoint.h (set_breakpoint_condition): Add a new bool parameter.
> > 	* breakpoint.c: Update the help text of the 'condition' and 'break'
> > 	commands.
> > 	(set_breakpoint_condition): Take a new bool parameter
> > 	to control whether condition definition should be forced even when
> > 	the condition expression is invalid in all of the current locations.
> > 	(condition_command): Update the call to 'set_breakpoint_condition'.
> > 	(find_condition_and_thread): Take the "-force-condition" flag into
> > 	account.
> >         * linespec.c (linespec_keywords): Add "-force-condition" as an
> > 	element.
> >         (FORCE_KEYWORD_INDEX): New #define.
> >         (linespec_lexer_lex_keyword): Update to consider "-force-condition"
> > 	as a keyword.
> > 	* ada-lang.c (create_ada_exception_catchpoint): Ditto.
> > 	* guile/scm-breakpoint.c (gdbscm_set_breakpoint_condition_x): Ditto.
> > 	* python/py-breakpoint.c (bppy_set_condition): Ditto.
> >
> > gdb/testsuite/ChangeLog:
> > 2020-08-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> >
> > 	* gdb.base/condbreak-multi-context.exp: Expand to test forcing
> > 	the condition.
> > 	* gdb.linespec/cpcompletion.exp: Update to consider the
> > 	'-force-condition' keyword.
> > 	* gdb.linespec/explicit.exp: Ditto.
> > 	* lib/completion-support.exp: Ditto.
> >
> > gdb/doc/ChangeLog:
> > 2020-07-31  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> >
> > 	* gdb.texinfo (Set Breaks): Document the '-force-condition' flag
> > 	of the 'break'command.
> > 	* gdb.texinfo (Conditions): Document the '-force' flag of the
> > 	'condition' command.
> 
> OK for the documentation part.
> 
> What about the NEWS?

I forgot about it.  Thanks for reminding.  How about the change below?

diff --git a/gdb/NEWS b/gdb/NEWS
index 1789cf31356..c99d3181a8b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -21,6 +21,28 @@ set debug event-loop
 show debug event-loop
   Control the display of debug output about GDB's event loop.

+* Changed commands
+
+break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM]
+      [-force-condition] [if CONDITION]
+  This command would previously refuse setting a breakpoint if the
+  CONDITION expression is invalid at a location.  It now accepts and
+  defines the breakpoint if there is at least one location at which
+  the CONDITION is valid.  The locations for which the CONDITION is
+  invalid, are automatically disabled.  If CONDITION is invalid at all
+  of the locations, setting the breakpoint is still rejected.  However,
+  the '-force-condition' flag can be used in this case for forcing GDB to
+  define the breakpoint, making all the current locations automatically
+  disabled.  This may be useful if the user knows the condition will
+  become meaningful at a future location, e.g. due to a shared library
+  load.
+
+condition [-force] N COND
+  The behavior of this command is changed the same way for the 'break'
+  command as explained above.  The '-force' flag can be used to force
+  GDB into defining the condition even when COND is invalid for all the
+  current locations of breakpoint N.
+
 *** Changes in GDB 10

 * There are new feature names for ARC targets: "org.gnu.gdb.arc.core"


Thanks,
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-13 15:46       ` Aktemur, Tankut Baris
@ 2020-10-13 16:12         ` Eli Zaretskii
  0 siblings, 0 replies; 103+ messages in thread
From: Eli Zaretskii @ 2020-10-13 16:12 UTC (permalink / raw)
  To: Aktemur, Tankut Baris; +Cc: gdb-patches, simark

> From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com>
> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>,
> 	"simark@simark.ca" <simark@simark.ca>
> Date: Tue, 13 Oct 2020 15:46:43 +0000
> 
> > What about the NEWS?

> 

> I forgot about it.  Thanks for reminding.  How about the change below?

> 

> diff --git a/gdb/NEWS b/gdb/NEWS

> index 1789cf31356..c99d3181a8b 100644

> --- a/gdb/NEWS

> +++ b/gdb/NEWS


Thanks, this is OK.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location
  2020-10-13 12:25   ` [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
  2020-10-13 15:06     ` Eli Zaretskii
@ 2020-10-16 22:20     ` Simon Marchi
  1 sibling, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2020-10-16 22:20 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches

On 2020-10-13 8:25 a.m., Tankut Baris Aktemur via Gdb-patches wrote:
> Currently, for a conditional breakpoint, GDB checks if the condition
> can be evaluated in the context of the first symtab and line (SAL).
> In case of an error, defining the conditional breakpoint is aborted.
> This prevents having a conditional breakpoint whose condition may
> actually be meaningful for some of the location contexts.  This patch
> makes it possible to define conditional BPs by checking all location
> contexts.  If the condition is meaningful for even one context, the
> breakpoint is defined.  The locations for which the condition gives
> errors are disabled.
>
> The bp_location struct is introduced a new field, 'disabled_by_cond'.
> This field denotes whether the location is disabled automatically
> because the condition was non-evaluatable.  Disabled-by-cond locations
> cannot be enabled by the user.  But locations that are not
> disabled-by-cond can be enabled/disabled by the user manually as
> before.
>
> For a concrete example, consider 3 contexts of a function 'func'.
>
>   class Base
>   {
>   public:
>     int b = 20;
>
>     void func () {}
>   };
>
>   class A : public Base
>   {
>   public:
>     int a = 10;
>
>     void func () {}
>   };
>
>   class C : public Base
>   {
>   public:
>     int c = 30;
>
>     void func () {}
>   };
>
> Note that
>
> * the variable 'a' is defined only in the context of A::func.
> * the variable 'c' is defined only in the context of C::func.
> * the variable 'b' is defined in all the three contexts.
>
> With the existing GDB, it's not possible to define a conditional
> breakpoint at 'func' if the condition refers to 'a' or 'c':
>
>   (gdb) break func if a == 10
>   No symbol "a" in current context.
>   (gdb) break func if c == 30
>   No symbol "c" in current context.
>   (gdb) info breakpoints
>   No breakpoints or watchpoints.
>
> With this patch, it becomes possible:
>
>   (gdb) break func if a == 10
>   warning: failed to validate condition at location 1, disabling:
>     No symbol "a" in current context.
>   warning: failed to validate condition at location 3, disabling:
>     No symbol "a" in current context.
>   Breakpoint 1 at 0x11b6: func. (3 locations)
>   (gdb) break func if c == 30
>   Note: breakpoint 1 also set at pc 0x11ce.
>   Note: breakpoint 1 also set at pc 0x11c2.
>   Note: breakpoint 1 also set at pc 0x11b6.
>   warning: failed to validate condition at location 1, disabling:
>     No symbol "c" in current context.
>   warning: failed to validate condition at location 2, disabling:
>     No symbol "c" in current context.
>   Breakpoint 2 at 0x11b6: func. (3 locations)
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if a == 10
>   1.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
>   1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
>   1.3                         N*  0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
>   2       breakpoint     keep y   <MULTIPLE>
>           stop only if c == 30
>   2.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
>   2.2                         N*  0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
>   2.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
>   (*): Breakpoint condition is invalid at this location.
>
> Here, uppercase 'N' denotes that the location is disabled because of
> the invalid condition, as mentioned with a footnote in the legend of
> the table.  Locations that are disabled by the user are still denoted
> with lowercase 'n'.  Executing the code hits the breakpoints 1.2 and
> 2.3 as expected.
>
> Defining a condition on an unconditional breakpoint gives the same
> behavior above:
>
>   (gdb) break func
>   Breakpoint 1 at 0x11b6: func. (3 locations)
>   (gdb) cond 1 a == 10
>   warning: failed to validate condition at location 1.1, disabling:
>     No symbol "a" in current context.
>   warning: failed to validate condition at location 1.3, disabling:
>     No symbol "a" in current context.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if a == 10
>   1.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
>   1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
>   1.3                         N*  0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
>   (*): Breakpoint condition is invalid at this location.
>
> Locations that are disabled because of a condition cannot be enabled
> by the user:
>
>   ...
>   (gdb) enable 1.1
>   Breakpoint 1's condition is invalid at location 1, cannot enable.
>
> Resetting the condition enables the locations back:
>
>   ...
>   (gdb) cond 1
>   Breakpoint 1's condition is now valid at location 1, enabling.
>   Breakpoint 1's condition is now valid at location 3, enabling.
>   Breakpoint 1 now unconditional.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>   1.1                         y   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
>   1.2                         y   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
>   1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
>
> If a location is disabled by the user, a condition can still be defined
> but the location will remain disabled even if the condition is meaningful
> for the disabled location:
>
>   ...
>   (gdb) disable 1.2
>   (gdb) cond 1 a == 10
>   warning: failed to validate condition at location 1.1, disabling:
>     No symbol "a" in current context.
>   warning: failed to validate condition at location 1.3, disabling:
>     No symbol "a" in current context.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if a == 10
>   1.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
>   1.2                         n   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
>   1.3                         N*  0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
>   (*): Breakpoint condition is invalid at this location.
>
> The condition of a breakpoint can be changed.  Locations'
> enable/disable states are updated accordingly.
>
>   ...
>   (gdb) cond 1 c == 30
>   warning: failed to validate condition at location 1.1, disabling:
>     No symbol "c" in current context.
>   Breakpoint 1's condition is now valid at location 3, enabling.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if c == 30
>   1.1                         N*  0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
>   1.2                         N*  0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
>   1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
>   (*): Breakpoint condition is invalid at this location.
>
>   (gdb) cond 1 b == 20
>   Breakpoint 1's condition is now valid at location 1, enabling.
>   (gdb) info breakpoints
>   Num     Type           Disp Enb Address            What
>   1       breakpoint     keep y   <MULTIPLE>
>           stop only if b == 20
>   1.1                         y   0x00000000000011b6 in Base::func() at condbreak-multi-context.cc:23
>   1.2                         n   0x00000000000011c2 in A::func() at condbreak-multi-context.cc:31
>   1.3                         y   0x00000000000011ce in C::func() at condbreak-multi-context.cc:39
>   # Note that location 1.2 was disabled by the user previously.
>
> If the condition expression is bad for all the locations, it will be
> rejected.
>
>   (gdb) cond 1 garbage
>   No symbol "garbage" in current context.
>
> For conditions that are invalid or valid for all the locations of a
> breakpoint, the existing behavior is preserved.
>
> Regression-tested on X86_64 Linux.

Hi Baris,

Since I didn't have any major issue with the previous version, I just
took a quick look at this one, and I think it's fine.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-13 12:25   ` [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
  2020-10-13 15:08     ` Eli Zaretskii
@ 2020-10-16 22:45     ` Simon Marchi
  2020-10-19 13:58       ` Aktemur, Tankut Baris
  2020-10-29 17:30     ` Pedro Alves
  2 siblings, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2020-10-16 22:45 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches


I don't have time to review this in as much depth as I'd like, but I
took a quick look at the code and tested the user experience, and it
looks good to me.  If nobody else has anything to add in ~1 week from
now, I'm fine with you merging this.

Some small comments below:

On 2020-10-13 8:25 a.m., Tankut Baris Aktemur via Gdb-patches wrote:
> @@ -950,9 +950,11 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
>  	      catch (const gdb_exception_error &e)
>  		{
>  		  /* Condition string is invalid.  If this happens to
> -		     be the last loc, abandon.  */
> +		     be the last loc, abandon (if not forced) or continue
> +		     (if forced).  */
>  		  if (loc->next == nullptr)
> -		    throw;
> +		    if (!force)
> +		      throw;

Either do

  if (loc->next == nullptr && !force)
    throw;

... or add braces to the outer if.

>  		}
>  	    }
>
> @@ -1032,6 +1034,18 @@ condition_command (const char *arg, int from_tty)
>      error_no_arg (_("breakpoint number"));
>
>    p = arg;
> +
> +  /* Check if the "-force" flag was passed.  */
> +  bool force = false;
> +  const char *tok = skip_spaces (p);
> +  const char *end_tok = skip_to_space (tok);
> +  int toklen = end_tok - tok;
> +  if (toklen >= 1 && strncmp (tok, "-force", toklen) == 0)
> +    {
> +      force = true;
> +      p = end_tok + 1;
> +    }
> +

Is there a chance you could use the gdb::option framework here?  That
should give tab-completion for free, in addition to simplify the
parsing.  I've never used it myself, so I don't know for sure it applies
here, but it's worth checking.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-16 22:45     ` Simon Marchi
@ 2020-10-19 13:58       ` Aktemur, Tankut Baris
  2020-10-19 14:07         ` Simon Marchi
  2020-10-27 10:13         ` Aktemur, Tankut Baris
  0 siblings, 2 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-10-19 13:58 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Saturday, October 17, 2020 12:46 AM, Simon Marchi wrote:
> I don't have time to review this in as much depth as I'd like, but I
> took a quick look at the code and tested the user experience, and it
> looks good to me.  If nobody else has anything to add in ~1 week from
> now, I'm fine with you merging this.

Hi Simon,

Thank you for your comments.  I'll wait for ~1 week as you suggest, and then merge
both patches.
 
> Some small comments below:
> 
> On 2020-10-13 8:25 a.m., Tankut Baris Aktemur via Gdb-patches wrote:
> > @@ -950,9 +950,11 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
> >  	      catch (const gdb_exception_error &e)
> >  		{
> >  		  /* Condition string is invalid.  If this happens to
> > -		     be the last loc, abandon.  */
> > +		     be the last loc, abandon (if not forced) or continue
> > +		     (if forced).  */
> >  		  if (loc->next == nullptr)
> > -		    throw;
> > +		    if (!force)
> > +		      throw;
> 
> Either do
> 
>   if (loc->next == nullptr && !force)
>     throw;
> 
> ... or add braces to the outer if.

Fixed by merging the conditions with a '&&'.

> 
> >  		}
> >  	    }
> >
> > @@ -1032,6 +1034,18 @@ condition_command (const char *arg, int from_tty)
> >      error_no_arg (_("breakpoint number"));
> >
> >    p = arg;
> > +
> > +  /* Check if the "-force" flag was passed.  */
> > +  bool force = false;
> > +  const char *tok = skip_spaces (p);
> > +  const char *end_tok = skip_to_space (tok);
> > +  int toklen = end_tok - tok;
> > +  if (toklen >= 1 && strncmp (tok, "-force", toklen) == 0)
> > +    {
> > +      force = true;
> > +      p = end_tok + 1;
> > +    }
> > +
> 
> Is there a chance you could use the gdb::option framework here?  That
> should give tab-completion for free, in addition to simplify the
> parsing.  I've never used it myself, so I don't know for sure it applies
> here, but it's worth checking.

I checked it and yes, it's applicable.  I found other similar uses (like the '-gid'
flag for 'info threads').  But let me send this as a separate, follow-up patch, to
make the review process easier.  OK with that?

-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-19 13:58       ` Aktemur, Tankut Baris
@ 2020-10-19 14:07         ` Simon Marchi
  2020-10-27 10:13         ` Aktemur, Tankut Baris
  1 sibling, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2020-10-19 14:07 UTC (permalink / raw)
  To: Aktemur, Tankut Baris, gdb-patches

On 2020-10-19 9:58 a.m., Aktemur, Tankut Baris wrote:
> I checked it and yes, it's applicable.  I found other similar uses (like the '-gid'
> flag for 'info threads').  But let me send this as a separate, follow-up patch, to
> make the review process easier.  OK with that?

Yes, sure.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-19 13:58       ` Aktemur, Tankut Baris
  2020-10-19 14:07         ` Simon Marchi
@ 2020-10-27 10:13         ` Aktemur, Tankut Baris
  2020-10-29 10:10           ` Tom de Vries
  1 sibling, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-10-27 10:13 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Monday, October 19, 2020 3:59 PM, Aktemur, Tankut Baris wrote:
> On Saturday, October 17, 2020 12:46 AM, Simon Marchi wrote:
> > I don't have time to review this in as much depth as I'd like, but I
> > took a quick look at the code and tested the user experience, and it
> > looks good to me.  If nobody else has anything to add in ~1 week from
> > now, I'm fine with you merging this.
> 
> Hi Simon,
> 
> Thank you for your comments.  I'll wait for ~1 week as you suggest, and then merge
> both patches.

I just pushed the patches.
Thanks.

-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts
  2020-10-13 12:25 ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
  2020-10-13 12:25   ` [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
  2020-10-13 12:25   ` [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
@ 2020-10-28 16:57   ` Gary Benson
  2020-10-29  7:43     ` Aktemur, Tankut Baris
  2 siblings, 1 reply; 103+ messages in thread
From: Gary Benson @ 2020-10-28 16:57 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches, simark

Hi Baris,

Tankut Baris Aktemur wrote:
>  create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp

This test fails if you build the test executable with Clang.  I've
inlined a full diff of the gdb.log files below, but I think the
issue is that Clang and GCC are writing the code or the debuginfo
in a different order, so where the test expects to see breakpoints
like:

  1.1 Base::func()
  1.2 A::func()
  1.3 C::func()

but what it gets with Clang is:

  1.1 A::func()
  1.2 Base::func()
  1.3 C::func()

Are you able to update the test to handle this?

In case you're not familiar with switching compilers you should be
able to do it by adding CC_FOR_TARGET=clang and CXX_FOR_TARGET=clang++
to your RUNTESTFLAGS, e.g.:

  cd /path/to/your/build
  export RUNTESTFLAGS="CC_FOR_TARGET=clang CXX_FOR_TARGET=clang++"
  make check TESTS=gdb.base/condbreak-multi-context.exp

Cheers,
Gary

-- 
--- /gdbtest/2020-10-28/with-gcc/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/gdb.log	2020-10-28 15:42:08.465601501 +0000
+++ /gdbtest/2020-10-28/with-clang/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/gdb.log	2020-10-28 15:53:48.394477290 +0000
@@ -1,24 +1,24 @@
-Test run by gdbtest on Wed Oct 28 15:42:04 2020
+Test run by gdbtest on Wed Oct 28 15:53:43 2020
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gdb tests ===
 
 Schedule of variations:
-    gdbtest-with-gcc
+    gdbtest-with-clang
 
-Running target gdbtest-with-gcc
-Using /gdbtest/gdbtest/boards/gdbtest-with-gcc.exp as board description file for target.
+Running target gdbtest-with-clang
+Using /gdbtest/gdbtest/boards/gdbtest-with-clang.exp as board description file for target.
 Using /gdbtest/gdbtest/boards/gdbtest-base.exp as board description file for target.
 Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
 Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
 Using /gdbtest/src/gdb/testsuite/boards/../boards/local-board.exp as board description file for target.
 Using /gdbtest/src/gdb/testsuite/config/unix.exp as tool-and-target-specific interface file.
 Running /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.exp ...
-get_compiler_info: gcc-10-2-1
-Executing on host: gcc  -fno-stack-protector  -fdiagnostics-color=never -c -g  -o /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context0.o /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc    (timeout = 300)
-spawn -ignore SIGHUP gcc -fno-stack-protector -fdiagnostics-color=never -c -g -o /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context0.o /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc
-Executing on host: gcc  -fno-stack-protector /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context0.o  -fdiagnostics-color=never -g  -lm   -o /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context    (timeout = 300)
-spawn -ignore SIGHUP gcc -fno-stack-protector /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context0.o -fdiagnostics-color=never -g -lm -o /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context
+get_compiler_info: clang-12-0-0
+Executing on host: clang   -fdiagnostics-color=never -Wno-unknown-warning-option -c -g -o /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context0.o /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc    (timeout = 300)
+spawn -ignore SIGHUP clang -fdiagnostics-color=never -Wno-unknown-warning-option -c -g -o /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context0.o /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc
+Executing on host: clang /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context0.o   -fdiagnostics-color=never -Wno-unknown-warning-option -g  -lm  -o /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context    (timeout = 300)
+spawn -ignore SIGHUP clang /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context0.o -fdiagnostics-color=never -Wno-unknown-warning-option -g -lm -o /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context
 spawn /gdbtest/build/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /gdbtest/build/gdb/testsuite/../data-directory -iex set height 0 -iex set width 0 -ex set sysroot
 GNU gdb (GDB) 11.0.50.20201027-git
 Copyright (C) 2020 Free Software Foundation, Inc.
@@ -47,24 +47,24 @@
 (gdb) file /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context
 Reading symbols from /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context...
 (gdb) break func if a == 10
-warning: failed to validate condition at location 1, disabling:
+warning: failed to validate condition at location 2, disabling:
   No symbol "a" in current context.
 warning: failed to validate condition at location 3, disabling:
   No symbol "a" in current context.
-Breakpoint 1 at 0x401164: func. (3 locations)
-(gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: define bp with condition a == 10
+Breakpoint 1 at 0x4011e8: func. (3 locations)
+(gdb) FAIL: gdb.base/condbreak-multi-context.exp: scenario 1: define bp with condition a == 10
 print /d $bpnum
 $1 = 1
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: get bpnum1
 break func if c == 30
-Note: breakpoint 1 also set at pc 0x40117c.
-Note: breakpoint 1 also set at pc 0x401170.
-Note: breakpoint 1 also set at pc 0x401164.
+Note: breakpoint 1 also set at pc 0x4011e8.
+Note: breakpoint 1 also set at pc 0x4011f8.
+Note: breakpoint 1 also set at pc 0x401208.
 warning: failed to validate condition at location 1, disabling:
   No symbol "c" in current context.
 warning: failed to validate condition at location 2, disabling:
   No symbol "c" in current context.
-Breakpoint 2 at 0x401164: func. (3 locations)
+Breakpoint 2 at 0x4011e8: func. (3 locations)
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: define bp with condition c == 30
 print /d $bpnum
 $2 = 2
@@ -73,20 +73,20 @@
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>         
 	stop only if a == 10
-1.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-1.2                         y   0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-1.3                         N*  0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+1.1                         y   0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+1.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+1.3                         N*  0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 2       breakpoint     keep y   <MULTIPLE>         
 	stop only if c == 30
-2.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         y   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         y   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
-(gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: info break 1
+(gdb) FAIL: gdb.base/condbreak-multi-context.exp: scenario 1: info break 1
 run 
 Starting program: /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context 
 
-Breakpoint 1, A::func (this=0x7fffffffcfd4) at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+Breakpoint 1, A::func (this=0x7fffffffcfc0) at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
 31	  void func () {}
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: run until A::func
 print a
@@ -95,7 +95,7 @@
 continue
 Continuing.
 
-Breakpoint 2, C::func (this=0x7fffffffcfcc) at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+Breakpoint 2, C::func (this=0x7fffffffcfb8) at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 39	  void func () {}
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: run until C::func
 print c
@@ -103,24 +103,24 @@
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: print c
 continue
 Continuing.
-[Inferior 1 (process 3757547) exited normally]
+[Inferior 1 (process 46941) exited normally]
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: continue until exit
 info break 1 2
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>         
 	stop only if a == 10
 	breakpoint already hit 1 time
-1.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-1.2                         y   0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-1.3                         N*  0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+1.1                         y   0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+1.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+1.3                         N*  0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 2       breakpoint     keep y   <MULTIPLE>         
 	stop only if c == 30
 	breakpoint already hit 1 time
-2.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         y   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         y   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
-(gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 1: info break 2
+(gdb) FAIL: gdb.base/condbreak-multi-context.exp: scenario 1: info break 2
 spawn /gdbtest/build/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /gdbtest/build/gdb/testsuite/../data-directory -iex set height 0 -iex set width 0 -ex set sysroot
 GNU gdb (GDB) 11.0.50.20201027-git
 Copyright (C) 2020 Free Software Foundation, Inc.
@@ -149,24 +149,24 @@
 (gdb) file /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context
 Reading symbols from /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context...
 (gdb) break func
-Breakpoint 1 at 0x401164: func. (3 locations)
+Breakpoint 1 at 0x4011e8: func. (3 locations)
 (gdb) print /d $bpnum
 $1 = 1
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: get bpnum1
 break func
-Note: breakpoint 1 also set at pc 0x40117c.
-Note: breakpoint 1 also set at pc 0x401170.
-Note: breakpoint 1 also set at pc 0x401164.
-Breakpoint 2 at 0x401164: func. (3 locations)
+Note: breakpoint 1 also set at pc 0x4011e8.
+Note: breakpoint 1 also set at pc 0x4011f8.
+Note: breakpoint 1 also set at pc 0x401208.
+Breakpoint 2 at 0x4011e8: func. (3 locations)
 (gdb) print /d $bpnum
 $2 = 2
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: get bpnum2
 cond 1 a == 10
-warning: failed to validate condition at location 1.1, disabling:
+warning: failed to validate condition at location 1.2, disabling:
   No symbol "a" in current context.
 warning: failed to validate condition at location 1.3, disabling:
   No symbol "a" in current context.
-(gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: cond 1 a == 10
+(gdb) FAIL: gdb.base/condbreak-multi-context.exp: scenario 2: cond 1 a == 10
 cond 2 c == 30
 warning: failed to validate condition at location 2.1, disabling:
   No symbol "c" in current context.
@@ -177,20 +177,20 @@
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>         
 	stop only if a == 10
-1.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-1.2                         y   0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-1.3                         N*  0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+1.1                         y   0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+1.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+1.3                         N*  0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 2       breakpoint     keep y   <MULTIPLE>         
 	stop only if c == 30
-2.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         y   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         y   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
-(gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: info break 1
+(gdb) FAIL: gdb.base/condbreak-multi-context.exp: scenario 2: info break 1
 run 
 Starting program: /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context 
 
-Breakpoint 1, A::func (this=0x7fffffffcfd4) at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+Breakpoint 1, A::func (this=0x7fffffffcfc0) at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
 31	  void func () {}
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: run until A::func
 print a
@@ -199,7 +199,7 @@
 continue
 Continuing.
 
-Breakpoint 2, C::func (this=0x7fffffffcfcc) at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+Breakpoint 2, C::func (this=0x7fffffffcfb8) at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 39	  void func () {}
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: run until C::func
 print c
@@ -207,24 +207,24 @@
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: print c
 continue
 Continuing.
-[Inferior 1 (process 3757794) exited normally]
+[Inferior 1 (process 47152) exited normally]
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: continue until exit
 info break 1 2
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>         
 	stop only if a == 10
 	breakpoint already hit 1 time
-1.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-1.2                         y   0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-1.3                         N*  0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+1.1                         y   0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+1.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+1.3                         N*  0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 2       breakpoint     keep y   <MULTIPLE>         
 	stop only if c == 30
 	breakpoint already hit 1 time
-2.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         y   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         y   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
-(gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 2: info break 2
+(gdb) FAIL: gdb.base/condbreak-multi-context.exp: scenario 2: info break 2
 spawn /gdbtest/build/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /gdbtest/build/gdb/testsuite/../data-directory -iex set height 0 -iex set width 0 -ex set sysroot
 GNU gdb (GDB) 11.0.50.20201027-git
 Copyright (C) 2020 Free Software Foundation, Inc.
@@ -253,24 +253,24 @@
 (gdb) file /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context
 Reading symbols from /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context...
 (gdb) break func
-Breakpoint 1 at 0x401164: func. (3 locations)
+Breakpoint 1 at 0x4011e8: func. (3 locations)
 (gdb) print /d $bpnum
 $1 = 1
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: get bpnum1
 break func
-Note: breakpoint 1 also set at pc 0x40117c.
-Note: breakpoint 1 also set at pc 0x401170.
-Note: breakpoint 1 also set at pc 0x401164.
-Breakpoint 2 at 0x401164: func. (3 locations)
+Note: breakpoint 1 also set at pc 0x4011e8.
+Note: breakpoint 1 also set at pc 0x4011f8.
+Note: breakpoint 1 also set at pc 0x401208.
+Breakpoint 2 at 0x4011e8: func. (3 locations)
 (gdb) print /d $bpnum
 $2 = 2
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: get bpnum2
 cond 1 a == 10
-warning: failed to validate condition at location 1.1, disabling:
+warning: failed to validate condition at location 1.2, disabling:
   No symbol "a" in current context.
 warning: failed to validate condition at location 1.3, disabling:
   No symbol "a" in current context.
-(gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: cond 1 a == 10
+(gdb) FAIL: gdb.base/condbreak-multi-context.exp: scenario 3: cond 1 a == 10
 cond 2 c == 30
 warning: failed to validate condition at location 2.1, disabling:
   No symbol "c" in current context.
@@ -288,9 +288,9 @@
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>         
 	stop only if c == 30
-1.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-1.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-1.3                         y   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+1.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+1.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+1.3                         y   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: check bp 1 after changing the condition
 cond 1
@@ -301,9 +301,9 @@
 info break 1
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>         
-1.1                         y   0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-1.2                         y   0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-1.3                         y   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+1.1                         y   0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+1.2                         y   0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+1.3                         y   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: check bp 1 after resetting the condition
 disable 2.2
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: disable 2.2
@@ -311,9 +311,9 @@
 Num     Type           Disp Enb Address            What
 2       breakpoint     keep y   <MULTIPLE>         
 	stop only if c == 30
-2.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         y   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         y   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: check bp 2 after disabling loc 2
 cond 2
@@ -323,18 +323,18 @@
 info break 2
 Num     Type           Disp Enb Address            What
 2       breakpoint     keep y   <MULTIPLE>         
-2.1                         y   0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         n   0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         y   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         y   0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         n   0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         y   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: check bp 2 loc 2 should remain disabled
 disable 2.3
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: disable 2.3
 info break 2
 Num     Type           Disp Enb Address            What
 2       breakpoint     keep y   <MULTIPLE>         
-2.1                         y   0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         n   0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         n   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         y   0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         n   0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         n   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: check bp 2 after disabling loc 3
 cond 2 c == 30
 warning: failed to validate condition at location 2.1, disabling:
@@ -344,9 +344,9 @@
 Num     Type           Disp Enb Address            What
 2       breakpoint     keep y   <MULTIPLE>         
 	stop only if c == 30
-2.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         n   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         n   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: check bp 2 loc 3 should remain disabled
 enable 2.1
@@ -356,9 +356,9 @@
 Num     Type           Disp Enb Address            What
 2       breakpoint     keep y   <MULTIPLE>         
 	stop only if c == 30
-2.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         n   0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         n   0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: check bp 2 after enable attempt
 cond 2 garbage
@@ -367,7 +367,7 @@
 delete 1
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: delete 1
 break main
-Breakpoint 3 at 0x40110e: file /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc, line 45.
+Breakpoint 3 at 0x40111f: file /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc, line 45.
 (gdb) run 
 Starting program: /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context 
 
@@ -376,7 +376,7 @@
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: start
 continue
 Continuing.
-[Inferior 1 (process 3758069) exited normally]
+[Inferior 1 (process 47358) exited normally]
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: scenario 3: continue until exit
 spawn /gdbtest/build/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /gdbtest/build/gdb/testsuite/../data-directory -iex set height 0 -iex set width 0 -ex set sysroot
 GNU gdb (GDB) 11.0.50.20201027-git
@@ -406,7 +406,7 @@
 (gdb) file /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context
 Reading symbols from /gdbtest/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context...
 (gdb) break func
-Breakpoint 1 at 0x401164: func. (3 locations)
+Breakpoint 1 at 0x4011e8: func. (3 locations)
 (gdb) print /d $bpnum
 $1 = 1
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: force: get bpnum1
@@ -422,22 +422,22 @@
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>         
 	stop only if foo
-1.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-1.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-1.3                         N*  0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+1.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+1.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+1.3                         N*  0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: force: check bp 1 after forcing the condition
 break func -force-condition if baz
-Note: breakpoint 1 also set at pc 0x40117c.
-Note: breakpoint 1 also set at pc 0x401170.
-Note: breakpoint 1 also set at pc 0x401164.
+Note: breakpoint 1 also set at pc 0x4011e8.
+Note: breakpoint 1 also set at pc 0x4011f8.
+Note: breakpoint 1 also set at pc 0x401208.
 warning: failed to validate condition at location 1, disabling:
   No symbol "baz" in current context.
 warning: failed to validate condition at location 2, disabling:
   No symbol "baz" in current context.
 warning: failed to validate condition at location 3, disabling:
   No symbol "baz" in current context.
-Breakpoint 2 at 0x401164: func. (3 locations)
+Breakpoint 2 at 0x4011e8: func. (3 locations)
 (gdb) print /d $bpnum
 $2 = 2
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: force: get bpnum2
@@ -445,16 +445,17 @@
 Num     Type           Disp Enb Address            What
 2       breakpoint     keep y   <MULTIPLE>         
 	stop only if baz
-2.1                         N*  0x0000000000401164 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
-2.2                         N*  0x0000000000401170 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
-2.3                         N*  0x000000000040117c in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
+2.1                         N*  0x00000000004011e8 in A::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31
+2.2                         N*  0x00000000004011f8 in Base::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23
+2.3                         N*  0x0000000000401208 in C::func() at /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39
 (*): Breakpoint condition is invalid at this location.
 (gdb) PASS: gdb.base/condbreak-multi-context.exp: force: check bp 2 set using the break command
-testcase /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.exp completed in 4 seconds
+testcase /gdbtest/src/gdb/testsuite/gdb.base/condbreak-multi-context.exp completed in 5 seconds
 
 		=== gdb Summary ===
 
-# of expected passes		49
+# of expected passes		42
+# of unexpected failures	7
 Executing on host: /gdbtest/build/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /gdbtest/build/gdb/testsuite/../data-directory -iex "set height 0" -iex "set width 0" --version    (timeout = 300)
 spawn -ignore SIGHUP /gdbtest/build/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /gdbtest/build/gdb/testsuite/../data-directory -iex set height 0 -iex set width 0 --version
 GNU gdb (GDB) 11.0.50.20201027-git
@@ -464,4 +465,4 @@
 There is NO WARRANTY, to the extent permitted by law.
 /gdbtest/build/gdb/gdb version  11.0.50.20201027-git -nw -nx -data-directory /gdbtest/build/gdb/testsuite/../data-directory -iex "set height 0" -iex "set width 0"  -ex "set sysroot"
 
-runtest completed at Wed Oct 28 15:42:08 2020
+runtest completed at Wed Oct 28 15:53:48 2020


^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts
  2020-10-28 16:57   ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Gary Benson
@ 2020-10-29  7:43     ` Aktemur, Tankut Baris
  0 siblings, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-10-29  7:43 UTC (permalink / raw)
  To: Gary Benson; +Cc: gdb-patches, simark

On Wednesday, October 28, 2020 5:57 PM, Gary Benson wrote:
> Hi Baris,
> 
> Tankut Baris Aktemur wrote:
> >  create mode 100644 gdb/testsuite/gdb.base/condbreak-multi-context.exp
> 
> This test fails if you build the test executable with Clang.  I've
> inlined a full diff of the gdb.log files below, but I think the
> issue is that Clang and GCC are writing the code or the debuginfo
> in a different order, so where the test expects to see breakpoints
> like:
> 
>   1.1 Base::func()
>   1.2 A::func()
>   1.3 C::func()
> 
> but what it gets with Clang is:
> 
>   1.1 A::func()
>   1.2 Base::func()
>   1.3 C::func()
> 
> Are you able to update the test to handle this?

Hi Gary,

Thanks for notifying.  Yes, I'll work on it.

-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-27 10:13         ` Aktemur, Tankut Baris
@ 2020-10-29 10:10           ` Tom de Vries
  2020-10-29 10:30             ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Tom de Vries @ 2020-10-29 10:10 UTC (permalink / raw)
  To: Aktemur, Tankut Baris, Simon Marchi, gdb-patches

On 10/27/20 11:13 AM, Aktemur, Tankut Baris via Gdb-patches wrote:
> On Monday, October 19, 2020 3:59 PM, Aktemur, Tankut Baris wrote:
>> On Saturday, October 17, 2020 12:46 AM, Simon Marchi wrote:
>>> I don't have time to review this in as much depth as I'd like, but I
>>> took a quick look at the code and tested the user experience, and it
>>> looks good to me.  If nobody else has anything to add in ~1 week from
>>> now, I'm fine with you merging this.
>>
>> Hi Simon,
>>
>> Thank you for your comments.  I'll wait for ~1 week as you suggest, and then merge
>> both patches.
> 
> I just pushed the patches.

Apparently, it just took me two days to start using this new feature.
Awesome :) !

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-29 10:10           ` Tom de Vries
@ 2020-10-29 10:30             ` Aktemur, Tankut Baris
  0 siblings, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-10-29 10:30 UTC (permalink / raw)
  To: Tom de Vries, Simon Marchi, gdb-patches

On Thursday, October 29, 2020 11:11 AM, Tom de Vries wrote:
> On 10/27/20 11:13 AM, Aktemur, Tankut Baris via Gdb-patches wrote:
> > On Monday, October 19, 2020 3:59 PM, Aktemur, Tankut Baris wrote:
> >> On Saturday, October 17, 2020 12:46 AM, Simon Marchi wrote:
> >>> I don't have time to review this in as much depth as I'd like, but I
> >>> took a quick look at the code and tested the user experience, and it
> >>> looks good to me.  If nobody else has anything to add in ~1 week from
> >>> now, I'm fine with you merging this.
> >>
> >> Hi Simon,
> >>
> >> Thank you for your comments.  I'll wait for ~1 week as you suggest, and then merge
> >> both patches.
> >
> > I just pushed the patches.
> 
> Apparently, it just took me two days to start using this new feature.
> Awesome :) !
> 
> Thanks,
> - Tom

I'm more than glad to hear that it's been useful to you.

-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-13 12:25   ` [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
  2020-10-13 15:08     ` Eli Zaretskii
  2020-10-16 22:45     ` Simon Marchi
@ 2020-10-29 17:30     ` Pedro Alves
  2020-11-10 19:33       ` Aktemur, Tankut Baris
  2020-11-10 19:51       ` Aktemur, Tankut Baris
  2 siblings, 2 replies; 103+ messages in thread
From: Pedro Alves @ 2020-10-29 17:30 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches; +Cc: simark

On 10/13/20 1:25 PM, Tankut Baris Aktemur via Gdb-patches wrote:
> @@ -9192,10 +9207,25 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
>        if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
>  	{
>  	  tok = cond_start = end_tok + 1;
> -	  parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
> +	  try
> +	    {
> +	      parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
> +	    }
> +	  catch (const gdb_exception_error &)
> +	    {
> +	      if (!force)
> +		throw;
> +	      else
> +		tok = tok + strlen (tok);
> +	    }
>  	  cond_end = tok;
>  	  *cond_string = savestring (cond_start, cond_end - cond_start);
>  	}
> +      else if (toklen >= 1 && strncmp (tok, "-force-condition", toklen) == 0)
> +	{
> +	  tok = cond_start = end_tok + 1;
> +	  force = true;
> +	}
>        else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
>  	{
>  	  const char *tmptok;

Is it important to handle "-force-condition" in this position, as opposed
to making it another option handled by string_to_explicit_location ?

As is, this doesn't work, for example:

 (gdb) b -function main -force<TAB>

nor does:

 (gdb) b -force-condition main if 0
 invalid explicit location argument, "-force-condition"

IMO, ideally all '-' options would be handled in the same place.

At some point, I think it would be nice to convert the
"break" command to use gdb::option, but it isn't trivial.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-29 17:30     ` Pedro Alves
@ 2020-11-10 19:33       ` Aktemur, Tankut Baris
  2020-12-05 17:30         ` Pedro Alves
  2020-11-10 19:51       ` Aktemur, Tankut Baris
  1 sibling, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-11-10 19:33 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches; +Cc: simark

On Thursday, October 29, 2020 6:30 PM, Pedro Alves wrote:
> On 10/13/20 1:25 PM, Tankut Baris Aktemur via Gdb-patches wrote:
> > @@ -9192,10 +9207,25 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
> >        if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
> >  	{
> >  	  tok = cond_start = end_tok + 1;
> > -	  parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
> > +	  try
> > +	    {
> > +	      parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
> > +	    }
> > +	  catch (const gdb_exception_error &)
> > +	    {
> > +	      if (!force)
> > +		throw;
> > +	      else
> > +		tok = tok + strlen (tok);
> > +	    }
> >  	  cond_end = tok;
> >  	  *cond_string = savestring (cond_start, cond_end - cond_start);
> >  	}
> > +      else if (toklen >= 1 && strncmp (tok, "-force-condition", toklen) == 0)
> > +	{
> > +	  tok = cond_start = end_tok + 1;
> > +	  force = true;
> > +	}
> >        else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
> >  	{
> >  	  const char *tmptok;
> 
> Is it important to handle "-force-condition" in this position, as opposed
> to making it another option handled by string_to_explicit_location ?

I have mixed feelings about this.  On one hand, it feels more natural to me that
"-force-condition" belongs to the keywords group (i.e. 'thread', 'task', 'if')
because it's about defining the condition rather than the location.  On the other
hand, I agree that having it start with "-" gives it a flexible option feeling.
We could handle "-force-condition" like an option, but then this would not work:

  (gdb) break main thread 1 -force-condition if foo

Once we start typing keywords (in this case, 'thread'), no more options are expected.
Perhaps making "thread" and "task" also start with "-" and converting them to an
option would improve consistency and flexibility.

> As is, this doesn't work, for example:
> 
>  (gdb) b -function main -force<TAB>

This is a bug.  I propose a patch to fix it.  Please see below.

> 
> nor does:
> 
>  (gdb) b -force-condition main if 0
>  invalid explicit location argument, "-force-condition"

Based on the current implementation, this is expected because 
'-force-condition' is considered a keyword.

> IMO, ideally all '-' options would be handled in the same place.

Like I wrote above, this is a trade-off.  It gives more flexibility but also
brings some limitations.
 
> At some point, I think it would be nice to convert the
> "break" command to use gdb::option, but it isn't trivial.

Converting all keywords except "if" (currently "thread", "task", and "-force-condition")
to '-' options is IMHO a sweet-spot solution here.  It's likely to be easier than
gdb::option, but also improves positional flexibility.  However, backwards compatibility
would be a bit of pain.

Thanks.
-Baris


From 35c23da750cb4aa7fa6a6e1919a180fb13901fda Mon Sep 17 00:00:00 2001
From: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Date: Tue, 10 Nov 2020 16:09:15 +0100
Subject: [PATCH] gdb/completer: improve tab completion to consider the
 '-force-condition' flag

The commit

  commit 733d554a4625db4ffb89b7a20e1cf27ab071ef4d
  Author: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
  Date:   Tue Oct 27 10:56:03 2020 +0100

  gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition

introduced the '-force-condition' flag to the 'break' command.  This
flag was defined as a keyword like 'thread', 'task', and 'if'.
However, it starts with '-'.  This difference caused an uncovered case
when tab-completing a seemingly complete linespec.

Below, we see "-force-condition" in the completion list, where both
the options and the keywords are listed:

  (gdb) break -function main <TAB>
  -force-condition  -function  -label  -line  -qualified
  -source           if         task    thread

But tab-completing '-' lists only options:

  (gdb) break -function main -<TAB>
  -function   -label      -line       -qualified  -source

This patch fixes the problem by adding keywords to the completion
list, so that we see:

  (gdb) break -function main -<TAB>
  -force-condition  -function  -label  -line  -qualified  -source

gdb/ChangeLog:
2020-11-10  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* completer.c (complete_explicit_location): Also add keywords
	that start with '-' to the completion list.

gdb/testsuite/ChangeLog:
2020-11-10  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.linespec/explicit.exp: Extend with a test to check completing
	'-' after seemingly complete options.
---
 gdb/completer.c                         |  6 +++++-
 gdb/testsuite/gdb.linespec/explicit.exp | 14 ++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/gdb/completer.c b/gdb/completer.c
index 262c8556bf6..cf8c14e7828 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -892,7 +892,11 @@ complete_explicit_location (completion_tracker &tracker,
   int keyword = skip_keyword (tracker, explicit_options, &text);
 
   if (keyword == -1)
-    complete_on_enum (tracker, explicit_options, text, text);
+    {
+      complete_on_enum (tracker, explicit_options, text, text);
+      /* There are keywords that start with "-".   Include them, too.  */
+      complete_on_enum (tracker, linespec_keywords, text, text);
+    }
   else
     {
       /* Completing on value.  */
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
index 52a1fce5371..c33ab505e34 100644
--- a/gdb/testsuite/gdb.linespec/explicit.exp
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -469,6 +469,20 @@ namespace eval $testfile {
 	    }
 	}
 
+	# Test that after a seemingly finished option argument,
+	# completion for "-" matches both the explicit location
+	# options and the linespec keywords that start with "-".
+	with_test_prefix "complete '-' after options" {
+	    test_gdb_complete_multiple "b -function myfunction " "-" "" {
+		"-force-condition"
+		"-function"
+		"-label"
+		"-line"
+		"-qualified"
+		"-source"
+	    }
+	}
+
 	# Tests that ensure that after "if" we complete on expressions
 	# are in cpcompletion.exp.
 
-- 
2.17.1

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-10-29 17:30     ` Pedro Alves
  2020-11-10 19:33       ` Aktemur, Tankut Baris
@ 2020-11-10 19:51       ` Aktemur, Tankut Baris
  1 sibling, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-11-10 19:51 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches; +Cc: simark

On Thursday, October 29, 2020 6:30 PM, Pedro Alves wrote:
> On 10/13/20 1:25 PM, Tankut Baris Aktemur via Gdb-patches wrote:
> > @@ -9192,10 +9207,25 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
> >        if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
> >  	{
> >  	  tok = cond_start = end_tok + 1;
> > -	  parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
> > +	  try
> > +	    {
> > +	      parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
> > +	    }
> > +	  catch (const gdb_exception_error &)
> > +	    {
> > +	      if (!force)
> > +		throw;
> > +	      else
> > +		tok = tok + strlen (tok);
> > +	    }
> >  	  cond_end = tok;
> >  	  *cond_string = savestring (cond_start, cond_end - cond_start);
> >  	}
> > +      else if (toklen >= 1 && strncmp (tok, "-force-condition", toklen) == 0)
> > +	{
> > +	  tok = cond_start = end_tok + 1;
> > +	  force = true;
> > +	}
> >        else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
> >  	{
> >  	  const char *tmptok;
> 
> Is it important to handle "-force-condition" in this position, as opposed
> to making it another option handled by string_to_explicit_location ?
> 
> As is, this doesn't work, for example:
> 
>  (gdb) b -function main -force<TAB>
> 
> nor does:
> 
>  (gdb) b -force-condition main if 0
>  invalid explicit location argument, "-force-condition"

There is another case where it doesn't work:

  (gdb) break main -force-condition thread 1 if foo
  Function "main -force-condition" not defined.
  Make breakpoint pending on future shared library load? (y or [n])

This is because the commit required "-force-condition" to always be followed
by an "if".  It seems unnecessarily restrictive.  I'll submit a patch to relax
the requirement.

Regards
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-11-10 19:33       ` Aktemur, Tankut Baris
@ 2020-12-05 17:30         ` Pedro Alves
  2020-12-10 20:30           ` Tom Tromey
  0 siblings, 1 reply; 103+ messages in thread
From: Pedro Alves @ 2020-12-05 17:30 UTC (permalink / raw)
  To: Aktemur, Tankut Baris, gdb-patches; +Cc: simark

Hi Tankut,

Sorry for the delay.

On 11/10/20 7:33 PM, Aktemur, Tankut Baris wrote:
> On Thursday, October 29, 2020 6:30 PM, Pedro Alves wrote:
>> On 10/13/20 1:25 PM, Tankut Baris Aktemur via Gdb-patches wrote:
>>> @@ -9192,10 +9207,25 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
>>>        if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
>>>  	{
>>>  	  tok = cond_start = end_tok + 1;
>>> -	  parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
>>> +	  try
>>> +	    {
>>> +	      parse_exp_1 (&tok, pc, block_for_pc (pc), 0);
>>> +	    }
>>> +	  catch (const gdb_exception_error &)
>>> +	    {
>>> +	      if (!force)
>>> +		throw;
>>> +	      else
>>> +		tok = tok + strlen (tok);
>>> +	    }
>>>  	  cond_end = tok;
>>>  	  *cond_string = savestring (cond_start, cond_end - cond_start);
>>>  	}
>>> +      else if (toklen >= 1 && strncmp (tok, "-force-condition", toklen) == 0)
>>> +	{
>>> +	  tok = cond_start = end_tok + 1;
>>> +	  force = true;
>>> +	}
>>>        else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
>>>  	{
>>>  	  const char *tmptok;
>>
>> Is it important to handle "-force-condition" in this position, as opposed
>> to making it another option handled by string_to_explicit_location ?
> 
> I have mixed feelings about this.  On one hand, it feels more natural to me that
> "-force-condition" belongs to the keywords group (i.e. 'thread', 'task', 'if')
> because it's about defining the condition rather than the location.  On the other
> hand, I agree that having it start with "-" gives it a flexible option feeling.
> We could handle "-force-condition" like an option, but then this would not work:
> 
>   (gdb) break main thread 1 -force-condition if foo
> 
> Once we start typing keywords (in this case, 'thread'), no more options are expected.
> Perhaps making "thread" and "task" also start with "-" and converting them to an
> option would improve consistency and flexibility.

Calling "-force-condition" a keyword is a real stretch, IMO.  For all
intents and purposes, it's a flag, like "-qualified" is.  Why wouldn't
one be able to write:

  (gdb) break -force-condition main thread 1 if foo

With that, a user could do:

  (gdb) alias bf = break -force-condition
  (gdb) bf if foo

But it doesn't work:

  (gdb) bf main
  No default breakpoint address now.

... because GDB is parsing that as if the user has typed:

  (gdb) b if main
  No default breakpoint address now.


Also, I find it hard to justify that this works:

 (gdb) break main -force-condition if foo

while this doesn't:

 (gdb) break main -qualified


So IMO, the feature is misdesigned -- "-force-condition" should
be an option just like "-qualified" is, and then if you want to
handle "-force-condition" after the linespec, then really all
options should be handled in that position.

Note also that this doesn't work:

 (gdb) b main -force-condit if 0
 Function "main -force-condit" not defined.
 Make breakpoint pending on future shared library load? (y or [n]) 

... which is yet another inconsistency compared to other flags,
which can be abbreviated as long as unambiguous:

 (gdb) b -qual main


Anyhow, the patch is in, and I'm not going to ask to revert it.  Onward.

> 
>> As is, this doesn't work, for example:
>>
>>  (gdb) b -function main -force<TAB>
> 
> This is a bug.  I propose a patch to fix it.  Please see below.
> 
>>
>> nor does:
>>
>>  (gdb) b -force-condition main if 0
>>  invalid explicit location argument, "-force-condition"
> 
> Based on the current implementation, this is expected because 
> '-force-condition' is considered a keyword.
> 
>> IMO, ideally all '-' options would be handled in the same place.
> 
> Like I wrote above, this is a trade-off.  It gives more flexibility but also
> brings some limitations.
>  
>> At some point, I think it would be nice to convert the
>> "break" command to use gdb::option, but it isn't trivial.
> 
> Converting all keywords except "if" (currently "thread", "task", and "-force-condition")
> to '-' options is IMHO a sweet-spot solution here.  It's likely to be easier than
> gdb::option, but also improves positional flexibility.  However, backwards compatibility
> would be a bit of pain.

Breaking backwards compatibility here would be bad.  But there's no real need for
that.  We would instead handle all options in the spot where we handle
the keywords.

> 
> Thanks.
> -Baris
> 
> 
> From 35c23da750cb4aa7fa6a6e1919a180fb13901fda Mon Sep 17 00:00:00 2001
> From: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
> Date: Tue, 10 Nov 2020 16:09:15 +0100
> Subject: [PATCH] gdb/completer: improve tab completion to consider the
>  '-force-condition' flag
> 
> The commit
> 
>   commit 733d554a4625db4ffb89b7a20e1cf27ab071ef4d
>   Author: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
>   Date:   Tue Oct 27 10:56:03 2020 +0100
> 
>   gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
> 
> introduced the '-force-condition' flag to the 'break' command.  This
> flag was defined as a keyword like 'thread', 'task', and 'if'.
> However, it starts with '-'.  This difference caused an uncovered case
> when tab-completing a seemingly complete linespec.
> 
> Below, we see "-force-condition" in the completion list, where both
> the options and the keywords are listed:
> 
>   (gdb) break -function main <TAB>
>   -force-condition  -function  -label  -line  -qualified
>   -source           if         task    thread
> 
> But tab-completing '-' lists only options:
> 
>   (gdb) break -function main -<TAB>
>   -function   -label      -line       -qualified  -source
> 
> This patch fixes the problem by adding keywords to the completion
> list, so that we see:
> 
>   (gdb) break -function main -<TAB>
>   -force-condition  -function  -label  -line  -qualified  -source
> 
> gdb/ChangeLog:
> 2020-11-10  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* completer.c (complete_explicit_location): Also add keywords
> 	that start with '-' to the completion list.
> 
> gdb/testsuite/ChangeLog:
> 2020-11-10  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.linespec/explicit.exp: Extend with a test to check completing
> 	'-' after seemingly complete options.

OK.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-12-05 17:30         ` Pedro Alves
@ 2020-12-10 20:30           ` Tom Tromey
  2020-12-15 11:20             ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Tom Tromey @ 2020-12-10 20:30 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Aktemur, Tankut Baris, gdb-patches, simark

>>>>> "Pedro" == Pedro Alves <pedro@palves.net> writes:

Pedro> Also, I find it hard to justify that this works:

Pedro>  (gdb) break main -force-condition if foo

Pedro> while this doesn't:

Pedro>  (gdb) break main -qualified

I wasn't really paying attention to this, but adding suffixes to
linespecs is generally a problem.  For example this will also mis-parse,
I think, if one uses the '*' form:

    break *whatever -force-condition

since this will parse as subtraction operators.

That is, adding a suffix ordinarily requires updating all the parsers
(really the lexers).  Option-style prefixes are better for this reason.

Pedro> Anyhow, the patch is in, and I'm not going to ask to revert it.  Onward.

IMO it should be fixed for the future.

Tom

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition
  2020-12-10 20:30           ` Tom Tromey
@ 2020-12-15 11:20             ` Aktemur, Tankut Baris
  0 siblings, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2020-12-15 11:20 UTC (permalink / raw)
  To: Tom Tromey, Pedro Alves; +Cc: gdb-patches, simark

On Thursday, December 10, 2020 9:30 PM, Tom Tromey wrote:
> >>>>> "Pedro" == Pedro Alves <pedro@palves.net> writes:
> 
> Pedro> Also, I find it hard to justify that this works:
> 
> Pedro>  (gdb) break main -force-condition if foo
> 
> Pedro> while this doesn't:
> 
> Pedro>  (gdb) break main -qualified
> 
> I wasn't really paying attention to this, but adding suffixes to
> linespecs is generally a problem.  For example this will also mis-parse,
> I think, if one uses the '*' form:
> 
>     break *whatever -force-condition
> 
> since this will parse as subtraction operators.
> 
> That is, adding a suffix ordinarily requires updating all the parsers
> (really the lexers).  Option-style prefixes are better for this reason.
> 
> Pedro> Anyhow, the patch is in, and I'm not going to ask to revert it.  Onward.
> 
> IMO it should be fixed for the future.

I'll investigate how this can be fixed, but please expect delays.

Thanks
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 0/2] Breakpoint conditions at locations with differing contexts
  2020-07-31 15:42 [PATCH 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
                   ` (3 preceding siblings ...)
  2020-10-13 12:25 ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
@ 2021-04-05 17:45 ` Jonah Graham
  2021-04-06 14:11   ` Aktemur, Tankut Baris
                     ` (2 more replies)
  4 siblings, 3 replies; 103+ messages in thread
From: Jonah Graham @ 2021-04-05 17:45 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

On Fri, 31 Jul 2020 at 11:42, Tankut Baris Aktemur via Gdb-patches <
gdb-patches@sourceware.org> wrote:

> This is a short series about conditional breakpoints where the
> condition may be invalid at some breakpoint locations because of their
> context.
>

Hi Tankut,

I have been testing GDB master against current Eclipse CDT and I came
across this change. I have some work in Eclipse CDT to display this
information to the user which I am tracking in
https://bugs.eclipse.org/bugs/show_bug.cgi?id=572589. Thanks for the new
GDB feature!

1. The problem I am having is that I want to display the "Breakpoint
condition is invalid at this location" type info in the UI, but I can't see
if there is any from MI to identify this information. Here is a trace that
causes me a problem:

$ ./gdb --interpreter=mi2 --quiet
=thread-group-added,id="i1"
(gdb)
18-file-exec-and-symbols --thread-group i1
/scratch/eclipse/src/cdt/runtime-CDT/bug572589/Debug/bug572589
18^done
(gdb)
26-break-insert -c "invalid condition here" -f main
&"warning: failed to validate condition at location 1, disabling:\n  "
&"No symbol \"invalid\" in current context.\n"
26^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="invalid
condition
here",times="0",original-location="main"},{number="1.1",enabled="N*",addr="0x0000000000001160",func="main",file="../src/bug572589.c",fullname="/scratch/eclipse/src/cdt/runtime-CDT/bug572589/src/bug572589.c",line="20",thread-groups=["i1"]}
(gdb)
info break
&"info break\n"
~"Num     Type           Disp Enb Address            What\n"
~"1       breakpoint     keep y   <MULTIPLE>         \n"
~"\tstop only if invalid condition here\n"
~"1.1                         N*  0x0000000000001160 in main at
../src/bug572589.c:20\n"
~"(*): Breakpoint condition is invalid at this location.\n"
^done
(gdb)
42-break-list
42^done,BreakpointTable={nr_rows="1",nr_cols="6",hdr=[{width="7",alignment="-1",col_name="number",colhdr="Num"},{width="14",alignment="-1",col_name="type",colhdr="Type"},{width="4",alignment="-1",col_name="disp",colhdr="Disp"},{width="3",alignment="-1",col_name="enabled",colhdr="Enb"},{width="18",alignment="-1",col_name="addr",colhdr="Address"},{width="40",alignment="2",col_name="what",colhdr="What"}],body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="invalid
condition
here",times="0",original-location="main"},{number="1.1",enabled="N*",addr="0x0000000000001160",func="main",file="../src/bug572589.c",fullname="/scratch/eclipse/src/cdt/runtime-CDT/bug572589/src/bug572589.c",line="20",thread-groups=["i1"]}]}
(gdb)

Is the enabled="N*" what CDT can use to know that?
https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI-Breakpoint-Commands.html#GDB_002fMI-Breakpoint-Commands
shows that enabled can be y or n (lowercase). If this is the way to
identify the invalid condition, can this be documented explicitly in the
docs? Can the warning string be part of the breakpoint structure returned
in MI?


2. The other problem is I want to enable the -force-condition in the UI,
but AFAICT that isn't supported from MI? If it is, I couldn't figure out
the invocation that worked.

Any guidance you can provide is most welcome.

Thanks,
Jonah

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH 0/2] Breakpoint conditions at locations with differing contexts
  2021-04-05 17:45 ` [PATCH " Jonah Graham
@ 2021-04-06 14:11   ` Aktemur, Tankut Baris
  2021-04-06 14:37     ` Jonah Graham
  2021-04-07 14:55   ` [PATCH 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  2021-04-07 21:24   ` [PATCH 0/2] Breakpoint conditions at locations with differing contexts Simon Marchi
  2 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-06 14:11 UTC (permalink / raw)
  To: Jonah Graham; +Cc: gdb-patches

On Monday, April 5, 2021 7:46 PM, Jonah Graham wrote:
> On Fri, 31 Jul 2020 at 11:42, Tankut Baris Aktemur via Gdb-patches <mailto:gdb-patches@sourceware.org> wrote:
> > This is a short series about conditional breakpoints where the
> > condition may be invalid at some breakpoint locations because of their
> > context.
>
> Hi Tankut,
>
> I have been testing GDB master against current Eclipse CDT and I came across this change. I have some work in Eclipse CDT to display this information to the user which I am tracking in https://bugs.eclipse.org/bugs/show_bug.cgi?id=572589. Thanks for the new GDB feature!

Hi Jonah,

Thanks for the feedback and reporting this issue.

> 1. The problem I am having is that I want to display the "Breakpoint condition is invalid at this location" type info in the UI, but I can't see if there is any from MI to identify this information. Here is a trace that causes me a problem:
>
> $ ./gdb --interpreter=mi2 --quiet
> =thread-group-added,id="i1"
> (gdb)
> 18-file-exec-and-symbols --thread-group i1 /scratch/eclipse/src/cdt/runtime-CDT/bug572589/Debug/bug572589
> 18^done
> (gdb)
> 26-break-insert -c "invalid condition here" -f main
> &"warning: failed to validate condition at location 1, disabling:\n  "
> &"No symbol \"invalid\" in current context.\n"
> 26^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="invalid condition here",times="0",original-location="main"},{number="1.1",enabled="N*",addr="0x0000000000001160",func="main",file="../src/bug572589.c",fullname="/scratch/eclipse/src/cdt/runtime-CDT/bug572589/src/bug572589.c",line="20",thread-groups=["i1"]}

This is an oversight.  The expected behavior is that the breakpoint
is rejected here, because at no location the condition is valid and
the condition is not being explicitly forced.
So, the expected behavior is

(gdb)
-break-insert -c "invalid condition here" -f main
^error,msg="No symbol \"invalid\" in current context."

I'll submit a patch to fix it.

> (gdb)
> info break
> &"info break\n"
> ~"Num     Type           Disp Enb Address            What\n"
> ~"1       breakpoint     keep y   <MULTIPLE>         \n"
> ~"\tstop only if invalid condition here\n"
> ~"1.1                         N*  0x0000000000001160 in main at ../src/bug572589.c:20\n"
> ~"(*): Breakpoint condition is invalid at this location.\n"
> ^done
> (gdb)
> 42-break-list
> 42^done,BreakpointTable={nr_rows="1",nr_cols="6",hdr=[{width="7",alignment="-1",col_name="number",colhdr="Num"},{width="14",alignment="-1",col_name="type",colhdr="Type"},{width="4",alignment="-1",col_name="disp",colhdr="Disp"},{width="3",alignment="-1",col_name="enabled",colhdr="Enb"},{width="18",alignment="-1",col_name="addr",colhdr="Address"},{width="40",alignment="2",col_name="what",colhdr="What"}],body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="invalid condition here",times="0",original-location="main"},{number="1.1",enabled="N*",addr="0x0000000000001160",func="main",file="../src/bug572589.c",fullname="/scratch/eclipse/src/cdt/runtime-CDT/bug572589/src/bug572589.c",line="20",thread-groups=["i1"]}]}
> (gdb)
>
> Is the enabled="N*" what CDT can use to know that? https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI-Breakpoint-Commands.html#GDB_002fMI-Breakpoint-Commands shows that enabled can be y or n (lowercase). If this is the way to identify the invalid condition, can this be documented explicitly in the docs?

"N*" is the third possible value and it means "disabled because the
condition is invalid at the location".  I'll also submit a patch to
update the doc.

> Can the warning string be part of the breakpoint structure returned in MI?

Are you referring to the "warning: failed to validate condition
at location 1, disabling:" string?  I'm not sure it should be a part
of the breakpoint structure.  Wouldn't the 'N*' value suffice to give
the necessary information?

>
> 2. The other problem is I want to enable the -force-condition in the UI, but AFAICT that isn't supported from MI? If it is, I couldn't figure out the invocation that worked.

This flag does not exist.  I'll submit a patch to recognize it in
the MI command.

>
> Any guidance you can provide is most welcome.
>
> Thanks,
> Jonah

Thanks.
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 0/2] Breakpoint conditions at locations with differing contexts
  2021-04-06 14:11   ` Aktemur, Tankut Baris
@ 2021-04-06 14:37     ` Jonah Graham
  2021-04-07  7:09       ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Jonah Graham @ 2021-04-06 14:37 UTC (permalink / raw)
  To: Aktemur, Tankut Baris; +Cc: gdb-patches

On Tue, 6 Apr 2021 at 10:11, Aktemur, Tankut Baris <
tankut.baris.aktemur@intel.com> wrote:

> Hi Jonah,
>

Hi Baris,


>
> Thanks for the feedback and reporting this issue.
>

Thanks for implementing it :-)


> I'll submit a patch to fix it.
>

Great. AFAICT -break-insert with a condition included always acts as if
-force-condition was included. i.e. "break method -force-condition if
symbol" is equivalent to "26-break-insert -c symbol -f method"


>
> "N*" is the third possible value and it means "disabled because the
> condition is invalid at the location".  I'll also submit a patch to
> update the doc.
>

Great.


>
> > Can the warning string be part of the breakpoint structure returned in
> MI?
>
> Are you referring to the "warning: failed to validate condition
> at location 1, disabling:" string?  I'm not sure it should be a part
> of the breakpoint structure.  Wouldn't the 'N*' value suffice to give
> the necessary information?
>

It is sufficient. I assume therefore that "N*" in a reply to break-insert
always means "warning: failed to validate condition
at location 1, disabling:" (What does the "1" refer to? IIUC it is the ".1"
in the breakpoint number?).

In the breakpoint table N* always means "Breakpoint condition is invalid at
this location" and that the breakpoint is disabled?


> >
> > 2. The other problem is I want to enable the -force-condition in the UI,
> but AFAICT that isn't supported from MI? If it is, I couldn't figure out
> the invocation that worked.
>
> This flag does not exist.  I'll submit a patch to recognize it in
> the MI command.
>

Great.



>
> >
> > Any guidance you can provide is most welcome.
> >
> > Thanks,
> > Jonah
>
> Thanks.
> -Baris
>

Thanks again,
Jonah

>
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH 0/2] Breakpoint conditions at locations with differing contexts
  2021-04-06 14:37     ` Jonah Graham
@ 2021-04-07  7:09       ` Aktemur, Tankut Baris
  2021-04-07 11:26         ` Jonah Graham
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-07  7:09 UTC (permalink / raw)
  To: Jonah Graham; +Cc: gdb-patches

Hi Jonah,

On Tuesday, April 6, 2021 4:37 PM, Jonah Graham wrote:
> Great. AFAICT -break-insert with a condition included always acts as if -force-condition was included. i.e. "break method -force-condition if symbol" is equivalent to "26-break-insert -c symbol -f method" 
 
Yes, this is the current behavior but it's unintentional.
I'm preparing a patch to fix this.

> I assume therefore that "N*" in a reply to break-insert always means "warning: failed to validate condition
at location 1, disabling:" (What does the "1" refer to? IIUC it is the ".1" in the breakpoint number?).

Yes and yes.  A breakpoint may have multiple locations.  The "1" here refers
to the location number; i.e.  the ".1" suffix in the breakpoint location number.

> In the breakpoint table N* always means "Breakpoint condition is invalid at this location" and that the breakpoint is disabled?

Only the particular location is disabled.  There may be other
locations that are still enabled (y) or disabled by the user (n).
Also note that "N*" may appear in the table for a location only,
not the breakpoint itself.

Regards.
-Baris



Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 0/2] Breakpoint conditions at locations with differing contexts
  2021-04-07  7:09       ` Aktemur, Tankut Baris
@ 2021-04-07 11:26         ` Jonah Graham
  0 siblings, 0 replies; 103+ messages in thread
From: Jonah Graham @ 2021-04-07 11:26 UTC (permalink / raw)
  To: Aktemur, Tankut Baris; +Cc: gdb-patches

 <http://www.kichwacoders.com>


On Wed, 7 Apr 2021 at 03:09, Aktemur, Tankut Baris <
tankut.baris.aktemur@intel.com> wrote:

> Hi Jonah,
>
> On Tuesday, April 6, 2021 4:37 PM, Jonah Graham wrote:
> > Great. AFAICT -break-insert with a condition included always acts as if
> -force-condition was included. i.e. "break method -force-condition if
> symbol" is equivalent to "26-break-insert -c symbol -f method"
>
> Yes, this is the current behavior but it's unintentional.
> I'm preparing a patch to fix this.
>
> > I assume therefore that "N*" in a reply to break-insert always means
> "warning: failed to validate condition
> at location 1, disabling:" (What does the "1" refer to? IIUC it is the
> ".1" in the breakpoint number?).
>
> Yes and yes.  A breakpoint may have multiple locations.  The "1" here
> refers
> to the location number; i.e.  the ".1" suffix in the breakpoint location
> number.
>
> > In the breakpoint table N* always means "Breakpoint condition is invalid
> at this location" and that the breakpoint is disabled?
>
> Only the particular location is disabled.  There may be other
> locations that are still enabled (y) or disabled by the user (n).
> Also note that "N*" may appear in the table for a location only,
> not the breakpoint itself.
>

Thank you Baris. All that makes sense.


>
> Regards.
> -Baris
>
>
Regards,
Jonah

~~~
Jonah Graham
Kichwa Coders
www.kichwacoders.com

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH 0/4] Multi-context invalid breakpoint conditions and MI
  2021-04-05 17:45 ` [PATCH " Jonah Graham
  2021-04-06 14:11   ` Aktemur, Tankut Baris
@ 2021-04-07 14:55   ` Tankut Baris Aktemur
  2021-04-07 14:55     ` [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI Tankut Baris Aktemur
                       ` (4 more replies)
  2021-04-07 21:24   ` [PATCH 0/2] Breakpoint conditions at locations with differing contexts Simon Marchi
  2 siblings, 5 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-07 14:55 UTC (permalink / raw)
  To: gdb-patches

Hi,

The starting point of this series is Jonah Graham's report at

  https://sourceware.org/pipermail/gdb-patches/2021-April/177498.html

When a bad breakpoint condition is used, the MI command
'-break-insert' inserts the breakpoint by disabling the breakpoint
locations.  This does not match the default CLI behavior, where the
breakpoint would be rejected unless the user explicitly uses the
'-force-condition' flag.  This series attempts to fix the problem and
align the MI behavior with CLI, together with some documentation
update.

Thanks
Baris


Tankut Baris Aktemur (4):
  gdb/doc: update the 'enabled' field's description for BP locations in
    MI
  testsuite, gdb.mi: fix duplicate test names in mi-break.exp
  gdb/breakpoint: add a 'force_condition' parameter to
    'create_breakpoint'
  gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the
    condition

 gdb/NEWS                          |  7 ++++++
 gdb/breakpoint.c                  | 40 ++++++++++++++++++++++++++-----
 gdb/breakpoint.h                  |  6 +++++
 gdb/doc/gdb.texinfo               | 21 +++++++++++-----
 gdb/guile/scm-breakpoint.c        |  2 +-
 gdb/mi/mi-cmd-break.c             |  9 ++++++-
 gdb/python/py-breakpoint.c        |  2 +-
 gdb/python/py-finishbreakpoint.c  |  2 +-
 gdb/testsuite/gdb.mi/mi-break.exp | 39 ++++++++++++++++++++++++++----
 9 files changed, 108 insertions(+), 20 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI
  2021-04-07 14:55   ` [PATCH 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
@ 2021-04-07 14:55     ` Tankut Baris Aktemur
  2021-04-07 15:15       ` Eli Zaretskii
  2021-04-07 21:42       ` Simon Marchi
  2021-04-07 14:55     ` [PATCH 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
                       ` (3 subsequent siblings)
  4 siblings, 2 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-07 14:55 UTC (permalink / raw)
  To: gdb-patches

Update the document to mention the "N*" value for the 'enabled' field
of breakpoint locations.  Also remove the line about the 'enable'
field, because there is no such field for locations.

gdb/doc/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (GDB/MI Breakpoint Information): Update the
	description for the 'enabled' field of breakpoint locations.
---
 gdb/doc/gdb.texinfo | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7dbffb65d53..bfac2b6d245 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30048,8 +30048,9 @@ location within that breakpoint.
 
 @item enabled
 This indicates whether the location is enabled, in which case the
-value is @samp{y}, or disabled, in which case the value is @samp{n}.
-Note that this is not the same as the field @code{enable}.
+value is @samp{y}, or disabled by the user, in which case the value
+is @samp{n}, or disabled because the breakpoint condition is invalid
+at this location, in which case the value is @samp{N*}.
 
 @item addr
 The address of this location as an hexidecimal number.
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp
  2021-04-07 14:55   ` [PATCH 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  2021-04-07 14:55     ` [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI Tankut Baris Aktemur
@ 2021-04-07 14:55     ` Tankut Baris Aktemur
  2021-04-07 21:49       ` Simon Marchi
  2021-04-07 14:55     ` [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-07 14:55 UTC (permalink / raw)
  To: gdb-patches

gdb/testsuite/ChangeLog:
2021-04-07  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp: Fix the duplicate test names.
---
 gdb/testsuite/gdb.mi/mi-break.exp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index a7c37b365e9..9d3d7ade6dc 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -93,7 +93,7 @@ proc test_tbreak_creation_and_listing {} {
 
     mi_gdb_test "777-break-delete" \
 	    "777\\^done" \
-	    "delete temp breakpoints"
+	    "delete tbreak temp breakpoints"
 }
 
 proc test_rbreak_creation_and_listing {} {
@@ -162,7 +162,7 @@ proc test_rbreak_creation_and_listing {} {
 
     mi_gdb_test "177-break-delete" \
 	    "177\\^done" \
-	    "delete temp breakpoints"
+	    "delete rbreak temp breakpoints"
 }
 
 proc test_abreak_creation {} {
@@ -281,7 +281,7 @@ proc test_breakpoint_commands {} {
 
     mi_gdb_test "-break-commands 9 \"bt\" \"set \$i=0\" \"while \$i<10\" \"print \$i\" \"set \$i=\$i+1\" \"end\" \"continue\" " \
         "\\^done" \
-        "breakpoint commands: set commands"
+        "breakpoint commands: set more commands"
 
     mi_send_resuming_command "exec-continue" "breakpoint commands: continue"
 
@@ -365,7 +365,7 @@ proc test_explicit_breakpoints {} {
 
     mi_gdb_test "-break-delete" \
 	    "\\^done" \
-	    "delete temp breakpoints"
+	    "delete explicit temp breakpoints"
 
     mi_create_breakpoint "-c \"intarg == 3\" --function callee2" \
 	"insert explicit conditional breakpoint in callee2" \
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-07 14:55   ` [PATCH 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  2021-04-07 14:55     ` [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI Tankut Baris Aktemur
  2021-04-07 14:55     ` [PATCH 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
@ 2021-04-07 14:55     ` Tankut Baris Aktemur
  2021-04-07 22:08       ` Simon Marchi
  2021-04-07 14:55     ` [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition Tankut Baris Aktemur
  2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  4 siblings, 1 reply; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-07 14:55 UTC (permalink / raw)
  To: gdb-patches

The 'create_breakpoint' function takes a 'parse_extra' argument that
determines whether the condition, thread, and force-condition
specifiers should be parsed from the extra string or be used from the
function arguments.  However, for the case when 'parse_extra' is
false, there is no way to pass the force-condition specifier.  This
patch adds it as a new argument.

Also, in the case when parse_extra is false, the current behavior is
as if the condition is being forced.  This is a bug.  The default
behavior should reject the breakpoint.  See below for a demo of this
incorrect behavior.  (The MI command '-break-insert' uses the
'create_breakpoint' function with parse_extra=0.)

  $ gdb -q --interpreter=mi2 /tmp/simple
  =thread-group-added,id="i1"
  =cmd-param-changed,param="history save",value="on"
  =cmd-param-changed,param="auto-load safe-path",value="/"
  ~"Reading symbols from /tmp/simple...\n"
  (gdb)
  -break-insert -c junk -f main
  &"warning: failed to validate condition at location 1, disabling:\n  "
  &"No symbol \"junk\" in current context.\n"
  ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main"},{number="1.1",enabled="N*",addr="0x000000000000114e",func="main",file="simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}
  (gdb)
  break main if junk
  &"break main if junk\n"
  &"No symbol \"junk\" in current context.\n"
  ^error,msg="No symbol \"junk\" in current context."
  (gdb)
  break main -force-condition if junk
  &"break main -force-condition if junk\n"
  ~"Note: breakpoint 1 also set at pc 0x114e.\n"
  &"warning: failed to validate condition at location 1, disabling:\n  "
  &"No symbol \"junk\" in current context.\n"
  ~"Breakpoint 2 at 0x114e: file simple.c, line 2.\n"
  =breakpoint-created,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main"},{number="2.1",enabled="N*",addr="0x000000000000114e",func="main",file="simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}
  ^done
  (gdb)

After applying this patch, we get the behavior below:

  (gdb)
  -break-insert -c junk -f main
  ^error,msg="No symbol \"junk\" in current context."

gdb/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (create_breakpoint): Add a new parameter,
	'force_condition'.
	* breakpoint.c (create_breakpoint): Use the 'force_condition'
	argument when 'parse_extra' is false to check if the condition
	is invalid at all of the breakpoint locations.
	Update the users below.
	(break_command_1)
	(dprintf_command)
	(trace_command)
	(ftrace_command)
	(strace_command)
	(create_tracepoint_from_upload): Update.
	* guile/scm-breakpoint.c (gdbscm_register_breakpoint_x): Update.
	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Update.
	* python/py-breakpoint.c (bppy_init): Update.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Update.

gdb/testsuite/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp: Extend with checks for invalid breakpoint
	conditions.
---
 gdb/breakpoint.c                  | 40 ++++++++++++++++++++++++++-----
 gdb/breakpoint.h                  |  6 +++++
 gdb/guile/scm-breakpoint.c        |  2 +-
 gdb/mi/mi-cmd-break.c             |  1 +
 gdb/python/py-breakpoint.c        |  2 +-
 gdb/python/py-finishbreakpoint.c  |  2 +-
 gdb/testsuite/gdb.mi/mi-break.exp | 13 ++++++++++
 7 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 16cf7977b62..45a09719392 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -9456,7 +9456,7 @@ create_breakpoint (struct gdbarch *gdbarch,
 		   struct event_location *location,
 		   const char *cond_string,
 		   int thread, const char *extra_string,
-		   int parse_extra,
+		   bool force_condition, int parse_extra,
 		   int tempflag, enum bptype type_wanted,
 		   int ignore_count,
 		   enum auto_boolean pending_break_support,
@@ -9554,6 +9554,33 @@ create_breakpoint (struct gdbarch *gdbarch,
 	      && extra_string != NULL && *extra_string != '\0')
 		error (_("Garbage '%s' at end of location"), extra_string);
 
+	  /* Check the validity of the condition.  We should error out
+	     if the condition is invalid at all of the locations and
+	     if it is not forced.  In the PARSE_EXTRA case above, this
+	     check is done when parsing the EXTRA_STRING.  */
+	  if (cond_string != nullptr && !force_condition)
+	    {
+	      int num_failures = 0;
+	      const linespec_sals &lsal = canonical.lsals[0];
+	      for (auto &sal : lsal.sals)
+		{
+		  const char *cond = cond_string;
+		  try
+		    {
+		      parse_exp_1 (&cond, sal.pc, block_for_pc (sal.pc), 0);
+		      /* One success is sufficient to keep going.  */
+		      break;
+		    }
+		  catch (const gdb_exception_error &)
+		    {
+		      num_failures++;
+		      /* If this is the last sal, error out.  */
+		      if (num_failures == lsal.sals.size ())
+			throw;
+		    }
+		}
+	    }
+
 	  /* Create a private copy of condition string.  */
 	  if (cond_string)
 	    cond_string_copy.reset (xstrdup (cond_string));
@@ -9632,7 +9659,7 @@ break_command_1 (const char *arg, int flag, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     tempflag, type_wanted,
 		     0 /* Ignore count */,
 		     pending_break_support,
@@ -9819,7 +9846,7 @@ dprintf_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0, bp_dprintf,
 		     0 /* Ignore count */,
 		     pending_break_support,
@@ -14717,7 +14744,7 @@ trace_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14735,7 +14762,7 @@ ftrace_command (const char *arg, int from_tty)
 							 current_language);
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_fast_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14769,7 +14796,7 @@ strace_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_static_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14839,6 +14866,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
   if (!create_breakpoint (get_current_arch (),
 			  location.get (),
 			  utp->cond_string.get (), -1, addr_str,
+			  false /* force_condition */,
 			  0 /* parse cond/thread */,
 			  0 /* tempflag */,
 			  utp->type /* type_wanted */,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index c30656971bb..ded498f5562 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1409,6 +1409,11 @@ enum breakpoint_create_flags
    the condition, thread, and extra string from EXTRA_STRING, ignoring
    the similarly named parameters.
 
+   If FORCE_CONDITION is true, the condition is accepted even when it is
+   invalid at all of the locations.  However, if PARSE_EXTRA is non-zero,
+   the FORCE_CONDITION parameter is ignored and the corresponding argument
+   is parsed from EXTRA_STRING.
+
    If INTERNAL is non-zero, the breakpoint number will be allocated
    from the internal breakpoint count.
 
@@ -1418,6 +1423,7 @@ extern int create_breakpoint (struct gdbarch *gdbarch,
 			      struct event_location *location,
 			      const char *cond_string, int thread,
 			      const char *extra_string,
+			      bool force_condition,
 			      int parse_extra,
 			      int tempflag, enum bptype wanted_type,
 			      int ignore_count,
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index 99098e7e155..af63893461b 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -440,7 +440,7 @@ gdbscm_register_breakpoint_x (SCM self)
 	    const breakpoint_ops *ops =
 	      breakpoint_ops_for_event_location (eloc.get (), false);
 	    create_breakpoint (get_current_arch (),
-			       eloc.get (), NULL, -1, NULL,
+			       eloc.get (), NULL, -1, NULL, false,
 			       0,
 			       0, bp_breakpoint,
 			       0,
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 1c3e9209a74..5a4a62ce8c3 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -353,6 +353,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 
   create_breakpoint (get_current_arch (), location.get (), condition, thread,
 		     extra_string.c_str (),
+		     false,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,
 		     ignore_count,
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 3fbb1c633ff..9650bd023b5 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -835,7 +835,7 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 	      breakpoint_ops_for_event_location (location.get (), false);
 
 	    create_breakpoint (python_gdbarch,
-			       location.get (), NULL, -1, NULL,
+			       location.get (), NULL, -1, NULL, false,
 			       0,
 			       temporary_bp, type,
 			       0,
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index d01b84273fc..38b4cc67901 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -294,7 +294,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
       event_location_up location
 	= new_address_location (get_frame_pc (prev_frame), NULL, 0);
       create_breakpoint (python_gdbarch,
-			 location.get (), NULL, thread, NULL,
+			 location.get (), NULL, thread, NULL, false,
 			 0,
 			 1 /*temp_flag*/,
 			 bp_breakpoint,
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index 9d3d7ade6dc..ac13e4d1e09 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -224,6 +224,19 @@ proc test_error {} {
     mi_gdb_test "-break-insert -c i==4 \"callme if i < 4\"" \
         ".*\\^error,msg=\"Garbage 'if i < 4' at end of location\"" \
         "conditional breakpoint with garbage after location"
+
+    # Try using an invalid condition.
+    mi_gdb_test "-break-insert -c bad callme" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "breakpoint with bad condition"
+
+    mi_gdb_test "-dprintf-insert -c bad callme 123" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "dprintf with bad condition"
+
+    mi_gdb_test "-break-condition 5 bad" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "invalid condition"
 }
 
 proc test_disabled_creation {} {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition
  2021-04-07 14:55   ` [PATCH 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
                       ` (2 preceding siblings ...)
  2021-04-07 14:55     ` [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
@ 2021-04-07 14:55     ` Tankut Baris Aktemur
  2021-04-07 15:18       ` Eli Zaretskii
  2021-04-07 22:26       ` Simon Marchi
  2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  4 siblings, 2 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-07 14:55 UTC (permalink / raw)
  To: gdb-patches

Add a '-b' flag to the '-break-insert' command to be able to force
conditions.  The '-break-condition' command directly uses the CLI's
'cond' command; hence, it already recognizes the '-force' flag.

Because the '-dprintf-insert' command uses the same mechanism as the
'-break-insert' command, it obtains the '-b' flag, too.

gdb/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Recognize the
	'-b' flag to force the condition in the '-break-insert' and
	'-dprintf-insert' commands.
	* NEWS: Mention the change.

gdb/testsuite/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp (test_forced_conditions): New proc that
	is called by the test.

gdb/doc/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (GDB/MI Breakpoint Commands): Mention the '-b'
	flag of the '-break-insert' and '-dprintf-insert' commands,
	and the '--force' flag of the '-break-condition' command.
---
 gdb/NEWS                          |  7 +++++++
 gdb/doc/gdb.texinfo               | 16 ++++++++++++----
 gdb/mi/mi-cmd-break.c             | 10 ++++++++--
 gdb/testsuite/gdb.mi/mi-break.exp | 18 ++++++++++++++++++
 4 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 6cf76a14317..0232ab92419 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,13 @@
     equivalent of the CLI's "break -qualified" and "dprintf
     -qualified".
 
+ ** '-break-insert -b' and '-dprintf-insert -b'
+
+    The MI -break-insert and -dprintf-insert commands now support a
+    '-b' flag to forcibly define a condition even when the condition
+    is invalid at all locations of the breakpoint.  This is equivalent
+    to the '--force-condition' flag of the CLI's "break" command.
+
 * GDB now supports core file debugging for x86_64 Cygwin programs.
 
 * GDB will now look for the .gdbinit file in a config directory before
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index bfac2b6d245..79839bdfbd5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30396,13 +30396,15 @@ times="0"@}
 @subsubheading Synopsis
 
 @smallexample
- -break-condition @var{number} @var{expr}
+ -break-condition [ -force ] @var{number} @var{expr}
 @end smallexample
 
 Breakpoint @var{number} will stop the program only if the condition in
 @var{expr} is true.  The condition becomes part of the
 @samp{-break-list} output (see the description of the @samp{-break-list}
-command below).
+command below).  If the @samp{-force} flag is passed, the condition
+is forcibly defined even when it is invalid for all locations of
+Breakpoint @var{number}.
 
 @subsubheading @value{GDBN} Command
 
@@ -30567,7 +30569,7 @@ N.A.
 @subsubheading Synopsis
 
 @smallexample
- -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ] [ --qualified ]
+ -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ] [ -b ] [ --qualified ]
     [ -c @var{condition} ] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ]
 @end smallexample
@@ -30624,6 +30626,9 @@ Create a tracepoint.  @xref{Tracepoints}.  When this parameter
 is used together with @samp{-h}, a fast tracepoint is created.
 @item -c @var{condition}
 Make the breakpoint conditional on @var{condition}.
+@item -b
+Forcibly define the breakpoint even if the condition is invalid at
+all of the breakpoint locations.
 @item -i @var{ignore-count}
 Initialize the @var{ignore-count}.
 @item -p @var{thread-id}
@@ -30692,7 +30697,7 @@ times="0"@}]@}
 @subsubheading Synopsis
 
 @smallexample
- -dprintf-insert [ -t ] [ -f ] [ -d ] [ --qualified ]
+ -dprintf-insert [ -t ] [ -f ] [ -d ] [ -b ] [ --qualified ]
     [ -c @var{condition} ] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ] [ @var{format} ]
     [ @var{argument} ]
@@ -30718,6 +30723,9 @@ cannot be parsed.
 Create a disabled breakpoint.
 @item -c @var{condition}
 Make the breakpoint conditional on @var{condition}.
+@item -b
+Forcibly define the breakpoint even if the condition is invalid at
+all of the breakpoint locations.
 @item -i @var{ignore-count}
 Set the ignore count of the breakpoint (@pxref{Conditions, ignore count})
 to @var{ignore-count}.
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 5a4a62ce8c3..09517d67927 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -183,6 +183,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
   int is_explicit = 0;
   struct explicit_location explicit_loc;
   std::string extra_string;
+  bool force_condition = false;
 
   enum opt
     {
@@ -191,7 +192,8 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
       TRACEPOINT_OPT,
       QUALIFIED_OPT,
       EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
-      EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT
+      EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT,
+      FORCE_CONDITION_OPT
     };
   static const struct mi_opt opts[] =
   {
@@ -203,6 +205,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
     {"f", PENDING_OPT, 0},
     {"d", DISABLE_OPT, 0},
     {"a", TRACEPOINT_OPT, 0},
+    {"b", FORCE_CONDITION_OPT, 0},
     {"-qualified", QUALIFIED_OPT, 0},
     {"-source" , EXPLICIT_SOURCE_OPT, 1},
     {"-function", EXPLICIT_FUNC_OPT, 1},
@@ -269,6 +272,9 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 	  is_explicit = 1;
 	  explicit_loc.line_offset = linespec_parse_line_offset (oarg);
 	  break;
+	case FORCE_CONDITION_OPT:
+	  force_condition = true;
+	  break;
 	}
     }
 
@@ -353,7 +359,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 
   create_breakpoint (get_current_arch (), location.get (), condition, thread,
 		     extra_string.c_str (),
-		     false,
+		     force_condition,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,
 		     ignore_count,
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index ac13e4d1e09..87724dea185 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -408,6 +408,22 @@ proc test_explicit_breakpoints {} {
 	".*Source filename requires function, label, or line offset.*"
 }
 
+proc test_forced_conditions {} {
+    # Test forcing an invalid condition.
+    mi_gdb_test "info break"
+    mi_gdb_test "-break-condition -force 15 bad" \
+        ".*warning: failed to validate condition at location 15.1, disabling:.*" \
+        "invalid condition is forced"
+
+    mi_gdb_test "-break-insert -c bad -b callme" \
+        ".*warning: failed to validate condition at location 1, disabling:.*" \
+        "breakpoint with bad condition is forced"
+
+    mi_gdb_test "-dprintf-insert -c bad -b callme 123" \
+        ".*warning: failed to validate condition at location 1, disabling:.*" \
+        "dprintf with bad condition is forced"
+}
+
 proc test_break {mi_mode} {
     global srcdir subdir binfile
 
@@ -440,6 +456,8 @@ proc test_break {mi_mode} {
     test_abreak_creation
 
     test_explicit_breakpoints
+
+    test_forced_conditions
 }
 
 if [gdb_debug_enabled] {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI
  2021-04-07 14:55     ` [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI Tankut Baris Aktemur
@ 2021-04-07 15:15       ` Eli Zaretskii
  2021-04-07 21:42       ` Simon Marchi
  1 sibling, 0 replies; 103+ messages in thread
From: Eli Zaretskii @ 2021-04-07 15:15 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

> Date: Wed,  7 Apr 2021 16:55:56 +0200
> From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> 
>  @item enabled
>  This indicates whether the location is enabled, in which case the
> -value is @samp{y}, or disabled, in which case the value is @samp{n}.
> -Note that this is not the same as the field @code{enable}.
> +value is @samp{y}, or disabled by the user, in which case the value
> +is @samp{n}, or disabled because the breakpoint condition is invalid
> +at this location, in which case the value is @samp{N*}.

This is better formatted as a @table.  Trying ti squeeze all of the
possible values into a single sentence runs a high risk of producing a
complex and confusing sentence.

Thanks.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition
  2021-04-07 14:55     ` [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition Tankut Baris Aktemur
@ 2021-04-07 15:18       ` Eli Zaretskii
  2021-04-07 15:27         ` Aktemur, Tankut Baris
  2021-04-07 22:26       ` Simon Marchi
  1 sibling, 1 reply; 103+ messages in thread
From: Eli Zaretskii @ 2021-04-07 15:18 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

> Date: Wed,  7 Apr 2021 16:55:59 +0200
> From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 6cf76a14317..0232ab92419 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -31,6 +31,13 @@
>      equivalent of the CLI's "break -qualified" and "dprintf
>      -qualified".
>  
> + ** '-break-insert -b' and '-dprintf-insert -b'
> +
> +    The MI -break-insert and -dprintf-insert commands now support a
> +    '-b' flag to forcibly define a condition even when the condition
> +    is invalid at all locations of the breakpoint.  This is equivalent
> +    to the '--force-condition' flag of the CLI's "break" command.

By "invalid at all locations" did you mean "invalid for some of the
locations"?  IOW, does this flag handle the case when the condition is
valid for some locations and invalid for others, or is it specifically
for the case when the condition is invalid for _all_ the locations?

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition
  2021-04-07 15:18       ` Eli Zaretskii
@ 2021-04-07 15:27         ` Aktemur, Tankut Baris
  2021-04-07 15:53           ` Eli Zaretskii
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-07 15:27 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Wednesday, April 7, 2021 5:18 PM, Eli Zaretskii wrote:
> > Date: Wed,  7 Apr 2021 16:55:59 +0200
> > From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> >
> > diff --git a/gdb/NEWS b/gdb/NEWS
> > index 6cf76a14317..0232ab92419 100644
> > --- a/gdb/NEWS
> > +++ b/gdb/NEWS
> > @@ -31,6 +31,13 @@
> >      equivalent of the CLI's "break -qualified" and "dprintf
> >      -qualified".
> >
> > + ** '-break-insert -b' and '-dprintf-insert -b'
> > +
> > +    The MI -break-insert and -dprintf-insert commands now support a
> > +    '-b' flag to forcibly define a condition even when the condition
> > +    is invalid at all locations of the breakpoint.  This is equivalent
> > +    to the '--force-condition' flag of the CLI's "break" command.
> 
> By "invalid at all locations" did you mean "invalid for some of the
> locations"?  IOW, does this flag handle the case when the condition is
> valid for some locations and invalid for others, or is it specifically
> for the case when the condition is invalid for _all_ the locations?

It is specifically for all the locations.  If there are some locations at
which the condition is valid, the breakpoint is accepted.  There is no need
for the '-b' flag then.  The locations at which the condition is valid are
disabled.

Thanks
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition
  2021-04-07 15:27         ` Aktemur, Tankut Baris
@ 2021-04-07 15:53           ` Eli Zaretskii
  2021-04-07 16:05             ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Eli Zaretskii @ 2021-04-07 15:53 UTC (permalink / raw)
  To: Aktemur, Tankut Baris; +Cc: gdb-patches

> From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com>
> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
> Date: Wed, 7 Apr 2021 15:27:13 +0000
> 
> > > +    The MI -break-insert and -dprintf-insert commands now support a
> > > +    '-b' flag to forcibly define a condition even when the condition
> > > +    is invalid at all locations of the breakpoint.  This is equivalent
> > > +    to the '--force-condition' flag of the CLI's "break" command.
> > 
> > By "invalid at all locations" did you mean "invalid for some of the
> > locations"?  IOW, does this flag handle the case when the condition is
> > valid for some locations and invalid for others, or is it specifically
> > for the case when the condition is invalid for _all_ the locations?
> 
> It is specifically for all the locations.  If there are some locations at
> which the condition is valid, the breakpoint is accepted.  There is no need
> for the '-b' flag then.  The locations at which the condition is valid are
> disabled.

Then how about simply accepting the condition by default in that case,
without any need for a special flag?  IOW, it makes little sense to me
to accept the condition if it is _sometimes_ invalid, but not if it is
_always_ invalid.  It sounds like a gratuitous limitation.  Am I
missing something?

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition
  2021-04-07 15:53           ` Eli Zaretskii
@ 2021-04-07 16:05             ` Aktemur, Tankut Baris
  2021-04-07 16:50               ` Eli Zaretskii
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-07 16:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Wednesday, April 7, 2021 5:54 PM, Eli Zaretskii wrote:
> > From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com>
> > CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
> > Date: Wed, 7 Apr 2021 15:27:13 +0000
> >
> > > > +    The MI -break-insert and -dprintf-insert commands now support a
> > > > +    '-b' flag to forcibly define a condition even when the condition
> > > > +    is invalid at all locations of the breakpoint.  This is equivalent
> > > > +    to the '--force-condition' flag of the CLI's "break" command.
> > >
> > > By "invalid at all locations" did you mean "invalid for some of the
> > > locations"?  IOW, does this flag handle the case when the condition is
> > > valid for some locations and invalid for others, or is it specifically
> > > for the case when the condition is invalid for _all_ the locations?
> >
> > It is specifically for all the locations.  If there are some locations at
> > which the condition is valid, the breakpoint is accepted.  There is no need
> > for the '-b' flag then.  The locations at which the condition is valid are
> > disabled.
> 
> Then how about simply accepting the condition by default in that case,
> without any need for a special flag?  IOW, it makes little sense to me
> to accept the condition if it is _sometimes_ invalid, but not if it is
> _always_ invalid.  It sounds like a gratuitous limitation.  Am I
> missing something?

There are two problems with that approach:

1. Backward compatibility would be broken.

2. (The more important one, IMHO) If the user makes a typo in the condition,
the breakpoint would still be accepted by making it disabled at all the locations.
The force flag is the user telling GDB "I'm sure about this condition expression,
it will be meaningful in the future, just accept it." I think this scenario is less
common than the user entering really bad conditions.  Hence, it had made more sense
to reject the breakpoint in the default case.

-Baris

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition
  2021-04-07 16:05             ` Aktemur, Tankut Baris
@ 2021-04-07 16:50               ` Eli Zaretskii
  0 siblings, 0 replies; 103+ messages in thread
From: Eli Zaretskii @ 2021-04-07 16:50 UTC (permalink / raw)
  To: Aktemur, Tankut Baris; +Cc: gdb-patches

> From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com>
> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
> Date: Wed, 7 Apr 2021 16:05:11 +0000
> > Then how about simply accepting the condition by default in that case,
> > without any need for a special flag?  IOW, it makes little sense to me
> > to accept the condition if it is _sometimes_ invalid, but not if it is
> > _always_ invalid.  It sounds like a gratuitous limitation.  Am I
> > missing something?
> 
> There are two problems with that approach:
> 
> 1. Backward compatibility would be broken.

Would someone expect the current behavior?  Why would they?

> 2. (The more important one, IMHO) If the user makes a typo in the condition,
> the breakpoint would still be accepted by making it disabled at all the locations.

That's easy: issue a warning.

Anyway, if no one else thinks like me, I'm okay with doing it your
way.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 0/2] Breakpoint conditions at locations with differing contexts
  2021-04-05 17:45 ` [PATCH " Jonah Graham
  2021-04-06 14:11   ` Aktemur, Tankut Baris
  2021-04-07 14:55   ` [PATCH 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
@ 2021-04-07 21:24   ` Simon Marchi
  2021-04-07 21:36     ` Jonah Graham
  2 siblings, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2021-04-07 21:24 UTC (permalink / raw)
  To: Jonah Graham, Tankut Baris Aktemur; +Cc: gdb-patches

On 2021-04-05 1:45 p.m., Jonah Graham wrote:> On Fri, 31 Jul 2020 at 11:42, Tankut Baris Aktemur via Gdb-patches <
> 26^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="invalid
> condition
> here",times="0",original-location="main"},{number="1.1",enabled="N*",addr="0x0000000000001160",func="main",file="../src/bug572589.c",fullname="/scratch/eclipse/src/cdt/runtime-CDT/bug572589/src/bug572589.c",line="20",thread-groups=["i1"]}

Hi Jonah,

Off-topic, but if you look at the MI output above, you'll note that it's
not valid syntax.  A proper / strict MI parser should reject it.  This
has been fixed in MI3:

    https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Development-and-Front-Ends.html#GDB_002fMI-Development-and-Front-Ends

So you might want to consider upgrading to MI3 for GDB versions >= 9.1.

This is the commit that fixed it:

    https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b4be1b0648608a2578bbed39841c8ee411773edd

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 0/2] Breakpoint conditions at locations with differing contexts
  2021-04-07 21:24   ` [PATCH 0/2] Breakpoint conditions at locations with differing contexts Simon Marchi
@ 2021-04-07 21:36     ` Jonah Graham
  0 siblings, 0 replies; 103+ messages in thread
From: Jonah Graham @ 2021-04-07 21:36 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tankut Baris Aktemur, gdb-patches

On Wed., Apr. 7, 2021, 17:24 Simon Marchi, <simon.marchi@polymtl.ca> wrote:

> On 2021-04-05 1:45 p.m., Jonah Graham wrote:> On Fri, 31 Jul 2020 at
> 11:42, Tankut Baris Aktemur via Gdb-patches <
> >
> 26^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="invalid
> > condition
> >
> here",times="0",original-location="main"},{number="1.1",enabled="N*",addr="0x0000000000001160",func="main",file="../src/bug572589.c",fullname="/scratch/eclipse/src/cdt/runtime-CDT/bug572589/src/bug572589.c",line="20",thread-groups=["i1"]}
>
> Hi Jonah,
>
> Off-topic, but if you look at the MI output above, you'll note that it's
> not valid syntax.  A proper / strict MI parser should reject it.  This
> has been fixed in MI3:
>
>
> https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Development-and-Front-Ends.html#GDB_002fMI-Development-and-Front-Ends
>
> So you might want to consider upgrading to MI3 for GDB versions >= 9.1.
>

Thanks Simon for fixing that bug, there are some workarounds in the front
end for that. MI3 is on my to do list, I guess that is reason to raise it
higher up!

Jonah


> This is the commit that fixed it:
>
>
> https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b4be1b0648608a2578bbed39841c8ee411773edd
>
> Simon
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI
  2021-04-07 14:55     ` [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI Tankut Baris Aktemur
  2021-04-07 15:15       ` Eli Zaretskii
@ 2021-04-07 21:42       ` Simon Marchi
  1 sibling, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2021-04-07 21:42 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches

On 2021-04-07 10:55 a.m., Tankut Baris Aktemur via Gdb-patches wrote:
> Update the document to mention the "N*" value for the 'enabled' field
> of breakpoint locations.  Also remove the line about the 'enable'
> field, because there is no such field for locations.

Hi Baris,

The asterisk in N* exists because it refers to the bottom note in the
CLI output:

    (gdb) i b
    Num     Type           Disp Enb Address            What
    1       breakpoint     keep y   <MULTIPLE>
            stop only if patate == 2
    1.1                         N*  0x00000000000011f7 in main at test.c:27
    (*): Breakpoint condition is invalid at this location.

If we didn't have that bottom note, I suppose the value would simply be
"N" (and it would be very cryptic for CLI users).

So I think it would make sense that for MI, we only output "N" as the
enabled value, instead of "N*".

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp
  2021-04-07 14:55     ` [PATCH 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
@ 2021-04-07 21:49       ` Simon Marchi
  0 siblings, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2021-04-07 21:49 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches

On 2021-04-07 10:55 a.m., Tankut Baris Aktemur via Gdb-patches wrote:
> gdb/testsuite/ChangeLog:
> 2021-04-07  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.mi/mi-break.exp: Fix the duplicate test names.

What would you think of using proc_with_prefix, as the patch below does?
I find that adding the test proc name in the test names helps to give a
bit of context.


From 03f0d5465a59a3e7de30ad19255b239f3a0cd459 Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@polymtl.ca>
Date: Wed, 7 Apr 2021 17:46:14 -0400
Subject: [PATCH] patch

Change-Id: Ibb103c3de2b8fe257f83c569117c4fd422e41379
---
 gdb/testsuite/gdb.mi/mi-break.exp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index a7c37b365e93..19438f21f634 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -46,7 +46,7 @@ set line_callme_body   [expr $line_callme_head + 2]
 
 set fullname "fullname=\"${fullname_syntax}${srcfile}\""
 
-proc test_tbreak_creation_and_listing {} {
+proc_with_prefix test_tbreak_creation_and_listing {} {
     global srcfile
     global line_callee4_head
     global line_callee4_body
@@ -96,7 +96,7 @@ proc test_tbreak_creation_and_listing {} {
 	    "delete temp breakpoints"
 }
 
-proc test_rbreak_creation_and_listing {} {
+proc_with_prefix test_rbreak_creation_and_listing {} {
     global line_callee4_body
     global line_callee3_body
     global line_callee2_body
@@ -165,7 +165,7 @@ proc test_rbreak_creation_and_listing {} {
 	    "delete temp breakpoints"
 }
 
-proc test_abreak_creation {} {
+proc_with_prefix test_abreak_creation {} {
     mi_create_varobj tpnum \$tpnum "create local variable tpnum"
     # Test that $tpnum is not set before creating a tracepoint.
     mi_gdb_test "521-var-evaluate-expression tpnum" \
@@ -183,7 +183,7 @@ proc test_abreak_creation {} {
 	"524\\^done,value=\"10\"" "eval tpnum after tracepoint"
 }
 
-proc test_ignore_count {} {
+proc_with_prefix test_ignore_count {} {
     global line_callme_body
 
     mi_gdb_test "-break-insert -i 1 callme" \
@@ -196,7 +196,7 @@ proc test_ignore_count {} {
         {"" "disp=\"keep\"" } "run to breakpoint with ignore count"
 }
 
-proc test_error {} {
+proc_with_prefix test_error {} {
     mi_gdb_test "-break-insert function_that_does_not_exist" \
         ".*\\^error,msg=\"Function \\\\\"function_that_does_not_exist\\\\\" not defined.\"" \
         "breakpoint at nonexistent function"
@@ -226,7 +226,7 @@ proc test_error {} {
         "conditional breakpoint with garbage after location"
 }
 
-proc test_disabled_creation {} {
+proc_with_prefix test_disabled_creation {} {
     global line_callee2_body
 
     set bp [mi_make_breakpoint -number 6 -type breakpoint -disp keep \
@@ -241,7 +241,7 @@ proc test_disabled_creation {} {
             "test disabled creation: cleanup"
 }
 
-proc test_breakpoint_commands {} {
+proc_with_prefix test_breakpoint_commands {} {
     global line_callee2_body
 
     set bp_no_script \
@@ -281,7 +281,7 @@ proc test_breakpoint_commands {} {
 
     mi_gdb_test "-break-commands 9 \"bt\" \"set \$i=0\" \"while \$i<10\" \"print \$i\" \"set \$i=\$i+1\" \"end\" \"continue\" " \
         "\\^done" \
-        "breakpoint commands: set commands"
+        "breakpoint commands: set more commands"
 
     mi_send_resuming_command "exec-continue" "breakpoint commands: continue"
 
@@ -318,7 +318,7 @@ proc test_breakpoint_commands {} {
 # code.  In-depth testing of explicit breakpoints is accomplished in
 # gdb.linespec tests.
 
-proc test_explicit_breakpoints {} {
+proc_with_prefix test_explicit_breakpoints {} {
     global srcfile
     global line_callee3_head line_callee4_head
     global line_callee3_body line_callee4_body
-- 
2.30.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-07 14:55     ` [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
@ 2021-04-07 22:08       ` Simon Marchi
  2021-04-08  7:44         ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2021-04-07 22:08 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches



On 2021-04-07 10:55 a.m., Tankut Baris Aktemur via Gdb-patches wrote:
> The 'create_breakpoint' function takes a 'parse_extra' argument that
> determines whether the condition, thread, and force-condition
> specifiers should be parsed from the extra string or be used from the
> function arguments.  However, for the case when 'parse_extra' is
> false, there is no way to pass the force-condition specifier.  This
> patch adds it as a new argument.
> 
> Also, in the case when parse_extra is false, the current behavior is
> as if the condition is being forced.  This is a bug.  The default
> behavior should reject the breakpoint.  See below for a demo of this
> incorrect behavior.  (The MI command '-break-insert' uses the
> 'create_breakpoint' function with parse_extra=0.)
> 
>   $ gdb -q --interpreter=mi2 /tmp/simple
>   =thread-group-added,id="i1"
>   =cmd-param-changed,param="history save",value="on"
>   =cmd-param-changed,param="auto-load safe-path",value="/"
>   ~"Reading symbols from /tmp/simple...\n"
>   (gdb)
>   -break-insert -c junk -f main
>   &"warning: failed to validate condition at location 1, disabling:\n  "
>   &"No symbol \"junk\" in current context.\n"
>   ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main"},{number="1.1",enabled="N*",addr="0x000000000000114e",func="main",file="simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}
>   (gdb)
>   break main if junk
>   &"break main if junk\n"
>   &"No symbol \"junk\" in current context.\n"
>   ^error,msg="No symbol \"junk\" in current context."
>   (gdb)
>   break main -force-condition if junk
>   &"break main -force-condition if junk\n"
>   ~"Note: breakpoint 1 also set at pc 0x114e.\n"
>   &"warning: failed to validate condition at location 1, disabling:\n  "
>   &"No symbol \"junk\" in current context.\n"
>   ~"Breakpoint 2 at 0x114e: file simple.c, line 2.\n"
>   =breakpoint-created,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main"},{number="2.1",enabled="N*",addr="0x000000000000114e",func="main",file="simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}
>   ^done
>   (gdb)
> 
> After applying this patch, we get the behavior below:
> 
>   (gdb)
>   -break-insert -c junk -f main
>   ^error,msg="No symbol \"junk\" in current context."

You can also mention that this restores the previous behavior (present
in existing releases).

> diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
> index 9d3d7ade6dc..ac13e4d1e09 100644
> --- a/gdb/testsuite/gdb.mi/mi-break.exp
> +++ b/gdb/testsuite/gdb.mi/mi-break.exp
> @@ -224,6 +224,19 @@ proc test_error {} {
>      mi_gdb_test "-break-insert -c i==4 \"callme if i < 4\"" \
>          ".*\\^error,msg=\"Garbage 'if i < 4' at end of location\"" \
>          "conditional breakpoint with garbage after location"
> +
> +    # Try using an invalid condition.
> +    mi_gdb_test "-break-insert -c bad callme" \
> +        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
> +        "breakpoint with bad condition"
> +
> +    mi_gdb_test "-dprintf-insert -c bad callme 123" \
> +        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
> +        "dprintf with bad condition"
> +
> +    mi_gdb_test "-break-condition 5 bad" \
> +        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
> +        "invalid condition"

Here, does the 5 refer to an existing breakpoint number created by
another test function?  It's a bit annoying when test functions rely on
the state left by other test functions, that makes them harder to debug
in isolation.  In my ideal world, each test_* function in this file
(except test_break, which is just the driver) would spawn a fresh GDB,
such that if you need to debug one of them, you can comment out all the
other ones.

The patch is still OK though, and thanks for taking the time to write a
test.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition
  2021-04-07 14:55     ` [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition Tankut Baris Aktemur
  2021-04-07 15:18       ` Eli Zaretskii
@ 2021-04-07 22:26       ` Simon Marchi
  1 sibling, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2021-04-07 22:26 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches

On 2021-04-07 10:55 a.m., Tankut Baris Aktemur via Gdb-patches wrote:
> @@ -203,6 +205,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
>      {"f", PENDING_OPT, 0},
>      {"d", DISABLE_OPT, 0},
>      {"a", TRACEPOINT_OPT, 0},
> +    {"b", FORCE_CONDITION_OPT, 0},
>      {"-qualified", QUALIFIED_OPT, 0},
>      {"-source" , EXPLICIT_SOURCE_OPT, 1},
>      {"-function", EXPLICIT_FUNC_OPT, 1},

Hi, it's me nitpicking names again: instead of choosing a meaningless
single letter, could we use --force-condition?  It would just be more
obvious to any human reading MI logs, and machines don't really care
about the extra typing.

> +proc test_forced_conditions {} {
> +    # Test forcing an invalid condition.
> +    mi_gdb_test "info break"
> +    mi_gdb_test "-break-condition -force 15 bad" \
> +        ".*warning: failed to validate condition at location 15.1, disabling:.*" \
> +        "invalid condition is forced"
> +
> +    mi_gdb_test "-break-insert -c bad -b callme" \
> +        ".*warning: failed to validate condition at location 1, disabling:.*" \
> +        "breakpoint with bad condition is forced"
> +
> +    mi_gdb_test "-dprintf-insert -c bad -b callme 123" \
> +        ".*warning: failed to validate condition at location 1, disabling:.*" \
> +        "dprintf with bad condition is forced"


It would be good to validate at least that the commands succeed (output ^done).

At least for the -break-insert case, it might be a good idea to improve
(to be able to pass the -b/--force-condition flag) and use
mi_create_breakpoint_multi.  You could then validate what the command
outputs (one location with enabled="N").

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-07 22:08       ` Simon Marchi
@ 2021-04-08  7:44         ` Aktemur, Tankut Baris
  2021-04-08 13:59           ` Simon Marchi
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-08  7:44 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Thursday, April 8, 2021 12:09 AM, Simon Marchi wrote:
> On 2021-04-07 10:55 a.m., Tankut Baris Aktemur via Gdb-patches wrote:
> > diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
> > index 9d3d7ade6dc..ac13e4d1e09 100644
> > --- a/gdb/testsuite/gdb.mi/mi-break.exp
> > +++ b/gdb/testsuite/gdb.mi/mi-break.exp
> > @@ -224,6 +224,19 @@ proc test_error {} {
> >      mi_gdb_test "-break-insert -c i==4 \"callme if i < 4\"" \
> >          ".*\\^error,msg=\"Garbage 'if i < 4' at end of location\"" \
> >          "conditional breakpoint with garbage after location"
> > +
> > +    # Try using an invalid condition.
> > +    mi_gdb_test "-break-insert -c bad callme" \
> > +        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
> > +        "breakpoint with bad condition"
> > +
> > +    mi_gdb_test "-dprintf-insert -c bad callme 123" \
> > +        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
> > +        "dprintf with bad condition"
> > +
> > +    mi_gdb_test "-break-condition 5 bad" \
> > +        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
> > +        "invalid condition"
> 
> Here, does the 5 refer to an existing breakpoint number created by
> another test function?  It's a bit annoying when test functions rely on
> the state left by other test functions, that makes them harder to debug
> in isolation.  In my ideal world, each test_* function in this file
> (except test_break, which is just the driver) would spawn a fresh GDB,
> such that if you need to debug one of them, you can comment out all the
> other ones.

Ack.  The other test functions also refer to hardcoded breakpoint numbers.
Fiddling with the breakpoint list by deleting/adding new breakpoints
caused the other tests to fail, and thus I simply opted for the easier
solution of hardcoding.

> The patch is still OK though, and thanks for taking the time to write a
> test.
> 
> Simon

Thanks.
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-08  7:44         ` Aktemur, Tankut Baris
@ 2021-04-08 13:59           ` Simon Marchi
  2021-04-08 14:19             ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2021-04-08 13:59 UTC (permalink / raw)
  To: Aktemur, Tankut Baris, gdb-patches

On 2021-04-08 3:44 a.m., Aktemur, Tankut Baris wrote:
> Ack.  The other test functions also refer to hardcoded breakpoint numbers.
> Fiddling with the breakpoint list by deleting/adding new breakpoints
> caused the other tests to fail, and thus I simply opted for the easier
> solution of hardcoding.

And I don't want to put on you the burden of doing this change, so I
think your patch is OK.  But this would be an item on the wishlist, and
I mentioned it because it can perhaps influence the future tests you
write from scratch (if you agree with the idea).

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-08 13:59           ` Simon Marchi
@ 2021-04-08 14:19             ` Aktemur, Tankut Baris
  0 siblings, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-08 14:19 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Thursday, April 8, 2021 4:00 PM, Simon Marchi wrote:
> On 2021-04-08 3:44 a.m., Aktemur, Tankut Baris wrote:
> > Ack.  The other test functions also refer to hardcoded breakpoint numbers.
> > Fiddling with the breakpoint list by deleting/adding new breakpoints
> > caused the other tests to fail, and thus I simply opted for the easier
> > solution of hardcoding.
> 
> And I don't want to put on you the burden of doing this change, so I
> think your patch is OK.  But this would be an item on the wishlist, and
> I mentioned it because it can perhaps influence the future tests you
> write from scratch (if you agree with the idea).
> 
> Simon

Thank you for your empathy.  Yes, I agree with the idea -- it's hard
to argue against it :)

-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI
  2021-04-07 14:55   ` [PATCH 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
                       ` (3 preceding siblings ...)
  2021-04-07 14:55     ` [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition Tankut Baris Aktemur
@ 2021-04-08 14:22     ` Tankut Baris Aktemur
  2021-04-08 14:22       ` [PATCH v2 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
                         ` (5 more replies)
  4 siblings, 6 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-08 14:22 UTC (permalink / raw)
  To: gdb-patches

Hi,

This is v2 of

  https://sourceware.org/pipermail/gdb-patches/2021-April/177532.html

The changes with respect to v1 are:

* Using a table in the documentation of the 'enabled' field in MI output.

* Displaying "N" instead of "N*" in MI for locations that are disabled
  because of the breakpoint condition.

* Using proc_with_prefix to eliminate duplicate test names in
  gdb.mi/mi-break.exp.

* Using "--force-condition" instead of "-b" as a flag for the MI's
  -break-insert command.

* Revising the tests to check for command completion ("^done")
  and using 'mi_make_breakpoint_multi' to check for the 'enabled="N"'
  field.

Simon Marchi (1):
  testsuite, gdb.mi: fix duplicate test names in mi-break.exp

Tankut Baris Aktemur (3):
  gdb/breakpoint: display "N" on MI for disabled-by-condition locations
  gdb/breakpoint: add a 'force_condition' parameter to
    'create_breakpoint'
  gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd

 gdb/NEWS                          |  8 +++++
 gdb/breakpoint.c                  | 48 +++++++++++++++++++++-----
 gdb/breakpoint.h                  |  6 ++++
 gdb/doc/gdb.texinfo               | 29 ++++++++++++----
 gdb/guile/scm-breakpoint.c        |  2 +-
 gdb/mi/mi-cmd-break.c             |  7 ++++
 gdb/python/py-breakpoint.c        |  2 +-
 gdb/python/py-finishbreakpoint.c  |  2 +-
 gdb/testsuite/gdb.mi/mi-break.exp | 57 ++++++++++++++++++++++++++-----
 9 files changed, 134 insertions(+), 27 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations
  2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
@ 2021-04-08 14:22       ` Tankut Baris Aktemur
  2021-04-08 15:04         ` Eli Zaretskii
  2021-04-08 14:22       ` [PATCH v2 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
                         ` (4 subsequent siblings)
  5 siblings, 1 reply; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-08 14:22 UTC (permalink / raw)
  To: gdb-patches

For breakpoint locations that are disabled because of an invalid
condition, CLI displays "N*" in the 'enabled' field, where '*' refers
to the footnote below the table:

  (*): Breakpoint condition is invalid at this location.

This is not necessary for MI, where we shall simply print "N" without
the footnote.

Update the document to mention the "N" value for the MI.  Also remove
the line about the 'enable' field, because there is no such field for
locations.

gdb/ChangeLog:
2021-04-08  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.c (print_one_breakpoint_location): Display "N" for
	disabled-by-condition locations on MI-like output.
	(breakpoint_1): Do not display the disabled-by-condition footnote
	if the output is MI-like.

gdb/doc/ChangeLog:
2021-04-08  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (GDB/MI Breakpoint Information): Update the
	description for the 'enabled' field of breakpoint locations.
---
 gdb/breakpoint.c    |  8 ++++++--
 gdb/doc/gdb.texinfo | 13 ++++++++++---
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 16cf7977b62..0136019b4ae 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -6190,8 +6190,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 
   /* 4 */
   annotate_field (3);
+  /* For locations that are disabled because of an invalid condition,
+     display "N*" on CLI, where "*" refers to a footnote below the
+     table.  For MI, simply display a "N" without a footnote.  */
+  const char *N = (uiout->is_mi_like_p ()) ? "N" : "N*";
   if (part_of_multiple)
-    uiout->field_string ("enabled", (loc->disabled_by_cond ? "N*"
+    uiout->field_string ("enabled", (loc->disabled_by_cond ? N
 				     : (loc->enabled ? "y" : "n")));
   else
     uiout->field_fmt ("enabled", "%c", bpenables[(int) b->enable_state]);
@@ -6716,7 +6720,7 @@ breakpoint_1 (const char *bp_num_list, bool show_internal,
       if (last_loc && !server_command)
 	set_next_address (last_loc->gdbarch, last_loc->address);
 
-      if (has_disabled_by_cond_location)
+      if (has_disabled_by_cond_location && !uiout->is_mi_like_p ())
 	uiout->message (_("(*): Breakpoint condition is invalid at this "
 			  "location.\n"));
     }
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7dbffb65d53..438dcca5039 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30047,9 +30047,16 @@ number of the parent breakpoint.  The second digit is the number of the
 location within that breakpoint.
 
 @item enabled
-This indicates whether the location is enabled, in which case the
-value is @samp{y}, or disabled, in which case the value is @samp{n}.
-Note that this is not the same as the field @code{enable}.
+There are three possible values, with the following meanings:
+@table @code
+@item y
+The location is enabled.
+@item n
+The location is disabled by the user.
+@item N
+The location is disabled because the breakpoint condition is invalid
+at this location.
+@end table
 
 @item addr
 The address of this location as an hexidecimal number.
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp
  2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  2021-04-08 14:22       ` [PATCH v2 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
@ 2021-04-08 14:22       ` Tankut Baris Aktemur
  2021-04-08 14:22       ` [PATCH v2 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
                         ` (3 subsequent siblings)
  5 siblings, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-08 14:22 UTC (permalink / raw)
  To: gdb-patches

From: Simon Marchi <simon.marchi@polymtl.ca>

gdb/testsuite/ChangeLog:
2021-04-07  Simon Marchi  <simon.marchi@polymtl.ca>
	    Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp: Fix the duplicate test names.
---
 gdb/testsuite/gdb.mi/mi-break.exp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index a7c37b365e9..19438f21f63 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -46,7 +46,7 @@ set line_callme_body   [expr $line_callme_head + 2]
 
 set fullname "fullname=\"${fullname_syntax}${srcfile}\""
 
-proc test_tbreak_creation_and_listing {} {
+proc_with_prefix test_tbreak_creation_and_listing {} {
     global srcfile
     global line_callee4_head
     global line_callee4_body
@@ -96,7 +96,7 @@ proc test_tbreak_creation_and_listing {} {
 	    "delete temp breakpoints"
 }
 
-proc test_rbreak_creation_and_listing {} {
+proc_with_prefix test_rbreak_creation_and_listing {} {
     global line_callee4_body
     global line_callee3_body
     global line_callee2_body
@@ -165,7 +165,7 @@ proc test_rbreak_creation_and_listing {} {
 	    "delete temp breakpoints"
 }
 
-proc test_abreak_creation {} {
+proc_with_prefix test_abreak_creation {} {
     mi_create_varobj tpnum \$tpnum "create local variable tpnum"
     # Test that $tpnum is not set before creating a tracepoint.
     mi_gdb_test "521-var-evaluate-expression tpnum" \
@@ -183,7 +183,7 @@ proc test_abreak_creation {} {
 	"524\\^done,value=\"10\"" "eval tpnum after tracepoint"
 }
 
-proc test_ignore_count {} {
+proc_with_prefix test_ignore_count {} {
     global line_callme_body
 
     mi_gdb_test "-break-insert -i 1 callme" \
@@ -196,7 +196,7 @@ proc test_ignore_count {} {
         {"" "disp=\"keep\"" } "run to breakpoint with ignore count"
 }
 
-proc test_error {} {
+proc_with_prefix test_error {} {
     mi_gdb_test "-break-insert function_that_does_not_exist" \
         ".*\\^error,msg=\"Function \\\\\"function_that_does_not_exist\\\\\" not defined.\"" \
         "breakpoint at nonexistent function"
@@ -226,7 +226,7 @@ proc test_error {} {
         "conditional breakpoint with garbage after location"
 }
 
-proc test_disabled_creation {} {
+proc_with_prefix test_disabled_creation {} {
     global line_callee2_body
 
     set bp [mi_make_breakpoint -number 6 -type breakpoint -disp keep \
@@ -241,7 +241,7 @@ proc test_disabled_creation {} {
             "test disabled creation: cleanup"
 }
 
-proc test_breakpoint_commands {} {
+proc_with_prefix test_breakpoint_commands {} {
     global line_callee2_body
 
     set bp_no_script \
@@ -281,7 +281,7 @@ proc test_breakpoint_commands {} {
 
     mi_gdb_test "-break-commands 9 \"bt\" \"set \$i=0\" \"while \$i<10\" \"print \$i\" \"set \$i=\$i+1\" \"end\" \"continue\" " \
         "\\^done" \
-        "breakpoint commands: set commands"
+        "breakpoint commands: set more commands"
 
     mi_send_resuming_command "exec-continue" "breakpoint commands: continue"
 
@@ -318,7 +318,7 @@ proc test_breakpoint_commands {} {
 # code.  In-depth testing of explicit breakpoints is accomplished in
 # gdb.linespec tests.
 
-proc test_explicit_breakpoints {} {
+proc_with_prefix test_explicit_breakpoints {} {
     global srcfile
     global line_callee3_head line_callee4_head
     global line_callee3_body line_callee4_body
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  2021-04-08 14:22       ` [PATCH v2 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
  2021-04-08 14:22       ` [PATCH v2 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
@ 2021-04-08 14:22       ` Tankut Baris Aktemur
  2021-04-08 14:22       ` [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
                         ` (2 subsequent siblings)
  5 siblings, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-08 14:22 UTC (permalink / raw)
  To: gdb-patches

The 'create_breakpoint' function takes a 'parse_extra' argument that
determines whether the condition, thread, and force-condition
specifiers should be parsed from the extra string or be used from the
function arguments.  However, for the case when 'parse_extra' is
false, there is no way to pass the force-condition specifier.  This
patch adds it as a new argument.

Also, in the case when parse_extra is false, the current behavior is
as if the condition is being forced.  This is a bug.  The default
behavior should reject the breakpoint.  See below for a demo of this
incorrect behavior.  (The MI command '-break-insert' uses the
'create_breakpoint' function with parse_extra=0.)

  $ gdb -q --interpreter=mi3 /tmp/simple
  =thread-group-added,id="i1"
  =cmd-param-changed,param="history save",value="on"
  =cmd-param-changed,param="auto-load safe-path",value="/"
  ~"Reading symbols from /tmp/simple...\n"
  (gdb)
  -break-insert -c junk -f main
  &"warning: failed to validate condition at location 1, disabling:\n  "
  &"No symbol \"junk\" in current context.\n"
  ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main",locations=[{number="1.1",enabled="N",addr="0x000000000000114e",func="main",file="/tmp/simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}]}
  (gdb)
  break main if junk
  &"break main if junk\n"
  &"No symbol \"junk\" in current context.\n"
  ^error,msg="No symbol \"junk\" in current context."
  (gdb)
  break main -force-condition if junk
  &"break main -force-condition if junk\n"
  ~"Note: breakpoint 1 also set at pc 0x114e.\n"
  &"warning: failed to validate condition at location 1, disabling:\n  "
  &"No symbol \"junk\" in current context.\n"
  ~"Breakpoint 2 at 0x114e: file /tmp/simple.c, line 2.\n"
  =breakpoint-created,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main",locations=[{number="2.1",enabled="N",addr="0x000000000000114e",func="main",file="/tmp/simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}]}
  ^done
  (gdb)

After applying this patch, we get the behavior below:

  (gdb)
  -break-insert -c junk -f main
  ^error,msg="No symbol \"junk\" in current context."

This restores the behavior that is present in the existing releases.

gdb/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (create_breakpoint): Add a new parameter,
	'force_condition'.
	* breakpoint.c (create_breakpoint): Use the 'force_condition'
	argument when 'parse_extra' is false to check if the condition
	is invalid at all of the breakpoint locations.
	Update the users below.
	(break_command_1)
	(dprintf_command)
	(trace_command)
	(ftrace_command)
	(strace_command)
	(create_tracepoint_from_upload): Update.
	* guile/scm-breakpoint.c (gdbscm_register_breakpoint_x): Update.
	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Update.
	* python/py-breakpoint.c (bppy_init): Update.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Update.

gdb/testsuite/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp: Extend with checks for invalid breakpoint
	conditions.
---
 gdb/breakpoint.c                  | 40 ++++++++++++++++++++++++++-----
 gdb/breakpoint.h                  |  6 +++++
 gdb/guile/scm-breakpoint.c        |  2 +-
 gdb/mi/mi-cmd-break.c             |  1 +
 gdb/python/py-breakpoint.c        |  2 +-
 gdb/python/py-finishbreakpoint.c  |  2 +-
 gdb/testsuite/gdb.mi/mi-break.exp | 13 ++++++++++
 7 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 0136019b4ae..e5a5f6b0c6a 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -9460,7 +9460,7 @@ create_breakpoint (struct gdbarch *gdbarch,
 		   struct event_location *location,
 		   const char *cond_string,
 		   int thread, const char *extra_string,
-		   int parse_extra,
+		   bool force_condition, int parse_extra,
 		   int tempflag, enum bptype type_wanted,
 		   int ignore_count,
 		   enum auto_boolean pending_break_support,
@@ -9558,6 +9558,33 @@ create_breakpoint (struct gdbarch *gdbarch,
 	      && extra_string != NULL && *extra_string != '\0')
 		error (_("Garbage '%s' at end of location"), extra_string);
 
+	  /* Check the validity of the condition.  We should error out
+	     if the condition is invalid at all of the locations and
+	     if it is not forced.  In the PARSE_EXTRA case above, this
+	     check is done when parsing the EXTRA_STRING.  */
+	  if (cond_string != nullptr && !force_condition)
+	    {
+	      int num_failures = 0;
+	      const linespec_sals &lsal = canonical.lsals[0];
+	      for (auto &sal : lsal.sals)
+		{
+		  const char *cond = cond_string;
+		  try
+		    {
+		      parse_exp_1 (&cond, sal.pc, block_for_pc (sal.pc), 0);
+		      /* One success is sufficient to keep going.  */
+		      break;
+		    }
+		  catch (const gdb_exception_error &)
+		    {
+		      num_failures++;
+		      /* If this is the last sal, error out.  */
+		      if (num_failures == lsal.sals.size ())
+			throw;
+		    }
+		}
+	    }
+
 	  /* Create a private copy of condition string.  */
 	  if (cond_string)
 	    cond_string_copy.reset (xstrdup (cond_string));
@@ -9636,7 +9663,7 @@ break_command_1 (const char *arg, int flag, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     tempflag, type_wanted,
 		     0 /* Ignore count */,
 		     pending_break_support,
@@ -9823,7 +9850,7 @@ dprintf_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0, bp_dprintf,
 		     0 /* Ignore count */,
 		     pending_break_support,
@@ -14721,7 +14748,7 @@ trace_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14739,7 +14766,7 @@ ftrace_command (const char *arg, int from_tty)
 							 current_language);
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_fast_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14773,7 +14800,7 @@ strace_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_static_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14843,6 +14870,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
   if (!create_breakpoint (get_current_arch (),
 			  location.get (),
 			  utp->cond_string.get (), -1, addr_str,
+			  false /* force_condition */,
 			  0 /* parse cond/thread */,
 			  0 /* tempflag */,
 			  utp->type /* type_wanted */,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index c30656971bb..ded498f5562 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1409,6 +1409,11 @@ enum breakpoint_create_flags
    the condition, thread, and extra string from EXTRA_STRING, ignoring
    the similarly named parameters.
 
+   If FORCE_CONDITION is true, the condition is accepted even when it is
+   invalid at all of the locations.  However, if PARSE_EXTRA is non-zero,
+   the FORCE_CONDITION parameter is ignored and the corresponding argument
+   is parsed from EXTRA_STRING.
+
    If INTERNAL is non-zero, the breakpoint number will be allocated
    from the internal breakpoint count.
 
@@ -1418,6 +1423,7 @@ extern int create_breakpoint (struct gdbarch *gdbarch,
 			      struct event_location *location,
 			      const char *cond_string, int thread,
 			      const char *extra_string,
+			      bool force_condition,
 			      int parse_extra,
 			      int tempflag, enum bptype wanted_type,
 			      int ignore_count,
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index 99098e7e155..af63893461b 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -440,7 +440,7 @@ gdbscm_register_breakpoint_x (SCM self)
 	    const breakpoint_ops *ops =
 	      breakpoint_ops_for_event_location (eloc.get (), false);
 	    create_breakpoint (get_current_arch (),
-			       eloc.get (), NULL, -1, NULL,
+			       eloc.get (), NULL, -1, NULL, false,
 			       0,
 			       0, bp_breakpoint,
 			       0,
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 1c3e9209a74..5a4a62ce8c3 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -353,6 +353,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 
   create_breakpoint (get_current_arch (), location.get (), condition, thread,
 		     extra_string.c_str (),
+		     false,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,
 		     ignore_count,
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 3fbb1c633ff..9650bd023b5 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -835,7 +835,7 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 	      breakpoint_ops_for_event_location (location.get (), false);
 
 	    create_breakpoint (python_gdbarch,
-			       location.get (), NULL, -1, NULL,
+			       location.get (), NULL, -1, NULL, false,
 			       0,
 			       temporary_bp, type,
 			       0,
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index d01b84273fc..38b4cc67901 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -294,7 +294,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
       event_location_up location
 	= new_address_location (get_frame_pc (prev_frame), NULL, 0);
       create_breakpoint (python_gdbarch,
-			 location.get (), NULL, thread, NULL,
+			 location.get (), NULL, thread, NULL, false,
 			 0,
 			 1 /*temp_flag*/,
 			 bp_breakpoint,
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index 19438f21f63..e46a6cc0ec6 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -224,6 +224,19 @@ proc_with_prefix test_error {} {
     mi_gdb_test "-break-insert -c i==4 \"callme if i < 4\"" \
         ".*\\^error,msg=\"Garbage 'if i < 4' at end of location\"" \
         "conditional breakpoint with garbage after location"
+
+    # Try using an invalid condition.
+    mi_gdb_test "-break-insert -c bad callme" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "breakpoint with bad condition"
+
+    mi_gdb_test "-dprintf-insert -c bad callme 123" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "dprintf with bad condition"
+
+    mi_gdb_test "-break-condition 5 bad" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "invalid condition"
 }
 
 proc_with_prefix test_disabled_creation {} {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
                         ` (2 preceding siblings ...)
  2021-04-08 14:22       ` [PATCH v2 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
@ 2021-04-08 14:22       ` Tankut Baris Aktemur
  2021-04-08 15:06         ` Eli Zaretskii
  2021-04-11  1:06         ` Jonah Graham
  2021-04-11  1:13       ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Jonah Graham
  2021-04-21 12:17       ` [PATCH v3 " Tankut Baris Aktemur
  5 siblings, 2 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-08 14:22 UTC (permalink / raw)
  To: gdb-patches

Add a '--force-condition' flag to the '-break-insert' command to be
able to force conditions.  The '-break-condition' command directly
uses the CLI's 'cond' command; hence, it already recognizes the
'-force' flag.

Because the '-dprintf-insert' command uses the same mechanism as the
'-break-insert' command, it obtains the '--force-condition' flag, too.

gdb/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Recognize the
	'--force-condition' flag to force the condition in the
	'-break-insert' and '-dprintf-insert' commands.
	* NEWS: Mention the change.

gdb/testsuite/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp (test_forced_conditions): New proc that
	is called by the test.

gdb/doc/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (GDB/MI Breakpoint Commands): Mention the
	'--force-condition' flag of the '-break-insert' and
	'-dprintf-insert' commands, and the '--force' flag of the
	'-break-condition' command.
---
 gdb/NEWS                          |  8 ++++++++
 gdb/doc/gdb.texinfo               | 16 ++++++++++++----
 gdb/mi/mi-cmd-break.c             |  8 +++++++-
 gdb/testsuite/gdb.mi/mi-break.exp | 26 ++++++++++++++++++++++++++
 4 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 6cf76a14317..66f9d756fc4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,14 @@
     equivalent of the CLI's "break -qualified" and "dprintf
     -qualified".
 
+ ** '-break-insert --force-condition' and '-dprintf-insert --force-condition'
+
+    The MI -break-insert and -dprintf-insert commands now support a
+    '--force-condition' flag to forcibly define a condition even when
+    the condition is invalid at all locations of the breakpoint.  This
+    is equivalent to the '-force-condition' flag of the CLI's "break"
+    command.
+
 * GDB now supports core file debugging for x86_64 Cygwin programs.
 
 * GDB will now look for the .gdbinit file in a config directory before
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 438dcca5039..ab0e4b2d7a8 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30402,13 +30402,15 @@ times="0"@}
 @subsubheading Synopsis
 
 @smallexample
- -break-condition @var{number} @var{expr}
+ -break-condition [ -force ] @var{number} @var{expr}
 @end smallexample
 
 Breakpoint @var{number} will stop the program only if the condition in
 @var{expr} is true.  The condition becomes part of the
 @samp{-break-list} output (see the description of the @samp{-break-list}
-command below).
+command below).  If the @samp{-force} flag is passed, the condition
+is forcibly defined even when it is invalid for all locations of
+Breakpoint @var{number}.
 
 @subsubheading @value{GDBN} Command
 
@@ -30574,7 +30576,7 @@ N.A.
 
 @smallexample
  -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ] [ --qualified ]
-    [ -c @var{condition} ] [ -i @var{ignore-count} ]
+    [ -c @var{condition} ] [ --force-condition ] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ]
 @end smallexample
 
@@ -30630,6 +30632,9 @@ Create a tracepoint.  @xref{Tracepoints}.  When this parameter
 is used together with @samp{-h}, a fast tracepoint is created.
 @item -c @var{condition}
 Make the breakpoint conditional on @var{condition}.
+@item --force-condition
+Forcibly define the breakpoint even if the condition is invalid at
+all of the breakpoint locations.
 @item -i @var{ignore-count}
 Initialize the @var{ignore-count}.
 @item -p @var{thread-id}
@@ -30699,7 +30704,7 @@ times="0"@}]@}
 
 @smallexample
  -dprintf-insert [ -t ] [ -f ] [ -d ] [ --qualified ]
-    [ -c @var{condition} ] [ -i @var{ignore-count} ]
+    [ -c @var{condition} ] [--force-condition] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ] [ @var{format} ]
     [ @var{argument} ]
 @end smallexample
@@ -30724,6 +30729,9 @@ cannot be parsed.
 Create a disabled breakpoint.
 @item -c @var{condition}
 Make the breakpoint conditional on @var{condition}.
+@item --force-condition
+Forcibly define the breakpoint even if the condition is invalid at
+all of the breakpoint locations.
 @item -i @var{ignore-count}
 Set the ignore count of the breakpoint (@pxref{Conditions, ignore count})
 to @var{ignore-count}.
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 5a4a62ce8c3..fec75a8da5a 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -183,12 +183,14 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
   int is_explicit = 0;
   struct explicit_location explicit_loc;
   std::string extra_string;
+  bool force_condition = false;
 
   enum opt
     {
       HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
       IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT,
       TRACEPOINT_OPT,
+      FORCE_CONDITION_OPT,
       QUALIFIED_OPT,
       EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
       EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT
@@ -203,6 +205,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
     {"f", PENDING_OPT, 0},
     {"d", DISABLE_OPT, 0},
     {"a", TRACEPOINT_OPT, 0},
+    {"-force-condition", FORCE_CONDITION_OPT, 0},
     {"-qualified", QUALIFIED_OPT, 0},
     {"-source" , EXPLICIT_SOURCE_OPT, 1},
     {"-function", EXPLICIT_FUNC_OPT, 1},
@@ -269,6 +272,9 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 	  is_explicit = 1;
 	  explicit_loc.line_offset = linespec_parse_line_offset (oarg);
 	  break;
+	case FORCE_CONDITION_OPT:
+	  force_condition = true;
+	  break;
 	}
     }
 
@@ -353,7 +359,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 
   create_breakpoint (get_current_arch (), location.get (), condition, thread,
 		     extra_string.c_str (),
-		     false,
+		     force_condition,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,
 		     ignore_count,
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index e46a6cc0ec6..e84577f8628 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -408,6 +408,30 @@ proc_with_prefix test_explicit_breakpoints {} {
 	".*Source filename requires function, label, or line offset.*"
 }
 
+# Test forcing an invalid condition.
+
+proc_with_prefix test_forced_conditions {} {
+    set warning ".*warning: failed to validate condition .* disabling.*"
+
+    # Define a plain breakpoint first, and a condition later.
+    mi_create_breakpoint "callme" "define a bp" ""
+    mi_gdb_test "-break-condition -force \$bpnum bad" \
+        "${warning}\\^done" \
+        "invalid condition is forced"
+
+    set loc [mi_make_breakpoint_loc -enabled "N"]
+    set args [list -cond "bad" -locations "\\\[$loc\\\]"]
+    set bp [eval mi_make_breakpoint_multi $args]
+
+    mi_gdb_test "-break-insert -c bad --force-condition callme" \
+	"${warning}\\^done,$bp" \
+	"breakpoint with forced condition"
+
+    mi_gdb_test "-dprintf-insert -c bad --force-condition callme 123" \
+        "${warning}\\^done,$bp" \
+        "dprintf with forced condition"
+}
+
 proc test_break {mi_mode} {
     global srcdir subdir binfile
 
@@ -440,6 +464,8 @@ proc test_break {mi_mode} {
     test_abreak_creation
 
     test_explicit_breakpoints
+
+    test_forced_conditions
 }
 
 if [gdb_debug_enabled] {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations
  2021-04-08 14:22       ` [PATCH v2 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
@ 2021-04-08 15:04         ` Eli Zaretskii
  0 siblings, 0 replies; 103+ messages in thread
From: Eli Zaretskii @ 2021-04-08 15:04 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

> Date: Thu,  8 Apr 2021 16:22:36 +0200
> From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> 
> For breakpoint locations that are disabled because of an invalid
> condition, CLI displays "N*" in the 'enabled' field, where '*' refers
> to the footnote below the table:
> 
>   (*): Breakpoint condition is invalid at this location.
> 
> This is not necessary for MI, where we shall simply print "N" without
> the footnote.
> 
> Update the document to mention the "N" value for the MI.  Also remove
> the line about the 'enable' field, because there is no such field for
> locations.
> 
> gdb/ChangeLog:
> 2021-04-08  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* breakpoint.c (print_one_breakpoint_location): Display "N" for
> 	disabled-by-condition locations on MI-like output.
> 	(breakpoint_1): Do not display the disabled-by-condition footnote
> 	if the output is MI-like.
> 
> gdb/doc/ChangeLog:
> 2021-04-08  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.texinfo (GDB/MI Breakpoint Information): Update the
> 	description for the 'enabled' field of breakpoint locations.

OK for the documentation part, thanks.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-08 14:22       ` [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
@ 2021-04-08 15:06         ` Eli Zaretskii
  2021-04-08 15:12           ` Aktemur, Tankut Baris
  2021-04-11  1:06         ` Jonah Graham
  1 sibling, 1 reply; 103+ messages in thread
From: Eli Zaretskii @ 2021-04-08 15:06 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

> Date: Thu,  8 Apr 2021 16:22:39 +0200
> From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 6cf76a14317..66f9d756fc4 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -31,6 +31,14 @@
>      equivalent of the CLI's "break -qualified" and "dprintf
>      -qualified".
>  
> + ** '-break-insert --force-condition' and '-dprintf-insert --force-condition'
> +
> +    The MI -break-insert and -dprintf-insert commands now support a
> +    '--force-condition' flag to forcibly define a condition even when
> +    the condition is invalid at all locations of the breakpoint.  This
> +    is equivalent to the '-force-condition' flag of the CLI's "break"
> +    command.
> +
>  * GDB now supports core file debugging for x86_64 Cygwin programs.

This part is OK.

>  Breakpoint @var{number} will stop the program only if the condition in
>  @var{expr} is true.  The condition becomes part of the
>  @samp{-break-list} output (see the description of the @samp{-break-list}
> -command below).
> +command below).  If the @samp{-force} flag is passed, the condition
> +is forcibly defined even when it is invalid for all locations of
> +Breakpoint @var{number}.
   ^^^^^^^^^^
"Breakpoint" should not be capitalized here.

Thanks.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-08 15:06         ` Eli Zaretskii
@ 2021-04-08 15:12           ` Aktemur, Tankut Baris
  0 siblings, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-08 15:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Thursday, April 8, 2021 5:07 PM, Eli Zaretskii wrote:
> > Date: Thu,  8 Apr 2021 16:22:39 +0200
> > From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> >
> > diff --git a/gdb/NEWS b/gdb/NEWS
> > index 6cf76a14317..66f9d756fc4 100644
> > --- a/gdb/NEWS
> > +++ b/gdb/NEWS
> > @@ -31,6 +31,14 @@
> >      equivalent of the CLI's "break -qualified" and "dprintf
> >      -qualified".
> >
> > + ** '-break-insert --force-condition' and '-dprintf-insert --force-condition'
> > +
> > +    The MI -break-insert and -dprintf-insert commands now support a
> > +    '--force-condition' flag to forcibly define a condition even when
> > +    the condition is invalid at all locations of the breakpoint.  This
> > +    is equivalent to the '-force-condition' flag of the CLI's "break"
> > +    command.
> > +
> >  * GDB now supports core file debugging for x86_64 Cygwin programs.
> 
> This part is OK.
> 
> >  Breakpoint @var{number} will stop the program only if the condition in
> >  @var{expr} is true.  The condition becomes part of the
> >  @samp{-break-list} output (see the description of the @samp{-break-list}
> > -command below).
> > +command below).  If the @samp{-force} flag is passed, the condition
> > +is forcibly defined even when it is invalid for all locations of
> > +Breakpoint @var{number}.
>    ^^^^^^^^^^
> "Breakpoint" should not be capitalized here.

I'll fix this on my local branch.

> Thanks.

Thanks,
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-08 14:22       ` [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
  2021-04-08 15:06         ` Eli Zaretskii
@ 2021-04-11  1:06         ` Jonah Graham
  2021-04-11  1:12           ` Simon Marchi
  1 sibling, 1 reply; 103+ messages in thread
From: Jonah Graham @ 2021-04-11  1:06 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

On Thu, 8 Apr 2021 at 10:23, Tankut Baris Aktemur <
tankut.baris.aktemur@intel.com> wrote:

> Add a '--force-condition' flag to the '-break-insert' command to be
> able to force conditions.  The '-break-condition' command directly
> uses the CLI's 'cond' command; hence, it already recognizes the
> '-force' flag.
>
> Because the '-dprintf-insert' command uses the same mechanism as the
> '-break-insert' command, it obtains the '--force-condition' flag, too.
>

I don't know whether it matters, but in (MI) -break-condition, (CLI) break,
and (CLI) condition the force flag starts with one dash, but in (MI)
-break-insert/-dprintf-insert it starts with two dashes.

I think there is a convention that the MI long option names start with two
dashes, so -break-condition should probably accept --force for consistency.
The CLI certainly doesn't seem to have such a consistency AFAIU.

Thanks
Jonah


>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-11  1:06         ` Jonah Graham
@ 2021-04-11  1:12           ` Simon Marchi
  2021-04-21 12:06             ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2021-04-11  1:12 UTC (permalink / raw)
  To: Jonah Graham, Tankut Baris Aktemur; +Cc: gdb-patches

On 2021-04-10 9:06 p.m., Jonah Graham wrote:> On Thu, 8 Apr 2021 at 10:23, Tankut Baris Aktemur <
> tankut.baris.aktemur@intel.com> wrote:
> 
>> Add a '--force-condition' flag to the '-break-insert' command to be
>> able to force conditions.  The '-break-condition' command directly
>> uses the CLI's 'cond' command; hence, it already recognizes the
>> '-force' flag.
>>
>> Because the '-dprintf-insert' command uses the same mechanism as the
>> '-break-insert' command, it obtains the '--force-condition' flag, too.
>>
> 
> I don't know whether it matters, but in (MI) -break-condition, (CLI) break,
> and (CLI) condition the force flag starts with one dash, but in (MI)
> -break-insert/-dprintf-insert it starts with two dashes.
> 
> I think there is a convention that the MI long option names start with two
> dashes, so -break-condition should probably accept --force for consistency.
> The CLI certainly doesn't seem to have such a consistency AFAIU.

Good point, I think we should make -break-condition use --force.  Since
it wasn't released yet, we can still change it.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI
  2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
                         ` (3 preceding siblings ...)
  2021-04-08 14:22       ` [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
@ 2021-04-11  1:13       ` Jonah Graham
  2021-04-21 12:17       ` [PATCH v3 " Tankut Baris Aktemur
  5 siblings, 0 replies; 103+ messages in thread
From: Jonah Graham @ 2021-04-11  1:13 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

Hi Baris,

On Thu, 8 Apr 2021 at 10:23, Tankut Baris Aktemur <
tankut.baris.aktemur@intel.com> wrote:

> This is v2 of
>
>   https://sourceware.org/pipermail/gdb-patches/2021-April/177532.html
>
>
I have run v2 up and I quite like it. Critically it behaves the same as GDB
10 and previous on invalid condition inserted without the
--force[-condition]. This means that GDB 11 will work with existing
installations of Eclipse CDT (and presumably other frontends). Eclipse CDT
(and other frontends) can then optionally support the new feature.

I will continue to track Eclipse CDT's changes for this feature in
https://bugs.eclipse.org/bugs/show_bug.cgi?id=572589.

Thank you for the fast response.
Jonah

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-11  1:12           ` Simon Marchi
@ 2021-04-21 12:06             ` Aktemur, Tankut Baris
  2021-04-21 12:36               ` Simon Marchi
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-21 12:06 UTC (permalink / raw)
  To: Simon Marchi, Jonah Graham; +Cc: gdb-patches

On Sunday, April 11, 2021 3:13 AM, Simon Marchi wrote:
> On 2021-04-10 9:06 p.m., Jonah Graham wrote:> On Thu, 8 Apr 2021 at 10:23, Tankut Baris
> Aktemur <
> > tankut.baris.aktemur@intel.com> wrote:
> >
> >> Add a '--force-condition' flag to the '-break-insert' command to be
> >> able to force conditions.  The '-break-condition' command directly
> >> uses the CLI's 'cond' command; hence, it already recognizes the
> >> '-force' flag.
> >>
> >> Because the '-dprintf-insert' command uses the same mechanism as the
> >> '-break-insert' command, it obtains the '--force-condition' flag, too.
> >>
> >
> > I don't know whether it matters, but in (MI) -break-condition, (CLI) break,
> > and (CLI) condition the force flag starts with one dash, but in (MI)
> > -break-insert/-dprintf-insert it starts with two dashes.
> >
> > I think there is a convention that the MI long option names start with two
> > dashes, so -break-condition should probably accept --force for consistency.
> > The CLI certainly doesn't seem to have such a consistency AFAIU.
> 
> Good point, I think we should make -break-condition use --force.  Since
> it wasn't released yet, we can still change it.

Thanks, Jonah, for testing the patches with Eclipse CDT.  In v3, I'll include the
change for --force vs. -force.

Simon, the MI's -break-condition command directly uses the CLI's cond command.
I chose the straightforward solution of skipping the first "-" if the
argument pointer starts with "--force".  This essentially makes both the CLI
and the MI command accept both "--force" and "-force".  I thought it'd be good
to have this flexibility.  The alternative is to parse the MI argument strictly
for "--".

Thanks.
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v3 0/4] Multi-context invalid breakpoint conditions and MI
  2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
                         ` (4 preceding siblings ...)
  2021-04-11  1:13       ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Jonah Graham
@ 2021-04-21 12:17       ` Tankut Baris Aktemur
  2021-04-21 12:17         ` [PATCH v3 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
                           ` (4 more replies)
  5 siblings, 5 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-21 12:17 UTC (permalink / raw)
  To: gdb-patches

Hi,

This is v3 for

  https://sourceware.org/pipermail/gdb-patches/2021-April/177532.html

V2 is available at

  https://sourceware.org/pipermail/gdb-patches/2021-April/177578.html

In this revision, the 'cond' command skips the first "-" if it detects
that its argument string starts with "--force".  This way, both the
MI's -break-condition command and the CLI's cond command can flexibly
accept "--force" and "-force".  The documentation still uses "--force"
for MI and "-force" for CLI, though.

Simon Marchi (1):
  testsuite, gdb.mi: fix duplicate test names in mi-break.exp

Tankut Baris Aktemur (3):
  gdb/breakpoint: display "N" on MI for disabled-by-condition locations
  gdb/breakpoint: add a 'force_condition' parameter to
    'create_breakpoint'
  gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd

 gdb/NEWS                          | 15 ++++++++
 gdb/breakpoint.c                  | 56 +++++++++++++++++++++++++-----
 gdb/breakpoint.h                  |  6 ++++
 gdb/doc/gdb.texinfo               | 29 ++++++++++++----
 gdb/guile/scm-breakpoint.c        |  2 +-
 gdb/mi/mi-cmd-break.c             |  7 ++++
 gdb/python/py-breakpoint.c        |  2 +-
 gdb/python/py-finishbreakpoint.c  |  2 +-
 gdb/testsuite/gdb.mi/mi-break.exp | 57 ++++++++++++++++++++++++++-----
 9 files changed, 149 insertions(+), 27 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v3 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations
  2021-04-21 12:17       ` [PATCH v3 " Tankut Baris Aktemur
@ 2021-04-21 12:17         ` Tankut Baris Aktemur
  2021-04-21 12:48           ` Eli Zaretskii
  2021-04-21 12:17         ` [PATCH v3 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
                           ` (3 subsequent siblings)
  4 siblings, 1 reply; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-21 12:17 UTC (permalink / raw)
  To: gdb-patches

For breakpoint locations that are disabled because of an invalid
condition, CLI displays "N*" in the 'enabled' field, where '*' refers
to the footnote below the table:

  (*): Breakpoint condition is invalid at this location.

This is not necessary for MI, where we shall simply print "N" without
the footnote.

Update the document to mention the "N" value for the MI.  Also remove
the line about the 'enable' field, because there is no such field for
locations.

gdb/ChangeLog:
2021-04-08  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.c (print_one_breakpoint_location): Display "N" for
	disabled-by-condition locations on MI-like output.
	(breakpoint_1): Do not display the disabled-by-condition footnote
	if the output is MI-like.

gdb/doc/ChangeLog:
2021-04-08  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (GDB/MI Breakpoint Information): Update the
	description for the 'enabled' field of breakpoint locations.
---
 gdb/breakpoint.c    |  8 ++++++--
 gdb/doc/gdb.texinfo | 13 ++++++++++---
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 16cf7977b62..0136019b4ae 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -6190,8 +6190,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 
   /* 4 */
   annotate_field (3);
+  /* For locations that are disabled because of an invalid condition,
+     display "N*" on CLI, where "*" refers to a footnote below the
+     table.  For MI, simply display a "N" without a footnote.  */
+  const char *N = (uiout->is_mi_like_p ()) ? "N" : "N*";
   if (part_of_multiple)
-    uiout->field_string ("enabled", (loc->disabled_by_cond ? "N*"
+    uiout->field_string ("enabled", (loc->disabled_by_cond ? N
 				     : (loc->enabled ? "y" : "n")));
   else
     uiout->field_fmt ("enabled", "%c", bpenables[(int) b->enable_state]);
@@ -6716,7 +6720,7 @@ breakpoint_1 (const char *bp_num_list, bool show_internal,
       if (last_loc && !server_command)
 	set_next_address (last_loc->gdbarch, last_loc->address);
 
-      if (has_disabled_by_cond_location)
+      if (has_disabled_by_cond_location && !uiout->is_mi_like_p ())
 	uiout->message (_("(*): Breakpoint condition is invalid at this "
 			  "location.\n"));
     }
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 51e1c64a98a..ec15654ba58 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30047,9 +30047,16 @@ number of the parent breakpoint.  The second digit is the number of the
 location within that breakpoint.
 
 @item enabled
-This indicates whether the location is enabled, in which case the
-value is @samp{y}, or disabled, in which case the value is @samp{n}.
-Note that this is not the same as the field @code{enable}.
+There are three possible values, with the following meanings:
+@table @code
+@item y
+The location is enabled.
+@item n
+The location is disabled by the user.
+@item N
+The location is disabled because the breakpoint condition is invalid
+at this location.
+@end table
 
 @item addr
 The address of this location as an hexidecimal number.
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v3 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp
  2021-04-21 12:17       ` [PATCH v3 " Tankut Baris Aktemur
  2021-04-21 12:17         ` [PATCH v3 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
@ 2021-04-21 12:17         ` Tankut Baris Aktemur
  2021-04-21 12:17         ` [PATCH v3 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
                           ` (2 subsequent siblings)
  4 siblings, 0 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-21 12:17 UTC (permalink / raw)
  To: gdb-patches

From: Simon Marchi <simon.marchi@polymtl.ca>

gdb/testsuite/ChangeLog:
2021-04-07  Simon Marchi  <simon.marchi@polymtl.ca>
	    Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp: Fix the duplicate test names.
---
 gdb/testsuite/gdb.mi/mi-break.exp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index a7c37b365e9..19438f21f63 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -46,7 +46,7 @@ set line_callme_body   [expr $line_callme_head + 2]
 
 set fullname "fullname=\"${fullname_syntax}${srcfile}\""
 
-proc test_tbreak_creation_and_listing {} {
+proc_with_prefix test_tbreak_creation_and_listing {} {
     global srcfile
     global line_callee4_head
     global line_callee4_body
@@ -96,7 +96,7 @@ proc test_tbreak_creation_and_listing {} {
 	    "delete temp breakpoints"
 }
 
-proc test_rbreak_creation_and_listing {} {
+proc_with_prefix test_rbreak_creation_and_listing {} {
     global line_callee4_body
     global line_callee3_body
     global line_callee2_body
@@ -165,7 +165,7 @@ proc test_rbreak_creation_and_listing {} {
 	    "delete temp breakpoints"
 }
 
-proc test_abreak_creation {} {
+proc_with_prefix test_abreak_creation {} {
     mi_create_varobj tpnum \$tpnum "create local variable tpnum"
     # Test that $tpnum is not set before creating a tracepoint.
     mi_gdb_test "521-var-evaluate-expression tpnum" \
@@ -183,7 +183,7 @@ proc test_abreak_creation {} {
 	"524\\^done,value=\"10\"" "eval tpnum after tracepoint"
 }
 
-proc test_ignore_count {} {
+proc_with_prefix test_ignore_count {} {
     global line_callme_body
 
     mi_gdb_test "-break-insert -i 1 callme" \
@@ -196,7 +196,7 @@ proc test_ignore_count {} {
         {"" "disp=\"keep\"" } "run to breakpoint with ignore count"
 }
 
-proc test_error {} {
+proc_with_prefix test_error {} {
     mi_gdb_test "-break-insert function_that_does_not_exist" \
         ".*\\^error,msg=\"Function \\\\\"function_that_does_not_exist\\\\\" not defined.\"" \
         "breakpoint at nonexistent function"
@@ -226,7 +226,7 @@ proc test_error {} {
         "conditional breakpoint with garbage after location"
 }
 
-proc test_disabled_creation {} {
+proc_with_prefix test_disabled_creation {} {
     global line_callee2_body
 
     set bp [mi_make_breakpoint -number 6 -type breakpoint -disp keep \
@@ -241,7 +241,7 @@ proc test_disabled_creation {} {
             "test disabled creation: cleanup"
 }
 
-proc test_breakpoint_commands {} {
+proc_with_prefix test_breakpoint_commands {} {
     global line_callee2_body
 
     set bp_no_script \
@@ -281,7 +281,7 @@ proc test_breakpoint_commands {} {
 
     mi_gdb_test "-break-commands 9 \"bt\" \"set \$i=0\" \"while \$i<10\" \"print \$i\" \"set \$i=\$i+1\" \"end\" \"continue\" " \
         "\\^done" \
-        "breakpoint commands: set commands"
+        "breakpoint commands: set more commands"
 
     mi_send_resuming_command "exec-continue" "breakpoint commands: continue"
 
@@ -318,7 +318,7 @@ proc test_breakpoint_commands {} {
 # code.  In-depth testing of explicit breakpoints is accomplished in
 # gdb.linespec tests.
 
-proc test_explicit_breakpoints {} {
+proc_with_prefix test_explicit_breakpoints {} {
     global srcfile
     global line_callee3_head line_callee4_head
     global line_callee3_body line_callee4_body
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v3 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-21 12:17       ` [PATCH v3 " Tankut Baris Aktemur
  2021-04-21 12:17         ` [PATCH v3 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
  2021-04-21 12:17         ` [PATCH v3 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
@ 2021-04-21 12:17         ` Tankut Baris Aktemur
  2021-04-21 13:18           ` Simon Marchi
  2021-04-21 12:17         ` [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
  2021-04-22 14:35         ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  4 siblings, 1 reply; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-21 12:17 UTC (permalink / raw)
  To: gdb-patches

The 'create_breakpoint' function takes a 'parse_extra' argument that
determines whether the condition, thread, and force-condition
specifiers should be parsed from the extra string or be used from the
function arguments.  However, for the case when 'parse_extra' is
false, there is no way to pass the force-condition specifier.  This
patch adds it as a new argument.

Also, in the case when parse_extra is false, the current behavior is
as if the condition is being forced.  This is a bug.  The default
behavior should reject the breakpoint.  See below for a demo of this
incorrect behavior.  (The MI command '-break-insert' uses the
'create_breakpoint' function with parse_extra=0.)

  $ gdb -q --interpreter=mi3 /tmp/simple
  =thread-group-added,id="i1"
  =cmd-param-changed,param="history save",value="on"
  =cmd-param-changed,param="auto-load safe-path",value="/"
  ~"Reading symbols from /tmp/simple...\n"
  (gdb)
  -break-insert -c junk -f main
  &"warning: failed to validate condition at location 1, disabling:\n  "
  &"No symbol \"junk\" in current context.\n"
  ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main",locations=[{number="1.1",enabled="N",addr="0x000000000000114e",func="main",file="/tmp/simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}]}
  (gdb)
  break main if junk
  &"break main if junk\n"
  &"No symbol \"junk\" in current context.\n"
  ^error,msg="No symbol \"junk\" in current context."
  (gdb)
  break main -force-condition if junk
  &"break main -force-condition if junk\n"
  ~"Note: breakpoint 1 also set at pc 0x114e.\n"
  &"warning: failed to validate condition at location 1, disabling:\n  "
  &"No symbol \"junk\" in current context.\n"
  ~"Breakpoint 2 at 0x114e: file /tmp/simple.c, line 2.\n"
  =breakpoint-created,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main",locations=[{number="2.1",enabled="N",addr="0x000000000000114e",func="main",file="/tmp/simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}]}
  ^done
  (gdb)

After applying this patch, we get the behavior below:

  (gdb)
  -break-insert -c junk -f main
  ^error,msg="No symbol \"junk\" in current context."

This restores the behavior that is present in the existing releases.

gdb/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* breakpoint.h (create_breakpoint): Add a new parameter,
	'force_condition'.
	* breakpoint.c (create_breakpoint): Use the 'force_condition'
	argument when 'parse_extra' is false to check if the condition
	is invalid at all of the breakpoint locations.
	Update the users below.
	(break_command_1)
	(dprintf_command)
	(trace_command)
	(ftrace_command)
	(strace_command)
	(create_tracepoint_from_upload): Update.
	* guile/scm-breakpoint.c (gdbscm_register_breakpoint_x): Update.
	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Update.
	* python/py-breakpoint.c (bppy_init): Update.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Update.

gdb/testsuite/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp: Extend with checks for invalid breakpoint
	conditions.
---
 gdb/breakpoint.c                  | 40 ++++++++++++++++++++++++++-----
 gdb/breakpoint.h                  |  6 +++++
 gdb/guile/scm-breakpoint.c        |  2 +-
 gdb/mi/mi-cmd-break.c             |  1 +
 gdb/python/py-breakpoint.c        |  2 +-
 gdb/python/py-finishbreakpoint.c  |  2 +-
 gdb/testsuite/gdb.mi/mi-break.exp | 13 ++++++++++
 7 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 0136019b4ae..c2d0ffba974 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -9460,7 +9460,7 @@ create_breakpoint (struct gdbarch *gdbarch,
 		   struct event_location *location,
 		   const char *cond_string,
 		   int thread, const char *extra_string,
-		   int parse_extra,
+		   bool force_condition, int parse_extra,
 		   int tempflag, enum bptype type_wanted,
 		   int ignore_count,
 		   enum auto_boolean pending_break_support,
@@ -9558,6 +9558,33 @@ create_breakpoint (struct gdbarch *gdbarch,
 	      && extra_string != NULL && *extra_string != '\0')
 		error (_("Garbage '%s' at end of location"), extra_string);
 
+	  /* Check the validity of the condition.  We should error out
+	     if the condition is invalid at all of the locations and
+	     if it is not forced.  In the PARSE_EXTRA case above, this
+	     check is done when parsing the EXTRA_STRING.  */
+	  if (cond_string != nullptr && !force_condition)
+	    {
+	      int num_failures = 0;
+	      const linespec_sals &lsal = canonical.lsals[0];
+	      for (const auto &sal : lsal.sals)
+		{
+		  const char *cond = cond_string;
+		  try
+		    {
+		      parse_exp_1 (&cond, sal.pc, block_for_pc (sal.pc), 0);
+		      /* One success is sufficient to keep going.  */
+		      break;
+		    }
+		  catch (const gdb_exception_error &)
+		    {
+		      num_failures++;
+		      /* If this is the last sal, error out.  */
+		      if (num_failures == lsal.sals.size ())
+			throw;
+		    }
+		}
+	    }
+
 	  /* Create a private copy of condition string.  */
 	  if (cond_string)
 	    cond_string_copy.reset (xstrdup (cond_string));
@@ -9636,7 +9663,7 @@ break_command_1 (const char *arg, int flag, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     tempflag, type_wanted,
 		     0 /* Ignore count */,
 		     pending_break_support,
@@ -9823,7 +9850,7 @@ dprintf_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0, bp_dprintf,
 		     0 /* Ignore count */,
 		     pending_break_support,
@@ -14721,7 +14748,7 @@ trace_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14739,7 +14766,7 @@ ftrace_command (const char *arg, int from_tty)
 							 current_language);
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_fast_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14773,7 +14800,7 @@ strace_command (const char *arg, int from_tty)
 
   create_breakpoint (get_current_arch (),
 		     location.get (),
-		     NULL, 0, arg, 1 /* parse arg */,
+		     NULL, 0, arg, false, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_static_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14843,6 +14870,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
   if (!create_breakpoint (get_current_arch (),
 			  location.get (),
 			  utp->cond_string.get (), -1, addr_str,
+			  false /* force_condition */,
 			  0 /* parse cond/thread */,
 			  0 /* tempflag */,
 			  utp->type /* type_wanted */,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index c30656971bb..ded498f5562 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1409,6 +1409,11 @@ enum breakpoint_create_flags
    the condition, thread, and extra string from EXTRA_STRING, ignoring
    the similarly named parameters.
 
+   If FORCE_CONDITION is true, the condition is accepted even when it is
+   invalid at all of the locations.  However, if PARSE_EXTRA is non-zero,
+   the FORCE_CONDITION parameter is ignored and the corresponding argument
+   is parsed from EXTRA_STRING.
+
    If INTERNAL is non-zero, the breakpoint number will be allocated
    from the internal breakpoint count.
 
@@ -1418,6 +1423,7 @@ extern int create_breakpoint (struct gdbarch *gdbarch,
 			      struct event_location *location,
 			      const char *cond_string, int thread,
 			      const char *extra_string,
+			      bool force_condition,
 			      int parse_extra,
 			      int tempflag, enum bptype wanted_type,
 			      int ignore_count,
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index 99098e7e155..af63893461b 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -440,7 +440,7 @@ gdbscm_register_breakpoint_x (SCM self)
 	    const breakpoint_ops *ops =
 	      breakpoint_ops_for_event_location (eloc.get (), false);
 	    create_breakpoint (get_current_arch (),
-			       eloc.get (), NULL, -1, NULL,
+			       eloc.get (), NULL, -1, NULL, false,
 			       0,
 			       0, bp_breakpoint,
 			       0,
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 1c3e9209a74..5a4a62ce8c3 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -353,6 +353,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 
   create_breakpoint (get_current_arch (), location.get (), condition, thread,
 		     extra_string.c_str (),
+		     false,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,
 		     ignore_count,
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 3fbb1c633ff..9650bd023b5 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -835,7 +835,7 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 	      breakpoint_ops_for_event_location (location.get (), false);
 
 	    create_breakpoint (python_gdbarch,
-			       location.get (), NULL, -1, NULL,
+			       location.get (), NULL, -1, NULL, false,
 			       0,
 			       temporary_bp, type,
 			       0,
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index d01b84273fc..38b4cc67901 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -294,7 +294,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
       event_location_up location
 	= new_address_location (get_frame_pc (prev_frame), NULL, 0);
       create_breakpoint (python_gdbarch,
-			 location.get (), NULL, thread, NULL,
+			 location.get (), NULL, thread, NULL, false,
 			 0,
 			 1 /*temp_flag*/,
 			 bp_breakpoint,
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index 19438f21f63..e46a6cc0ec6 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -224,6 +224,19 @@ proc_with_prefix test_error {} {
     mi_gdb_test "-break-insert -c i==4 \"callme if i < 4\"" \
         ".*\\^error,msg=\"Garbage 'if i < 4' at end of location\"" \
         "conditional breakpoint with garbage after location"
+
+    # Try using an invalid condition.
+    mi_gdb_test "-break-insert -c bad callme" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "breakpoint with bad condition"
+
+    mi_gdb_test "-dprintf-insert -c bad callme 123" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "dprintf with bad condition"
+
+    mi_gdb_test "-break-condition 5 bad" \
+        ".*\\^error,msg=\"No symbol \\\\\"bad\\\\\" in current context.\"" \
+        "invalid condition"
 }
 
 proc_with_prefix test_disabled_creation {} {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-21 12:17       ` [PATCH v3 " Tankut Baris Aktemur
                           ` (2 preceding siblings ...)
  2021-04-21 12:17         ` [PATCH v3 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
@ 2021-04-21 12:17         ` Tankut Baris Aktemur
  2021-04-21 12:50           ` Eli Zaretskii
  2021-04-21 13:37           ` Simon Marchi
  2021-04-22 14:35         ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  4 siblings, 2 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-21 12:17 UTC (permalink / raw)
  To: gdb-patches

Add a '--force-condition' flag to the '-break-insert' command to be
able to force conditions.  Because the '-dprintf-insert' command uses
the same mechanism as the '-break-insert' command, it obtains the
'--force-condition' flag, too.

The '-break-condition' command directly uses the CLI's 'cond' command.
Modify the 'condition_command' function to consider both "--force" and
"-force" as its argument, because "--" is the conventional delimiter
for arguments in MI.

gdb/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Recognize the
	'--force-condition' flag to force the condition in the
	'-break-insert' and '-dprintf-insert' commands.
	* breakpoint.c (condition_command): Consider having "--force"
	as the argument and normalize to "-force".
	* NEWS: Mention the change.

gdb/testsuite/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp (test_forced_conditions): New proc that
	is called by the test.

gdb/doc/ChangeLog:
2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (GDB/MI Breakpoint Commands): Mention the
	'--force-condition' flag of the '-break-insert' and
	'-dprintf-insert' commands, and the '--force' flag of the
	'-break-condition' command.
---
 gdb/NEWS                          | 15 +++++++++++++++
 gdb/breakpoint.c                  |  8 ++++++++
 gdb/doc/gdb.texinfo               | 16 ++++++++++++----
 gdb/mi/mi-cmd-break.c             |  8 +++++++-
 gdb/testsuite/gdb.mi/mi-break.exp | 26 ++++++++++++++++++++++++++
 5 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 6cf76a14317..a64dcefd167 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,21 @@
     equivalent of the CLI's "break -qualified" and "dprintf
     -qualified".
 
+ ** '-break-insert --force-condition' and '-dprintf-insert --force-condition'
+
+    The MI -break-insert and -dprintf-insert commands now support a
+    '--force-condition' flag to forcibly define a condition even when
+    the condition is invalid at all locations of the breakpoint.  This
+    is equivalent to the '-force-condition' flag of the CLI's "break"
+    command.
+
+ ** '-break-condition --force'
+
+    The MI -break-condition command now supports a '--force' flag to
+    forcibly define a condition even when the condition is invalid at
+    all locations of the selected breakpoint.  This is equivalent to
+    the '-force' flag of the CLI's "cond" command.
+
 * GDB now supports core file debugging for x86_64 Cygwin programs.
 
 * GDB will now look for the .gdbinit file in a config directory before
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index c2d0ffba974..f0a6deda511 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1073,6 +1073,14 @@ condition_command (const char *arg, int from_tty)
   if (arg == 0)
     error_no_arg (_("breakpoint number"));
 
+  /* The '-break-condition' MI command is delegated to this function.
+     However, MI has the convention of having "--" delimiter for
+     flags.  Accept both "-force" and "--force".  The force flag, if
+     exists, must be at the beginning of ARG.  */
+  arg = skip_spaces (arg);
+  if (startswith (arg, "--force"))
+    arg++;
+
   p = arg;
 
   /* Check if the "-force" flag was passed.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ec15654ba58..17d1111407e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30402,13 +30402,15 @@ times="0"@}
 @subsubheading Synopsis
 
 @smallexample
- -break-condition @var{number} @var{expr}
+ -break-condition [ --force ] @var{number} @var{expr}
 @end smallexample
 
 Breakpoint @var{number} will stop the program only if the condition in
 @var{expr} is true.  The condition becomes part of the
 @samp{-break-list} output (see the description of the @samp{-break-list}
-command below).
+command below).  If the @samp{--force} flag is passed, the condition
+is forcibly defined even when it is invalid for all locations of
+breakpoint @var{number}.
 
 @subsubheading @value{GDBN} Command
 
@@ -30574,7 +30576,7 @@ N.A.
 
 @smallexample
  -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ] [ --qualified ]
-    [ -c @var{condition} ] [ -i @var{ignore-count} ]
+    [ -c @var{condition} ] [ --force-condition ] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ]
 @end smallexample
 
@@ -30630,6 +30632,9 @@ Create a tracepoint.  @xref{Tracepoints}.  When this parameter
 is used together with @samp{-h}, a fast tracepoint is created.
 @item -c @var{condition}
 Make the breakpoint conditional on @var{condition}.
+@item --force-condition
+Forcibly define the breakpoint even if the condition is invalid at
+all of the breakpoint locations.
 @item -i @var{ignore-count}
 Initialize the @var{ignore-count}.
 @item -p @var{thread-id}
@@ -30699,7 +30704,7 @@ times="0"@}]@}
 
 @smallexample
  -dprintf-insert [ -t ] [ -f ] [ -d ] [ --qualified ]
-    [ -c @var{condition} ] [ -i @var{ignore-count} ]
+    [ -c @var{condition} ] [--force-condition] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ] [ @var{format} ]
     [ @var{argument} ]
 @end smallexample
@@ -30724,6 +30729,9 @@ cannot be parsed.
 Create a disabled breakpoint.
 @item -c @var{condition}
 Make the breakpoint conditional on @var{condition}.
+@item --force-condition
+Forcibly define the breakpoint even if the condition is invalid at
+all of the breakpoint locations.
 @item -i @var{ignore-count}
 Set the ignore count of the breakpoint (@pxref{Conditions, ignore count})
 to @var{ignore-count}.
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 5a4a62ce8c3..fec75a8da5a 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -183,12 +183,14 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
   int is_explicit = 0;
   struct explicit_location explicit_loc;
   std::string extra_string;
+  bool force_condition = false;
 
   enum opt
     {
       HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
       IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT,
       TRACEPOINT_OPT,
+      FORCE_CONDITION_OPT,
       QUALIFIED_OPT,
       EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
       EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT
@@ -203,6 +205,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
     {"f", PENDING_OPT, 0},
     {"d", DISABLE_OPT, 0},
     {"a", TRACEPOINT_OPT, 0},
+    {"-force-condition", FORCE_CONDITION_OPT, 0},
     {"-qualified", QUALIFIED_OPT, 0},
     {"-source" , EXPLICIT_SOURCE_OPT, 1},
     {"-function", EXPLICIT_FUNC_OPT, 1},
@@ -269,6 +272,9 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 	  is_explicit = 1;
 	  explicit_loc.line_offset = linespec_parse_line_offset (oarg);
 	  break;
+	case FORCE_CONDITION_OPT:
+	  force_condition = true;
+	  break;
 	}
     }
 
@@ -353,7 +359,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 
   create_breakpoint (get_current_arch (), location.get (), condition, thread,
 		     extra_string.c_str (),
-		     false,
+		     force_condition,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,
 		     ignore_count,
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index e46a6cc0ec6..5f1c6810389 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -408,6 +408,30 @@ proc_with_prefix test_explicit_breakpoints {} {
 	".*Source filename requires function, label, or line offset.*"
 }
 
+# Test forcing an invalid condition.
+
+proc_with_prefix test_forced_conditions {} {
+    set warning ".*warning: failed to validate condition .* disabling.*"
+
+    # Define a plain breakpoint first, and a condition later.
+    mi_create_breakpoint "callme" "define a bp" ""
+    mi_gdb_test "-break-condition --force \$bpnum bad" \
+        "${warning}\\^done" \
+        "invalid condition is forced"
+
+    set loc [mi_make_breakpoint_loc -enabled "N"]
+    set args [list -cond "bad" -locations "\\\[$loc\\\]"]
+    set bp [eval mi_make_breakpoint_multi $args]
+
+    mi_gdb_test "-break-insert -c bad --force-condition callme" \
+	"${warning}\\^done,$bp" \
+	"breakpoint with forced condition"
+
+    mi_gdb_test "-dprintf-insert -c bad --force-condition callme 123" \
+        "${warning}\\^done,$bp" \
+        "dprintf with forced condition"
+}
+
 proc test_break {mi_mode} {
     global srcdir subdir binfile
 
@@ -440,6 +464,8 @@ proc test_break {mi_mode} {
     test_abreak_creation
 
     test_explicit_breakpoints
+
+    test_forced_conditions
 }
 
 if [gdb_debug_enabled] {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-21 12:06             ` Aktemur, Tankut Baris
@ 2021-04-21 12:36               ` Simon Marchi
  0 siblings, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2021-04-21 12:36 UTC (permalink / raw)
  To: Aktemur, Tankut Baris, Jonah Graham; +Cc: gdb-patches

On 2021-04-21 8:06 a.m., Aktemur, Tankut Baris wrote:> Simon, the MI's -break-condition command directly uses the CLI's cond command.
> I chose the straightforward solution of skipping the first "-" if the
> argument pointer starts with "--force".  This essentially makes both the CLI
> and the MI command accept both "--force" and "-force".  I thought it'd be good
> to have this flexibility.  The alternative is to parse the MI argument strictly
> for "--".

I disagree, I don't see how this flexibility is useful, and it just puts
an unnecessary burden on future maintainership, needing to support
both going forward.  I think we should accept just the one that respects
the convention for each interpreter.

GDB has not been very good historically w.r.t concistency in how it
accepts flags and arguments, I think we should strive to do better.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v3 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations
  2021-04-21 12:17         ` [PATCH v3 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
@ 2021-04-21 12:48           ` Eli Zaretskii
  0 siblings, 0 replies; 103+ messages in thread
From: Eli Zaretskii @ 2021-04-21 12:48 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

> Date: Wed, 21 Apr 2021 14:17:39 +0200
> From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> 
> gdb/ChangeLog:
> 2021-04-08  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* breakpoint.c (print_one_breakpoint_location): Display "N" for
> 	disabled-by-condition locations on MI-like output.
> 	(breakpoint_1): Do not display the disabled-by-condition footnote
> 	if the output is MI-like.
> 
> gdb/doc/ChangeLog:
> 2021-04-08  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.texinfo (GDB/MI Breakpoint Information): Update the
> 	description for the 'enabled' field of breakpoint locations.

OK for the documentation part, thanks.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-21 12:17         ` [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
@ 2021-04-21 12:50           ` Eli Zaretskii
  2021-04-21 13:37           ` Simon Marchi
  1 sibling, 0 replies; 103+ messages in thread
From: Eli Zaretskii @ 2021-04-21 12:50 UTC (permalink / raw)
  To: Tankut Baris Aktemur; +Cc: gdb-patches

> Date: Wed, 21 Apr 2021 14:17:42 +0200
> From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org>
> 
> gdb/ChangeLog:
> 2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Recognize the
> 	'--force-condition' flag to force the condition in the
> 	'-break-insert' and '-dprintf-insert' commands.
> 	* breakpoint.c (condition_command): Consider having "--force"
> 	as the argument and normalize to "-force".
> 	* NEWS: Mention the change.
> 
> gdb/testsuite/ChangeLog:
> 2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.mi/mi-break.exp (test_forced_conditions): New proc that
> 	is called by the test.
> 
> gdb/doc/ChangeLog:
> 2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.texinfo (GDB/MI Breakpoint Commands): Mention the
> 	'--force-condition' flag of the '-break-insert' and
> 	'-dprintf-insert' commands, and the '--force' flag of the
> 	'-break-condition' command.

Thanks, the documentation parts are OK.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v3 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-21 12:17         ` [PATCH v3 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
@ 2021-04-21 13:18           ` Simon Marchi
  2021-04-21 13:29             ` Aktemur, Tankut Baris
  0 siblings, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2021-04-21 13:18 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches

On 2021-04-21 8:17 a.m., Tankut Baris Aktemur wrote:> The 'create_breakpoint' function takes a 'parse_extra' argument that
> determines whether the condition, thread, and force-condition
> specifiers should be parsed from the extra string or be used from the
> function arguments.  However, for the case when 'parse_extra' is
> false, there is no way to pass the force-condition specifier.  This
> patch adds it as a new argument.
> 
> Also, in the case when parse_extra is false, the current behavior is
> as if the condition is being forced.  This is a bug.  The default
> behavior should reject the breakpoint.  See below for a demo of this
> incorrect behavior.  (The MI command '-break-insert' uses the
> 'create_breakpoint' function with parse_extra=0.)
> 
>   $ gdb -q --interpreter=mi3 /tmp/simple
>   =thread-group-added,id="i1"
>   =cmd-param-changed,param="history save",value="on"
>   =cmd-param-changed,param="auto-load safe-path",value="/"
>   ~"Reading symbols from /tmp/simple...\n"
>   (gdb)
>   -break-insert -c junk -f main
>   &"warning: failed to validate condition at location 1, disabling:\n  "
>   &"No symbol \"junk\" in current context.\n"
>   ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main",locations=[{number="1.1",enabled="N",addr="0x000000000000114e",func="main",file="/tmp/simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}]}
>   (gdb)
>   break main if junk
>   &"break main if junk\n"
>   &"No symbol \"junk\" in current context.\n"
>   ^error,msg="No symbol \"junk\" in current context."
>   (gdb)
>   break main -force-condition if junk
>   &"break main -force-condition if junk\n"
>   ~"Note: breakpoint 1 also set at pc 0x114e.\n"
>   &"warning: failed to validate condition at location 1, disabling:\n  "
>   &"No symbol \"junk\" in current context.\n"
>   ~"Breakpoint 2 at 0x114e: file /tmp/simple.c, line 2.\n"
>   =breakpoint-created,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="junk",times="0",original-location="main",locations=[{number="2.1",enabled="N",addr="0x000000000000114e",func="main",file="/tmp/simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}]}
>   ^done
>   (gdb)
> 
> After applying this patch, we get the behavior below:
> 
>   (gdb)
>   -break-insert -c junk -f main
>   ^error,msg="No symbol \"junk\" in current context."
> 
> This restores the behavior that is present in the existing releases.
> 
> gdb/ChangeLog:
> 2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* breakpoint.h (create_breakpoint): Add a new parameter,
> 	'force_condition'.
> 	* breakpoint.c (create_breakpoint): Use the 'force_condition'
> 	argument when 'parse_extra' is false to check if the condition
> 	is invalid at all of the breakpoint locations.
> 	Update the users below.
> 	(break_command_1)
> 	(dprintf_command)
> 	(trace_command)
> 	(ftrace_command)
> 	(strace_command)
> 	(create_tracepoint_from_upload): Update.
> 	* guile/scm-breakpoint.c (gdbscm_register_breakpoint_x): Update.
> 	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Update.
> 	* python/py-breakpoint.c (bppy_init): Update.
> 	* python/py-finishbreakpoint.c (bpfinishpy_init): Update.
> 
> gdb/testsuite/ChangeLog:
> 2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.mi/mi-break.exp: Extend with checks for invalid breakpoint
> 	conditions.

Up to this patch, it all LGTM and I think it could be merged right away.

Thanks,

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v3 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-21 13:18           ` Simon Marchi
@ 2021-04-21 13:29             ` Aktemur, Tankut Baris
  2021-04-21 14:28               ` Simon Marchi
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-21 13:29 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Wednesday, April 21, 2021 3:19 PM, Simon Marchi wrote:
> On 2021-04-21 8:17 a.m., Tankut Baris Aktemur wrote:> The 'create_breakpoint' function takes
> a 'parse_extra' argument that
> > determines whether the condition, thread, and force-condition
> > specifiers should be parsed from the extra string or be used from the
> > function arguments.  However, for the case when 'parse_extra' is
> > false, there is no way to pass the force-condition specifier.  This
> > patch adds it as a new argument.
> >
> > Also, in the case when parse_extra is false, the current behavior is
> > as if the condition is being forced.  This is a bug.  The default
> > behavior should reject the breakpoint.  See below for a demo of this
> > incorrect behavior.  (The MI command '-break-insert' uses the
> > 'create_breakpoint' function with parse_extra=0.)
> >
> >   $ gdb -q --interpreter=mi3 /tmp/simple
> >   =thread-group-added,id="i1"
> >   =cmd-param-changed,param="history save",value="on"
> >   =cmd-param-changed,param="auto-load safe-path",value="/"
> >   ~"Reading symbols from /tmp/simple...\n"
> >   (gdb)
> >   -break-insert -c junk -f main
> >   &"warning: failed to validate condition at location 1, disabling:\n  "
> >   &"No symbol \"junk\" in current context.\n"
> >
> ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="jun
> k",times="0",original-
> location="main",locations=[{number="1.1",enabled="N",addr="0x000000000000114e",func="main",f
> ile="/tmp/simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}]}
> >   (gdb)
> >   break main if junk
> >   &"break main if junk\n"
> >   &"No symbol \"junk\" in current context.\n"
> >   ^error,msg="No symbol \"junk\" in current context."
> >   (gdb)
> >   break main -force-condition if junk
> >   &"break main -force-condition if junk\n"
> >   ~"Note: breakpoint 1 also set at pc 0x114e.\n"
> >   &"warning: failed to validate condition at location 1, disabling:\n  "
> >   &"No symbol \"junk\" in current context.\n"
> >   ~"Breakpoint 2 at 0x114e: file /tmp/simple.c, line 2.\n"
> >   =breakpoint-
> created,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="<MULTIPLE>",cond="j
> unk",times="0",original-
> location="main",locations=[{number="2.1",enabled="N",addr="0x000000000000114e",func="main",f
> ile="/tmp/simple.c",fullname="/tmp/simple.c",line="2",thread-groups=["i1"]}]}
> >   ^done
> >   (gdb)
> >
> > After applying this patch, we get the behavior below:
> >
> >   (gdb)
> >   -break-insert -c junk -f main
> >   ^error,msg="No symbol \"junk\" in current context."
> >
> > This restores the behavior that is present in the existing releases.
> >
> > gdb/ChangeLog:
> > 2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> >
> > 	* breakpoint.h (create_breakpoint): Add a new parameter,
> > 	'force_condition'.
> > 	* breakpoint.c (create_breakpoint): Use the 'force_condition'
> > 	argument when 'parse_extra' is false to check if the condition
> > 	is invalid at all of the breakpoint locations.
> > 	Update the users below.
> > 	(break_command_1)
> > 	(dprintf_command)
> > 	(trace_command)
> > 	(ftrace_command)
> > 	(strace_command)
> > 	(create_tracepoint_from_upload): Update.
> > 	* guile/scm-breakpoint.c (gdbscm_register_breakpoint_x): Update.
> > 	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Update.
> > 	* python/py-breakpoint.c (bppy_init): Update.
> > 	* python/py-finishbreakpoint.c (bpfinishpy_init): Update.
> >
> > gdb/testsuite/ChangeLog:
> > 2021-04-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> >
> > 	* gdb.mi/mi-break.exp: Extend with checks for invalid breakpoint
> > 	conditions.
> 
> Up to this patch, it all LGTM and I think it could be merged right away.
> 
> Thanks,
> 
> Simon

Just to make sure, did you mean "up to and including this patch"?

-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-21 12:17         ` [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
  2021-04-21 12:50           ` Eli Zaretskii
@ 2021-04-21 13:37           ` Simon Marchi
  2021-04-21 13:49             ` Aktemur, Tankut Baris
  1 sibling, 1 reply; 103+ messages in thread
From: Simon Marchi @ 2021-04-21 13:37 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches

> diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
> index e46a6cc0ec6..5f1c6810389 100644
> --- a/gdb/testsuite/gdb.mi/mi-break.exp
> +++ b/gdb/testsuite/gdb.mi/mi-break.exp
> @@ -408,6 +408,30 @@ proc_with_prefix test_explicit_breakpoints {} {
>  	".*Source filename requires function, label, or line offset.*"
>  }
>  
> +# Test forcing an invalid condition.
> +
> +proc_with_prefix test_forced_conditions {} {
> +    set warning ".*warning: failed to validate condition .* disabling.*"
> +
> +    # Define a plain breakpoint first, and a condition later.
> +    mi_create_breakpoint "callme" "define a bp" ""
> +    mi_gdb_test "-break-condition --force \$bpnum bad" \
> +        "${warning}\\^done" \
> +        "invalid condition is forced"

This literally sends

  -break-condition --force $bpnum bad

But I don't understand what $bpnum refers to, can you explain?  I'm a bit lost.

> +
> +    set loc [mi_make_breakpoint_loc -enabled "N"]
> +    set args [list -cond "bad" -locations "\\\[$loc\\\]"]
> +    set bp [eval mi_make_breakpoint_multi $args]
> +
> +    mi_gdb_test "-break-insert -c bad --force-condition callme" \
> +	"${warning}\\^done,$bp" \
> +	"breakpoint with forced condition"

👍 (are we allowed emojis here?)

> +
> +    mi_gdb_test "-dprintf-insert -c bad --force-condition callme 123" \
> +        "${warning}\\^done,$bp" \
> +        "dprintf with forced condition"

It's really just a nit because it doesn't affect the test, but a dprintf
would normally take a format string, so I guess you meant:

  -dprintf-insert -c bad --force-condition callme "%d" 123

Or something like that.

So the patch pretty much LGTM, except the --force vs -force issue
mentioned in my other message.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-21 13:37           ` Simon Marchi
@ 2021-04-21 13:49             ` Aktemur, Tankut Baris
  2021-04-21 14:26               ` Simon Marchi
  0 siblings, 1 reply; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-21 13:49 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Wednesday, April 21, 2021 3:37 PM, Simon Marchi wrote:
> > diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
> > index e46a6cc0ec6..5f1c6810389 100644
> > --- a/gdb/testsuite/gdb.mi/mi-break.exp
> > +++ b/gdb/testsuite/gdb.mi/mi-break.exp
> > @@ -408,6 +408,30 @@ proc_with_prefix test_explicit_breakpoints {} {
> >  	".*Source filename requires function, label, or line offset.*"
> >  }
> >
> > +# Test forcing an invalid condition.
> > +
> > +proc_with_prefix test_forced_conditions {} {
> > +    set warning ".*warning: failed to validate condition .* disabling.*"
> > +
> > +    # Define a plain breakpoint first, and a condition later.
> > +    mi_create_breakpoint "callme" "define a bp" ""
> > +    mi_gdb_test "-break-condition --force \$bpnum bad" \
> > +        "${warning}\\^done" \
> > +        "invalid condition is forced"
> 
> This literally sends
> 
>   -break-condition --force $bpnum bad
> 
> But I don't understand what $bpnum refers to, can you explain?  I'm a bit lost.

It's GDB's internal variable that refers to the last-defined breakpoint's number.
It was my attempt to avoid hard-coding the breakpoint number.
 
> > +
> > +    set loc [mi_make_breakpoint_loc -enabled "N"]
> > +    set args [list -cond "bad" -locations "\\\[$loc\\\]"]
> > +    set bp [eval mi_make_breakpoint_multi $args]
> > +
> > +    mi_gdb_test "-break-insert -c bad --force-condition callme" \
> > +	"${warning}\\^done,$bp" \
> > +	"breakpoint with forced condition"
> 
> 👍 (are we allowed emojis here?)
> 
> > +
> > +    mi_gdb_test "-dprintf-insert -c bad --force-condition callme 123" \
> > +        "${warning}\\^done,$bp" \
> > +        "dprintf with forced condition"
> 
> It's really just a nit because it doesn't affect the test, but a dprintf
> would normally take a format string, so I guess you meant:
> 
>   -dprintf-insert -c bad --force-condition callme "%d" 123
> 
> Or something like that.

I meant "123" as a dummy format string that takes no parameters.
I'll convert it to `"%d" 123` to avoid confusion.

> So the patch pretty much LGTM, except the --force vs -force issue
> mentioned in my other message.
> 
> Simon

Thanks, I'll work on that part and send a revision.

-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-21 13:49             ` Aktemur, Tankut Baris
@ 2021-04-21 14:26               ` Simon Marchi
  0 siblings, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2021-04-21 14:26 UTC (permalink / raw)
  To: Aktemur, Tankut Baris, gdb-patches

On 2021-04-21 9:49 a.m., Aktemur, Tankut Baris wrote:> On Wednesday, April 21, 2021 3:37 PM, Simon Marchi wrote:
>>> diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
>>> index e46a6cc0ec6..5f1c6810389 100644
>>> --- a/gdb/testsuite/gdb.mi/mi-break.exp
>>> +++ b/gdb/testsuite/gdb.mi/mi-break.exp
>>> @@ -408,6 +408,30 @@ proc_with_prefix test_explicit_breakpoints {} {
>>>  	".*Source filename requires function, label, or line offset.*"
>>>  }
>>>
>>> +# Test forcing an invalid condition.
>>> +
>>> +proc_with_prefix test_forced_conditions {} {
>>> +    set warning ".*warning: failed to validate condition .* disabling.*"
>>> +
>>> +    # Define a plain breakpoint first, and a condition later.
>>> +    mi_create_breakpoint "callme" "define a bp" ""
>>> +    mi_gdb_test "-break-condition --force \$bpnum bad" \
>>> +        "${warning}\\^done" \
>>> +        "invalid condition is forced"
>>
>> This literally sends
>>
>>   -break-condition --force $bpnum bad
>>
>> But I don't understand what $bpnum refers to, can you explain?  I'm a bit lost.
> 
> It's GDB's internal variable that refers to the last-defined breakpoint's number.
> It was my attempt to avoid hard-coding the breakpoint number.

Ah!  Good idea.  I just didn't remember $bpnum (and will probably forget
it promptly again).

>>> +    mi_gdb_test "-dprintf-insert -c bad --force-condition callme 123" \
>>> +        "${warning}\\^done,$bp" \
>>> +        "dprintf with forced condition"
>>
>> It's really just a nit because it doesn't affect the test, but a dprintf
>> would normally take a format string, so I guess you meant:
>>
>>   -dprintf-insert -c bad --force-condition callme "%d" 123
>>
>> Or something like that.
> 
> I meant "123" as a dummy format string that takes no parameters.
> I'll convert it to `"%d" 123` to avoid confusion.

Ah, makes sense.  Well, what you had is ok.  I'd put it between quotes
just to be clear, or use "Hello" or something.  Not a big deal in any
case.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v3 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint'
  2021-04-21 13:29             ` Aktemur, Tankut Baris
@ 2021-04-21 14:28               ` Simon Marchi
  0 siblings, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2021-04-21 14:28 UTC (permalink / raw)
  To: Aktemur, Tankut Baris, gdb-patches

> Just to make sure, did you mean "up to and including this patch"?

Yes, an inclusive "Up to" :).

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI
  2021-04-21 12:17       ` [PATCH v3 " Tankut Baris Aktemur
                           ` (3 preceding siblings ...)
  2021-04-21 12:17         ` [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
@ 2021-04-22 14:35         ` Tankut Baris Aktemur
  2021-04-22 14:35           ` [PATCH v4 1/2] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
                             ` (2 more replies)
  4 siblings, 3 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-22 14:35 UTC (permalink / raw)
  To: gdb-patches

Hi,

This is a continuation of

  https://sourceware.org/pipermail/gdb-patches/2021-April/177951.html

The first patches of the series are already merged.  This revision
defines "--force-condition" and "--force" flags for the MI's
'-break-insert' and '-break-condition' commands, respectively.

Tankut Baris Aktemur (2):
  gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  gdb/mi: add a '--force' flag to the '-break-condition' command

 gdb/NEWS                          | 15 ++++++++
 gdb/breakpoint.c                  | 59 ++++++++++++++++------------
 gdb/breakpoint.h                  |  8 ++++
 gdb/doc/gdb.texinfo               | 16 ++++++--
 gdb/mi/mi-cmd-break.c             | 64 ++++++++++++++++++++++++++++++-
 gdb/mi/mi-cmds.c                  |  4 +-
 gdb/mi/mi-cmds.h                  |  1 +
 gdb/testsuite/gdb.mi/mi-break.exp | 31 +++++++++++++++
 8 files changed, 166 insertions(+), 32 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v4 1/2] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-22 14:35         ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
@ 2021-04-22 14:35           ` Tankut Baris Aktemur
  2021-05-06  2:40             ` Simon Marchi
  2021-04-22 14:35           ` [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command Tankut Baris Aktemur
  2021-05-05 15:57           ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Aktemur, Tankut Baris
  2 siblings, 1 reply; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-22 14:35 UTC (permalink / raw)
  To: gdb-patches

Add a '--force-condition' flag to the '-break-insert' command to be
able to force conditions.  Because the '-dprintf-insert' command uses
the same mechanism as the '-break-insert' command, it obtains the
'--force-condition' flag, too.

gdb/ChangeLog:
2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Recognize the
	'--force-condition' flag to force the condition in the
	'-break-insert' and '-dprintf-insert' commands.
	* NEWS: Mention the change.

gdb/testsuite/ChangeLog:
2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp (test_forced_conditions): New proc that
	is called by the test.

gdb/doc/ChangeLog:
2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (GDB/MI Breakpoint Commands): Mention the
	'--force-condition' flag of the '-break-insert' and
	'-dprintf-insert' commands.
---
 gdb/NEWS                          |  8 ++++++++
 gdb/doc/gdb.texinfo               | 10 ++++++++--
 gdb/mi/mi-cmd-break.c             |  8 +++++++-
 gdb/testsuite/gdb.mi/mi-break.exp | 20 ++++++++++++++++++++
 4 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index faccf40dd41..72bceb7266f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,14 @@
     equivalent of the CLI's "break -qualified" and "dprintf
     -qualified".
 
+ ** '-break-insert --force-condition' and '-dprintf-insert --force-condition'
+
+    The MI -break-insert and -dprintf-insert commands now support a
+    '--force-condition' flag to forcibly define a condition even when
+    the condition is invalid at all locations of the breakpoint.  This
+    is equivalent to the '-force-condition' flag of the CLI's "break"
+    command.
+
 * GDB now supports core file debugging for x86_64 Cygwin programs.
 
 * GDB will now look for the .gdbinit file in a config directory before
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index fd04aeee8fc..cac7ceb4665 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30681,7 +30681,7 @@ N.A.
 
 @smallexample
  -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ] [ --qualified ]
-    [ -c @var{condition} ] [ -i @var{ignore-count} ]
+    [ -c @var{condition} ] [ --force-condition ] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ]
 @end smallexample
 
@@ -30737,6 +30737,9 @@ Create a tracepoint.  @xref{Tracepoints}.  When this parameter
 is used together with @samp{-h}, a fast tracepoint is created.
 @item -c @var{condition}
 Make the breakpoint conditional on @var{condition}.
+@item --force-condition
+Forcibly define the breakpoint even if the condition is invalid at
+all of the breakpoint locations.
 @item -i @var{ignore-count}
 Initialize the @var{ignore-count}.
 @item -p @var{thread-id}
@@ -30806,7 +30809,7 @@ times="0"@}]@}
 
 @smallexample
  -dprintf-insert [ -t ] [ -f ] [ -d ] [ --qualified ]
-    [ -c @var{condition} ] [ -i @var{ignore-count} ]
+    [ -c @var{condition} ] [--force-condition] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ] [ @var{format} ]
     [ @var{argument} ]
 @end smallexample
@@ -30831,6 +30834,9 @@ cannot be parsed.
 Create a disabled breakpoint.
 @item -c @var{condition}
 Make the breakpoint conditional on @var{condition}.
+@item --force-condition
+Forcibly define the breakpoint even if the condition is invalid at
+all of the breakpoint locations.
 @item -i @var{ignore-count}
 Set the ignore count of the breakpoint (@pxref{Conditions, ignore count})
 to @var{ignore-count}.
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 5a4a62ce8c3..fec75a8da5a 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -183,12 +183,14 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
   int is_explicit = 0;
   struct explicit_location explicit_loc;
   std::string extra_string;
+  bool force_condition = false;
 
   enum opt
     {
       HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
       IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT,
       TRACEPOINT_OPT,
+      FORCE_CONDITION_OPT,
       QUALIFIED_OPT,
       EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
       EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT
@@ -203,6 +205,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
     {"f", PENDING_OPT, 0},
     {"d", DISABLE_OPT, 0},
     {"a", TRACEPOINT_OPT, 0},
+    {"-force-condition", FORCE_CONDITION_OPT, 0},
     {"-qualified", QUALIFIED_OPT, 0},
     {"-source" , EXPLICIT_SOURCE_OPT, 1},
     {"-function", EXPLICIT_FUNC_OPT, 1},
@@ -269,6 +272,9 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 	  is_explicit = 1;
 	  explicit_loc.line_offset = linespec_parse_line_offset (oarg);
 	  break;
+	case FORCE_CONDITION_OPT:
+	  force_condition = true;
+	  break;
 	}
     }
 
@@ -353,7 +359,7 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 
   create_breakpoint (get_current_arch (), location.get (), condition, thread,
 		     extra_string.c_str (),
-		     false,
+		     force_condition,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,
 		     ignore_count,
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index b2db2d41d1f..3b264ecdebd 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -408,6 +408,24 @@ proc_with_prefix test_explicit_breakpoints {} {
 	".*Source filename requires function, label, or line offset.*"
 }
 
+# Test forcing an invalid condition.
+
+proc_with_prefix test_forced_conditions {} {
+    set warning ".*warning: failed to validate condition .* disabling.*"
+
+    set loc [mi_make_breakpoint_loc -enabled "N"]
+    set args [list -cond "bad" -locations "\\\[$loc\\\]"]
+    set bp [eval mi_make_breakpoint_multi $args]
+
+    mi_gdb_test "-break-insert -c bad --force-condition callme" \
+	"${warning}\\^done,$bp" \
+	"breakpoint with forced condition"
+
+    mi_gdb_test "-dprintf-insert -c bad --force-condition callme \"Hello\"" \
+        "${warning}\\^done,$bp" \
+        "dprintf with forced condition"
+}
+
 proc test_break {mi_mode} {
     global srcdir subdir binfile
 
@@ -440,6 +458,8 @@ proc test_break {mi_mode} {
     test_abreak_creation
 
     test_explicit_breakpoints
+
+    test_forced_conditions
 }
 
 if [gdb_debug_enabled] {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command
  2021-04-22 14:35         ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  2021-04-22 14:35           ` [PATCH v4 1/2] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
@ 2021-04-22 14:35           ` Tankut Baris Aktemur
  2021-04-22 14:47             ` Aktemur, Tankut Baris
  2021-05-06  2:46             ` Simon Marchi
  2021-05-05 15:57           ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Aktemur, Tankut Baris
  2 siblings, 2 replies; 103+ messages in thread
From: Tankut Baris Aktemur @ 2021-04-22 14:35 UTC (permalink / raw)
  To: gdb-patches

Add a '--force' flag to the '-break-condition' command to be
able to force conditions.

gdb/ChangeLog:
2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* mi/mi-cmd-break.c (mi_cmd_break_condition): New function.
	* mi/mi-cmds.c: Change the binding of "-break-condition" to
	mi_cmd_break_condition.
	* mi/mi-cmds.h (mi_cmd_break_condition): Declare.
	* breakpoint.h (set_breakpoint_condition): Declare a new
	overload.
	* breakpoint.c (set_breakpoint_condition): New overloaded function
	extracted out from ...
	(condition_command): ... this.
	* NEWS: Mention the change.

gdb/testsuite/ChangeLog:
2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.mi/mi-break.exp (test_forced_conditions): Add a test
	for the -break-condition command's "--force" flag.

gdb/doc/ChangeLog:
2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* gdb.texinfo (GDB/MI Breakpoint Commands): Mention the
	'--force' flag of the '-break-condition' command.
---
 gdb/NEWS                          |  7 ++++
 gdb/breakpoint.c                  | 59 ++++++++++++++++++-------------
 gdb/breakpoint.h                  |  8 +++++
 gdb/doc/gdb.texinfo               |  6 ++--
 gdb/mi/mi-cmd-break.c             | 56 +++++++++++++++++++++++++++++
 gdb/mi/mi-cmds.c                  |  4 +--
 gdb/mi/mi-cmds.h                  |  1 +
 gdb/testsuite/gdb.mi/mi-break.exp | 11 ++++++
 8 files changed, 123 insertions(+), 29 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 72bceb7266f..27429280aa5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -39,6 +39,13 @@
     is equivalent to the '-force-condition' flag of the CLI's "break"
     command.
 
+ ** '-break-condition --force'
+
+    The MI -break-condition command now supports a '--force' flag to
+    forcibly define a condition even when the condition is invalid at
+    all locations of the selected breakpoint.  This is equivalent to
+    the '-force' flag of the CLI's "cond" command.
+
 * GDB now supports core file debugging for x86_64 Cygwin programs.
 
 * GDB will now look for the .gdbinit file in a config directory before
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index c2d0ffba974..22899ca9117 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -973,6 +973,39 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
   gdb::observers::breakpoint_modified.notify (b);
 }
 
+/* See breakpoint.h.  */
+
+void
+set_breakpoint_condition (int bpnum, const char *exp, int from_tty,
+			  bool force)
+{
+  struct breakpoint *b;
+  ALL_BREAKPOINTS (b)
+    if (b->number == bpnum)
+      {
+	/* Check if this breakpoint has a "stop" method implemented in an
+	   extension language.  This method and conditions entered into GDB
+	   from the CLI are mutually exclusive.  */
+	const struct extension_language_defn *extlang
+	  = get_breakpoint_cond_ext_lang (b, EXT_LANG_NONE);
+
+	if (extlang != NULL)
+	  {
+	    error (_("Only one stop condition allowed.  There is currently"
+		     " a %s stop condition defined for this breakpoint."),
+		   ext_lang_capitalized_name (extlang));
+	  }
+	set_breakpoint_condition (b, exp, from_tty, force);
+
+	if (is_breakpoint (b))
+	  update_global_location_list (UGLL_MAY_INSERT);
+
+	return;
+      }
+
+  error (_("No breakpoint number %d."), bpnum);
+}
+
 /* The options for the "condition" command.  */
 
 struct condition_command_opts
@@ -1066,7 +1099,6 @@ condition_completer (struct cmd_list_element *cmd,
 static void
 condition_command (const char *arg, int from_tty)
 {
-  struct breakpoint *b;
   const char *p;
   int bnum;
 
@@ -1085,30 +1117,7 @@ condition_command (const char *arg, int from_tty)
   if (bnum == 0)
     error (_("Bad breakpoint argument: '%s'"), arg);
 
-  ALL_BREAKPOINTS (b)
-    if (b->number == bnum)
-      {
-	/* Check if this breakpoint has a "stop" method implemented in an
-	   extension language.  This method and conditions entered into GDB
-	   from the CLI are mutually exclusive.  */
-	const struct extension_language_defn *extlang
-	  = get_breakpoint_cond_ext_lang (b, EXT_LANG_NONE);
-
-	if (extlang != NULL)
-	  {
-	    error (_("Only one stop condition allowed.  There is currently"
-		     " a %s stop condition defined for this breakpoint."),
-		   ext_lang_capitalized_name (extlang));
-	  }
-	set_breakpoint_condition (b, p, from_tty, cc_opts.force_condition);
-
-	if (is_breakpoint (b))
-	  update_global_location_list (UGLL_MAY_INSERT);
-
-	return;
-      }
-
-  error (_("No breakpoint number %d."), bnum);
+  set_breakpoint_condition (bnum, p, from_tty, cc_opts.force_condition);
 }
 
 /* Check that COMMAND do not contain commands that are suitable
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index ded498f5562..2925f77df56 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1657,6 +1657,14 @@ extern void breakpoint_retire_moribund (void);
 extern void set_breakpoint_condition (struct breakpoint *b, const char *exp,
 				      int from_tty, bool force);
 
+/* Set break condition for the breakpoint with number BPNUM to EXP.
+   Raise an error if no breakpoint with the given number is found.
+   Also raise an error if the breakpoint already has stop conditions.
+   If FORCE, define the condition even if it is invalid in
+   all of the breakpoint locations.  */
+extern void set_breakpoint_condition (int bpnum, const char *exp,
+				      int from_tty, bool force);
+
 /* Checks if we are catching syscalls or not.
    Returns 0 if not, greater than 0 if we are.  */
 extern int catch_syscall_enabled (void);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index cac7ceb4665..a7e045b0544 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30509,13 +30509,15 @@ times="0"@}
 @subsubheading Synopsis
 
 @smallexample
- -break-condition @var{number} @var{expr}
+ -break-condition [ --force ] @var{number} @var{expr}
 @end smallexample
 
 Breakpoint @var{number} will stop the program only if the condition in
 @var{expr} is true.  The condition becomes part of the
 @samp{-break-list} output (see the description of the @samp{-break-list}
-command below).
+command below).  If the @samp{--force} flag is passed, the condition
+is forcibly defined even when it is invalid for all locations of
+breakpoint @var{number}.
 
 @subsubheading @value{GDBN} Command
 
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index fec75a8da5a..1a217ecab03 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -385,6 +385,62 @@ mi_cmd_dprintf_insert (const char *command, char **argv, int argc)
   mi_cmd_break_insert_1 (1, command, argv, argc);
 }
 
+/* Implements the -break-condition command.
+   See the MI manual for the list of options.  */
+
+void
+mi_cmd_break_condition (const char *command, char **argv, int argc)
+{
+  enum option
+    {
+      FORCE_CONDITION_OPT,
+    };
+
+  static const struct mi_opt opts[] =
+  {
+    {"-force", FORCE_CONDITION_OPT, 0},
+    { 0, 0, 0 }
+  };
+
+  /* Parse arguments.  */
+  int oind = 0;
+  char *oarg;
+  bool force_condition = false;
+
+  while (true)
+    {
+      int opt = mi_getopt ("-break-condition", argc, argv,
+			   opts, &oind, &oarg);
+      if (opt < 0)
+	break;
+
+      switch (opt)
+	{
+	case FORCE_CONDITION_OPT:
+	  force_condition = true;
+	  break;
+	}
+    }
+
+  /* There must be at least two more args: a bpnum and a condition
+     expression.  */
+  if (oind + 1 >= argc)
+    error (_("-break-condition: Missing arguments"));
+
+  int bpnum = atoi (argv[oind]);
+
+  /* The rest form the condition expr.  */
+  std::string expr (argv[oind + 1]);
+  for (int i = oind + 2; i < argc; ++i)
+    {
+      expr += " ";
+      expr += argv[i];
+    }
+
+  set_breakpoint_condition (bpnum, expr.c_str (), 0 /* from_tty */,
+			    force_condition);
+}
+
 enum wp_type
 {
   REG_WP,
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index df4290ae5dc..1ed8b6f9126 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -45,8 +45,8 @@ static struct mi_cmd mi_cmds[] =
   DEF_MI_CMD_MI ("add-inferior", mi_cmd_add_inferior),
   DEF_MI_CMD_CLI_1 ("break-after", "ignore", 1,
 		    &mi_suppress_notification.breakpoint),
-  DEF_MI_CMD_CLI_1 ("break-condition","cond", 1,
-		  &mi_suppress_notification.breakpoint),
+  DEF_MI_CMD_MI_1 ("break-condition", mi_cmd_break_condition,
+		   &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_MI_1 ("break-commands", mi_cmd_break_commands,
 		   &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_CLI_1 ("break-delete", "delete breakpoint", 1,
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 4c05a4734a8..8da2e393919 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -36,6 +36,7 @@ extern mi_cmd_argv_ftype mi_cmd_ada_task_info;
 extern mi_cmd_argv_ftype mi_cmd_add_inferior;
 extern mi_cmd_argv_ftype mi_cmd_break_insert;
 extern mi_cmd_argv_ftype mi_cmd_dprintf_insert;
+extern mi_cmd_argv_ftype mi_cmd_break_condition;
 extern mi_cmd_argv_ftype mi_cmd_break_commands;
 extern mi_cmd_argv_ftype mi_cmd_break_passcount;
 extern mi_cmd_argv_ftype mi_cmd_break_watch;
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index 3b264ecdebd..b6ef3483004 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -424,6 +424,17 @@ proc_with_prefix test_forced_conditions {} {
     mi_gdb_test "-dprintf-insert -c bad --force-condition callme \"Hello\"" \
         "${warning}\\^done,$bp" \
         "dprintf with forced condition"
+
+    # Define a plain breakpoint first, and a condition later.
+    mi_create_breakpoint "callme" "define a bp" ""
+    mi_gdb_test "-break-condition --force 16 bad == 42" \
+        "${warning}\\^done" \
+        "invalid condition is forced"
+    set args [list -cond "bad == 42" -locations "\\\[$loc\\\]"]
+    set bp [eval mi_make_breakpoint_multi $args]
+    mi_gdb_test "-break-info 16" \
+	"\\^done,[mi_make_breakpoint_table [list $bp]]" \
+        "invalid condition is defined"
 }
 
 proc test_break {mi_mode} {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command
  2021-04-22 14:35           ` [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command Tankut Baris Aktemur
@ 2021-04-22 14:47             ` Aktemur, Tankut Baris
  2021-05-06  2:46             ` Simon Marchi
  1 sibling, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-04-22 14:47 UTC (permalink / raw)
  To: gdb-patches

On Thursday, April 22, 2021 4:36 PM, Aktemur, Tankut Baris wrote:
> Add a '--force' flag to the '-break-condition' command to be
> able to force conditions.
> 
> gdb/ChangeLog:
> 2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* mi/mi-cmd-break.c (mi_cmd_break_condition): New function.
> 	* mi/mi-cmds.c: Change the binding of "-break-condition" to
> 	mi_cmd_break_condition.
> 	* mi/mi-cmds.h (mi_cmd_break_condition): Declare.
> 	* breakpoint.h (set_breakpoint_condition): Declare a new
> 	overload.
> 	* breakpoint.c (set_breakpoint_condition): New overloaded function
> 	extracted out from ...
> 	(condition_command): ... this.
> 	* NEWS: Mention the change.
> 
> gdb/testsuite/ChangeLog:
> 2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.mi/mi-break.exp (test_forced_conditions): Add a test
> 	for the -break-condition command's "--force" flag.
> 
> gdb/doc/ChangeLog:
> 2021-04-21  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
> 
> 	* gdb.texinfo (GDB/MI Breakpoint Commands): Mention the
> 	'--force' flag of the '-break-condition' command.

> diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
> index 3b264ecdebd..b6ef3483004 100644
> --- a/gdb/testsuite/gdb.mi/mi-break.exp
> +++ b/gdb/testsuite/gdb.mi/mi-break.exp
> @@ -424,6 +424,17 @@ proc_with_prefix test_forced_conditions {} {
>      mi_gdb_test "-dprintf-insert -c bad --force-condition callme \"Hello\"" \
>          "${warning}\\^done,$bp" \
>          "dprintf with forced condition"
> +
> +    # Define a plain breakpoint first, and a condition later.
> +    mi_create_breakpoint "callme" "define a bp" ""
> +    mi_gdb_test "-break-condition --force 16 bad == 42" \

In the previous revision I was using $bpnum to avoid having to
hard-code the breakpoint number.  This was fine because the command
arguments were being passed to the CLI command's function directly.
The CLI command parses and converts $bpnum to an integer.
Here, I had to hardcode the number, which is common in this test file.

Thanks
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI
  2021-04-22 14:35         ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
  2021-04-22 14:35           ` [PATCH v4 1/2] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
  2021-04-22 14:35           ` [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command Tankut Baris Aktemur
@ 2021-05-05 15:57           ` Aktemur, Tankut Baris
  2 siblings, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-05-05 15:57 UTC (permalink / raw)
  To: gdb-patches, simon.marchi

On Thursday, April 22, 2021 4:36 PM, Aktemur, Tankut Baris wrote:
> Hi,
> 
> This is a continuation of
> 
>   https://sourceware.org/pipermail/gdb-patches/2021-April/177951.html
> 
> The first patches of the series are already merged.  This revision
> defines "--force-condition" and "--force" flags for the MI's
> '-break-insert' and '-break-condition' commands, respectively.

Kindly pinging.

Thanks.
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 1/2] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd
  2021-04-22 14:35           ` [PATCH v4 1/2] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
@ 2021-05-06  2:40             ` Simon Marchi
  0 siblings, 0 replies; 103+ messages in thread
From: Simon Marchi @ 2021-05-06  2:40 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches

On 2021-04-22 10:35 a.m., Tankut Baris Aktemur wrote:
> Add a '--force-condition' flag to the '-break-insert' command to be
> able to force conditions.  Because the '-dprintf-insert' command uses
> the same mechanism as the '-break-insert' command, it obtains the
> '--force-condition' flag, too.

LGTM, thanks.

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command
  2021-04-22 14:35           ` [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command Tankut Baris Aktemur
  2021-04-22 14:47             ` Aktemur, Tankut Baris
@ 2021-05-06  2:46             ` Simon Marchi
  2021-05-06  8:50               ` Aktemur, Tankut Baris
  2021-07-11 18:51               ` Jonah Graham
  1 sibling, 2 replies; 103+ messages in thread
From: Simon Marchi @ 2021-05-06  2:46 UTC (permalink / raw)
  To: Tankut Baris Aktemur, gdb-patches

> +  /* There must be at least two more args: a bpnum and a condition
> +     expression.  */
> +  if (oind + 1 >= argc)
> +    error (_("-break-condition: Missing arguments"));

I don't know what the standard is for MI commands, but it would be handy
for somebody trying this by hand to say what are the expected arguments
in the error message.

Otherwise, LGTM, thanks!

Simon

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command
  2021-05-06  2:46             ` Simon Marchi
@ 2021-05-06  8:50               ` Aktemur, Tankut Baris
  2021-07-11 18:51               ` Jonah Graham
  1 sibling, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-05-06  8:50 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On Thursday, May 6, 2021 4:47 AM, Simon Marchi wrote:
> > +  /* There must be at least two more args: a bpnum and a condition
> > +     expression.  */
> > +  if (oind + 1 >= argc)
> > +    error (_("-break-condition: Missing arguments"));
> 
> I don't know what the standard is for MI commands, but it would be handy
> for somebody trying this by hand to say what are the expected arguments
> in the error message.
> 
> Otherwise, LGTM, thanks!
> 
> Simon

I updated the error message and pushed both patches.
Thanks!

-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command
  2021-05-06  2:46             ` Simon Marchi
  2021-05-06  8:50               ` Aktemur, Tankut Baris
@ 2021-07-11 18:51               ` Jonah Graham
  2021-07-12  0:25                 ` Jonah Graham
  2021-07-12  8:33                 ` Aktemur, Tankut Baris
  1 sibling, 2 replies; 103+ messages in thread
From: Jonah Graham @ 2021-07-11 18:51 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tankut Baris Aktemur, gdb-patches

On Wed, 5 May 2021 at 22:46, Simon Marchi <simon.marchi@polymtl.ca> wrote:

> > +  /* There must be at least two more args: a bpnum and a condition
> > +     expression.  */
> > +  if (oind + 1 >= argc)
> > +    error (_("-break-condition: Missing arguments"));
>
> I don't know what the standard is for MI commands, but it would be handy
> for somebody trying this by hand to say what are the expected arguments
> in the error message.
>

Hi Baris and Simon,

Sorry I didn't catch this earlier, but this change breaks removing
conditions from MI. "-break-condition 2" should remove the condition for
breakpoint 2, same as "condition 2" at CLI does. Instead an error message
is returned:

^error,msg="-break-condition: Missing the <number> and/or <expr> argument"

which corresponds to the updated error message that was actually committed.

I raised https://sourceware.org/bugzilla/show_bug.cgi?id=28076 to track
this.

Jonah





>
> Otherwise, LGTM, thanks!
>
> Simon
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command
  2021-07-11 18:51               ` Jonah Graham
@ 2021-07-12  0:25                 ` Jonah Graham
  2021-07-12  8:33                 ` Aktemur, Tankut Baris
  1 sibling, 0 replies; 103+ messages in thread
From: Jonah Graham @ 2021-07-12  0:25 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tankut Baris Aktemur, gdb-patches

~~~
Jonah Graham
Kichwa Coders
www.kichwacoders.com


On Sun, 11 Jul 2021 at 14:51, Jonah Graham <jonah@kichwacoders.com> wrote:

> On Wed, 5 May 2021 at 22:46, Simon Marchi <simon.marchi@polymtl.ca> wrote:
>
>> > +  /* There must be at least two more args: a bpnum and a condition
>> > +     expression.  */
>> > +  if (oind + 1 >= argc)
>> > +    error (_("-break-condition: Missing arguments"));
>>
>> I don't know what the standard is for MI commands, but it would be handy
>> for somebody trying this by hand to say what are the expected arguments
>> in the error message.
>>
>
> Hi Baris and Simon,
>
> Sorry I didn't catch this earlier, but this change breaks removing
> conditions from MI. "-break-condition 2" should remove the condition for
> breakpoint 2, same as "condition 2" at CLI does. Instead an error message
> is returned:
>
> ^error,msg="-break-condition: Missing the <number> and/or <expr> argument"
>
> which corresponds to the updated error message that was actually committed.
>
> I raised https://sourceware.org/bugzilla/show_bug.cgi?id=28076 to track
> this.
>
> Jonah
>


PS. If you have a patch that you want me to run the Eclipse CDT testsuite
on, please cc me on the patch.

Jonah


>
>
>
>
>
>>
>> Otherwise, LGTM, thanks!
>>
>> Simon
>>
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* RE: [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command
  2021-07-11 18:51               ` Jonah Graham
  2021-07-12  0:25                 ` Jonah Graham
@ 2021-07-12  8:33                 ` Aktemur, Tankut Baris
  1 sibling, 0 replies; 103+ messages in thread
From: Aktemur, Tankut Baris @ 2021-07-12  8:33 UTC (permalink / raw)
  To: Jonah Graham; +Cc: gdb-patches, Simon Marchi

On Sunday, July 11, 2021 8:52 PM, Jonah Graham wrote:
> > On Wed, 5 May 2021 at 22:46, Simon Marchi <mailto:simon.marchi@polymtl.ca> wrote:
> > > +  /* There must be at least two more args: a bpnum and a condition
> > > +     expression.  */
> > > +  if (oind + 1 >= argc)
> > > +    error (_("-break-condition: Missing arguments"));
> >
> > I don't know what the standard is for MI commands, but it would be handy
> > for somebody trying this by hand to say what are the expected arguments
> > in the error message.
>
> Hi Baris and Simon,
>
> Sorry I didn't catch this earlier, but this change breaks removing conditions from MI. "-break-condition 2" should remove the condition for breakpoint 2, same as "condition 2" at CLI does\
. Instead an error message is returned:
>
> ^error,msg="-break-condition: Missing the <number> and/or <expr> argument"
>
> which corresponds to the updated error message that was actually committed.
>
> I raised https://sourceware.org/bugzilla/show_bug.cgi?id=28076 to track this.
>
> Jonah

Hi Jonah,

Sorry about this breakage.  I had implemented the behavior according to
the document, where the command was specified as

  -break-condition @var{number} @var{expr}

The 'expr' argument had seemed mandatory together with 'number'.  I conclude
that this is an oversight in the documentation because otherwise there is no
way to clear an existing breakpoint condition, as far as I know.  The 
-break-condition command was originally delegating all the arguments to the
CLI's "cond" command.  So, erasing a condition simply worked back then.

I submitted a patch to address the problem:
https://sourceware.org/pipermail/gdb-patches/2021-July/180818.html

Would you have a chance to test it?

Thanks
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 103+ messages in thread

end of thread, other threads:[~2021-07-12  8:33 UTC | newest]

Thread overview: 103+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-31 15:42 [PATCH 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
     [not found] ` <cover.1596209606.git.tankut.baris.aktemur@intel.com>
2020-07-31 15:42   ` [PATCH 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
2020-07-31 15:42   ` [RFC][PATCH 2/2] gdb/breakpoint: add a '-force' flag to the 'condition' command Tankut Baris Aktemur
2020-08-03 10:28     ` Andrew Burgess
2020-08-20 21:24 ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
2020-08-20 21:24   ` [PATCH v2 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
2020-09-19  3:05     ` Simon Marchi
2020-09-25 15:49       ` Aktemur, Tankut Baris
2020-09-25 16:10         ` Simon Marchi
2020-09-25 18:15           ` Aktemur, Tankut Baris
2020-10-13 12:24             ` Aktemur, Tankut Baris
2020-08-20 21:24   ` [PATCH v2 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
2020-09-04 11:02   ` [PATCH v2 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
2020-09-11 11:56   ` Tankut Baris Aktemur
2020-09-18 20:36   ` [PING][PATCH " Tankut Baris Aktemur
2020-09-25 15:51 ` [PATCH v3 " Tankut Baris Aktemur
2020-09-25 15:51   ` [PATCH v3 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
2020-09-25 15:51   ` [PATCH v3 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
2020-10-13 12:25 ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Tankut Baris Aktemur
2020-10-13 12:25   ` [PATCH v4 1/2] gdb/breakpoint: disable a bp location if condition is invalid at that location Tankut Baris Aktemur
2020-10-13 15:06     ` Eli Zaretskii
2020-10-13 15:17       ` Aktemur, Tankut Baris
2020-10-16 22:20     ` Simon Marchi
2020-10-13 12:25   ` [PATCH v4 2/2] gdb/breakpoint: add flags to 'condition' and 'break' commands to force condition Tankut Baris Aktemur
2020-10-13 15:08     ` Eli Zaretskii
2020-10-13 15:46       ` Aktemur, Tankut Baris
2020-10-13 16:12         ` Eli Zaretskii
2020-10-16 22:45     ` Simon Marchi
2020-10-19 13:58       ` Aktemur, Tankut Baris
2020-10-19 14:07         ` Simon Marchi
2020-10-27 10:13         ` Aktemur, Tankut Baris
2020-10-29 10:10           ` Tom de Vries
2020-10-29 10:30             ` Aktemur, Tankut Baris
2020-10-29 17:30     ` Pedro Alves
2020-11-10 19:33       ` Aktemur, Tankut Baris
2020-12-05 17:30         ` Pedro Alves
2020-12-10 20:30           ` Tom Tromey
2020-12-15 11:20             ` Aktemur, Tankut Baris
2020-11-10 19:51       ` Aktemur, Tankut Baris
2020-10-28 16:57   ` [PATCH v4 0/2] Breakpoint conditions at locations with differing contexts Gary Benson
2020-10-29  7:43     ` Aktemur, Tankut Baris
2021-04-05 17:45 ` [PATCH " Jonah Graham
2021-04-06 14:11   ` Aktemur, Tankut Baris
2021-04-06 14:37     ` Jonah Graham
2021-04-07  7:09       ` Aktemur, Tankut Baris
2021-04-07 11:26         ` Jonah Graham
2021-04-07 14:55   ` [PATCH 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
2021-04-07 14:55     ` [PATCH 1/4] gdb/doc: update the 'enabled' field's description for BP locations in MI Tankut Baris Aktemur
2021-04-07 15:15       ` Eli Zaretskii
2021-04-07 21:42       ` Simon Marchi
2021-04-07 14:55     ` [PATCH 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
2021-04-07 21:49       ` Simon Marchi
2021-04-07 14:55     ` [PATCH 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
2021-04-07 22:08       ` Simon Marchi
2021-04-08  7:44         ` Aktemur, Tankut Baris
2021-04-08 13:59           ` Simon Marchi
2021-04-08 14:19             ` Aktemur, Tankut Baris
2021-04-07 14:55     ` [PATCH 4/4] gdb/mi: add a '-b' flag to the '-break-insert' cmd to force the condition Tankut Baris Aktemur
2021-04-07 15:18       ` Eli Zaretskii
2021-04-07 15:27         ` Aktemur, Tankut Baris
2021-04-07 15:53           ` Eli Zaretskii
2021-04-07 16:05             ` Aktemur, Tankut Baris
2021-04-07 16:50               ` Eli Zaretskii
2021-04-07 22:26       ` Simon Marchi
2021-04-08 14:22     ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
2021-04-08 14:22       ` [PATCH v2 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
2021-04-08 15:04         ` Eli Zaretskii
2021-04-08 14:22       ` [PATCH v2 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
2021-04-08 14:22       ` [PATCH v2 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
2021-04-08 14:22       ` [PATCH v2 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
2021-04-08 15:06         ` Eli Zaretskii
2021-04-08 15:12           ` Aktemur, Tankut Baris
2021-04-11  1:06         ` Jonah Graham
2021-04-11  1:12           ` Simon Marchi
2021-04-21 12:06             ` Aktemur, Tankut Baris
2021-04-21 12:36               ` Simon Marchi
2021-04-11  1:13       ` [PATCH v2 0/4] Multi-context invalid breakpoint conditions and MI Jonah Graham
2021-04-21 12:17       ` [PATCH v3 " Tankut Baris Aktemur
2021-04-21 12:17         ` [PATCH v3 1/4] gdb/breakpoint: display "N" on MI for disabled-by-condition locations Tankut Baris Aktemur
2021-04-21 12:48           ` Eli Zaretskii
2021-04-21 12:17         ` [PATCH v3 2/4] testsuite, gdb.mi: fix duplicate test names in mi-break.exp Tankut Baris Aktemur
2021-04-21 12:17         ` [PATCH v3 3/4] gdb/breakpoint: add a 'force_condition' parameter to 'create_breakpoint' Tankut Baris Aktemur
2021-04-21 13:18           ` Simon Marchi
2021-04-21 13:29             ` Aktemur, Tankut Baris
2021-04-21 14:28               ` Simon Marchi
2021-04-21 12:17         ` [PATCH v3 4/4] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
2021-04-21 12:50           ` Eli Zaretskii
2021-04-21 13:37           ` Simon Marchi
2021-04-21 13:49             ` Aktemur, Tankut Baris
2021-04-21 14:26               ` Simon Marchi
2021-04-22 14:35         ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Tankut Baris Aktemur
2021-04-22 14:35           ` [PATCH v4 1/2] gdb/mi: add a '--force-condition' flag to the '-break-insert' cmd Tankut Baris Aktemur
2021-05-06  2:40             ` Simon Marchi
2021-04-22 14:35           ` [PATCH v4 2/2] gdb/mi: add a '--force' flag to the '-break-condition' command Tankut Baris Aktemur
2021-04-22 14:47             ` Aktemur, Tankut Baris
2021-05-06  2:46             ` Simon Marchi
2021-05-06  8:50               ` Aktemur, Tankut Baris
2021-07-11 18:51               ` Jonah Graham
2021-07-12  0:25                 ` Jonah Graham
2021-07-12  8:33                 ` Aktemur, Tankut Baris
2021-05-05 15:57           ` [PATCH v4 0/2] Multi-context invalid breakpoint conditions and MI Aktemur, Tankut Baris
2021-04-07 21:24   ` [PATCH 0/2] Breakpoint conditions at locations with differing contexts Simon Marchi
2021-04-07 21:36     ` Jonah Graham

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).