Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [Patch] Cannot set pending bp if condition set explicitly
@ 2012-07-24 14:45 Marc Khouzam
  2012-07-25 15:28 ` Tom Tromey
  0 siblings, 1 reply; 10+ messages in thread
From: Marc Khouzam @ 2012-07-24 14:45 UTC (permalink / raw)
  To: 'gdb-patches@sourceware.org'

Hi,

If I set a condition explicitly on a pending breakpoint (using
the 'condition' command), the breakpoint fails to install.

I believe it is because the condition is marked as parsed,
although, for a pending bp, this is not the case.
Note that using the form
  b mydll:c:5 if j==3
does work because the condition is not examined until the
pending breakpoint is installed.  This is not the case
when using the 'condition' command.
Broken session below.

No regressions on Ubuntu 32bit.

Is this ok for HEAD and 7_5?

Thanks

2012-07-20  Marc Khouzam  <marc.khouzam@ericsson.com>

	* breakpoint.c (set_breakpoint_condition): For pending
	breakpoints, mark condition as not parsed.

### Eclipse Workspace Patch 1.0
#P src
Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.694
diff -u -r1.694 breakpoint.c
--- gdb/breakpoint.c    19 Jul 2012 15:38:16 -0000      1.694
+++ gdb/breakpoint.c    23 Jul 2012 15:46:24 -0000
@@ -951,7 +951,12 @@
       /* I don't know if it matters whether this is the string the user
         typed in or the decompiled expression.  */
       b->cond_string = xstrdup (arg);
-      b->condition_not_parsed = 0;
+
+      /* For a pending breakoint, the condition is not parsed yet */
+      if (b->loc == NULL || b->loc->shlib_disabled)
+       b->condition_not_parsed = 1;
+      else  
+       b->condition_not_parsed = 0;
 
       if (is_watchpoint (b))
        {


> gdb myapp.exe
GNU gdb (GDB) 7.4.1
(gdb) b mydll.c:5
No source file named mydll.c.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (mydll.c:5) pending.
(gdb) cond 1 j==3
(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   <PENDING>  mydll.c:5
        stop only if j==3
(gdb) r
Starting program: /home/lmckhou/runtime-TestDSF/myapp/Debug/myapp.exe 
Error in re-setting breakpoint 1: No source file named /home/lmckhou/runtime-TestDSF/myLinuxDll/src/mydll.c.
5
warning: Temporarily disabling breakpoints for unloaded shared library "/home/lmckhou/runtime-TestDSF/myLinuxDll/Debug/libmyLinuxDll"
[Inferior 1 (process 3438) exited normally]

=> breakpoint was not installed and didn't hit


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

* Re: [Patch] Cannot set pending bp if condition set explicitly
  2012-07-24 14:45 [Patch] Cannot set pending bp if condition set explicitly Marc Khouzam
@ 2012-07-25 15:28 ` Tom Tromey
  2012-07-25 20:31   ` Marc Khouzam
  0 siblings, 1 reply; 10+ messages in thread
From: Tom Tromey @ 2012-07-25 15:28 UTC (permalink / raw)
  To: Marc Khouzam; +Cc: 'gdb-patches@sourceware.org'

>>>>> "Marc" == Marc Khouzam <marc.khouzam@ericsson.com> writes:

Marc> If I set a condition explicitly on a pending breakpoint (using
Marc> the 'condition' command), the breakpoint fails to install.

Marc> +      /* For a pending breakoint, the condition is not parsed yet */

Comment should end with a period and two spaces.

Marc> +      if (b->loc == NULL || b->loc->shlib_disabled)

I think this ought to use all_locations_are_pending.
But, I am not 100% sure of this.

A test case for this would be quite nice to have.

Tom


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

* RE: [Patch] Cannot set pending bp if condition set explicitly
  2012-07-25 15:28 ` Tom Tromey
@ 2012-07-25 20:31   ` Marc Khouzam
  2012-07-25 20:44     ` Tom Tromey
  2012-07-26 19:05     ` Pedro Alves
  0 siblings, 2 replies; 10+ messages in thread
From: Marc Khouzam @ 2012-07-25 20:31 UTC (permalink / raw)
  To: 'Tom Tromey'; +Cc: 'gdb-patches@sourceware.org'

> -----Original Message-----
> From: Tom Tromey [mailto:tromey@redhat.com] 
> Sent: Wednesday, July 25, 2012 11:28 AM
> To: Marc Khouzam
> Cc: 'gdb-patches@sourceware.org'
> Subject: Re: [Patch] Cannot set pending bp if condition set explicitly
> 
> >>>>> "Marc" == Marc Khouzam <marc.khouzam@ericsson.com> writes:
> 
> Marc> If I set a condition explicitly on a pending breakpoint (using
> Marc> the 'condition' command), the breakpoint fails to install.
> 
> Marc> +      /* For a pending breakoint, the condition is not 
> parsed yet */
> 
> Comment should end with a period and two spaces.

Fixed, along with "breakoint" typo.

> Marc> +      if (b->loc == NULL || b->loc->shlib_disabled)
> 
> I think this ought to use all_locations_are_pending.
> But, I am not 100% sure of this.

I took the original line from print_one_exception_catchpoint()
when it figures out to print <PENDING>.

But I changed it to use all_locations_are_pending() in the below 
patch, and it also solves the problem I was seeing.

> A test case for this would be quite nice to have.

I modified gdb.base/pending.exp to test this case. The test fails
before the patch and passes after.  You'll note that I removed the 
two tests tha were disabling bp 7 and 5.  There were no bp 7 or 5 in
the original test, and my changes added bp 5 which needed to stay 
enabled.

How does it look for HEAD and 7_5 (not the tests
for 7_5 I gather)?

Thanks

Marc

2012-07-25  Marc Khouzam  <marc.khouzam@ericsson.com>

	* breakpoint.c: Add declaration of all_locations_are_pending.
	(set_breakpoint_condition): For pending breakpoints, mark 
	condition as not parsed.

2012-07-25  Marc Khouzam  <marc.khouzam@ericsson.com>

	* gdb.base/pendshr.c: Extra line to set a new breakpoint.
	* gdb.base/pending.exp: Set an enabled pending breakpoint
	with an explicit condition.


### Eclipse Workspace Patch 1.0
#P src
Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.695
diff -u -r1.695 breakpoint.c
--- gdb/breakpoint.c    24 Jul 2012 17:37:56 -0000      1.695
+++ gdb/breakpoint.c    25 Jul 2012 20:15:20 -0000
@@ -230,6 +230,8 @@
 
 static void tcatch_command (char *arg, int from_tty);
 
+static int all_locations_are_pending (struct bp_location *loc);
+
 static void detach_single_step_breakpoints (void);
 
 static int single_step_breakpoint_inserted_here_p (struct address_space *,
@@ -951,7 +953,12 @@
       /* I don't know if it matters whether this is the string the user
         typed in or the decompiled expression.  */
       b->cond_string = xstrdup (arg);
-      b->condition_not_parsed = 0;
+
+      /* For a pending breakpoint, the condition is not parsed yet.  */
+      if (all_locations_are_pending (b->loc))
+       b->condition_not_parsed = 1;
+      else
+       b->condition_not_parsed = 0;
 
       if (is_watchpoint (b))
        {
Index: gdb/testsuite/gdb.base/pending.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/pending.exp,v
retrieving revision 1.26
diff -u -r1.26 pending.exp
--- gdb/testsuite/gdb.base/pending.exp  21 Jun 2012 20:46:22 -0000      1.26
+++ gdb/testsuite/gdb.base/pending.exp  25 Jul 2012 20:15:20 -0000
@@ -209,6 +209,32 @@
 "multiple pending breakpoints 2"
 
 #
+# Try a pending break with an explicit condition which is enabled at startup
+#
+
+set bp5_loc [gdb_get_line_number "y++" ${libfile}.c]
+gdb_test_multiple "break pendshr.c:$bp5_loc" "Set pending breakpoint 4" {
+     -re ".*Make breakpoint pending.*y or \\\[n\\\]. $" {
+           gdb_test "y" "Breakpoint.*pendshr.c:$bp5_loc.*pending." \
+               "Set pending breakpoint 5"
+     }
+}
+
+gdb_test_no_output "condition 5 k == 1"
+
+gdb_test "info break" \
+    "Num     Type\[ \]+Disp Enb Address\[ \]+What.*
+\[0-9\]+\[\t \]+breakpoint     keep n.*PENDING.*pendfunc1.*
+\[\t \]+stop only if k == 1.*
+\[\t \]+print k.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in main at .*$srcfile:$mainline.*
+\[0-9\]+\[\t \]+breakpoint     keep y.*PENDING.*pendshr.c:$bp2_loc if x > 3.*
+\[0-9\]+\[\t \]+breakpoint     keep y.*PENDING.*pendshr.c:$bp3_loc.*ignore next 2 hits.*
+\[0-9\]+\[\t \]+breakpoint     keep y.*PENDING.*pendshr.c:$bp5_loc.*
+\[\t \]+stop only if k == 1.*" \
+"multiple pending breakpoints 3"
+
+#
 # Run to main which should resolve a pending breakpoint
 #
 
@@ -218,6 +244,24 @@
 "running to main"
 
 #
+# Verify that all pending breakpoints have resolved.
+#
+gdb_test "info break" \
+    "Num     Type\[ \]+Disp Enb Address\[ \]+What.*
+\[0-9\]+\[\t \]+breakpoint     keep n.* in pendfunc1 at .*
+\[\t \]+stop only if k == 1.*
+\[\t \]+print k.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in main at .*$srcfile:$mainline.*
+\[\t \]+breakpoint already hit 1 time.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in pendfunc1 at .*pendshr.c:$bp2_loc.*
+\[\t \]+stop only if x > 3.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in pendfunc1 at .*pendshr.c:$bp3_loc.*
+\[\t \]+ignore next 2 hits.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in pendfunc1 at .*pendshr.c:$bp5_loc.*
+\[\t \]+stop only if k == 1.*" \
+"multiple pending breakpoints 4"
+
+#
 # Re-enable the first pending breakpoint which should resolve
 #
 
@@ -237,19 +281,14 @@
 \[$\]1 = 1." \
 "continue to resolved breakpoint 1"
 
-#
-# Disable the other two breakpoints, and continue to the one with
-# the ignore count.  Make sure you hit it the third time, x should
-# be 3 then.
-#
-
-gdb_test "disable 7" "" "Disable other breakpoints"
-gdb_test "disable 5" "" "Disable other breakpoints"
-
 gdb_test "continue" \
         ".*Breakpoint.*pendfunc1.*\\\(x=3\\\) at.*pendshr.c:$bp3_loc.*printf.*;" \
 "continue to resolved breakpoint 3"
 
+gdb_test "continue" \
+        ".*Breakpoint.*pendfunc1.*\\\(x=3\\\) at.*pendshr.c:$bp5_loc.*y\\+\\+;" \
+"continue to resolved breakpoint 5"
+
 delete_breakpoints
 
 gdb_breakpoint "main"
Index: gdb/testsuite/gdb.base/pendshr.c
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/pendshr.c,v
retrieving revision 1.10
diff -u -r1.10 pendshr.c
--- gdb/testsuite/gdb.base/pendshr.c    4 Jan 2012 08:17:46 -0000       1.10
+++ gdb/testsuite/gdb.base/pendshr.c    25 Jul 2012 20:15:20 -0000
@@ -21,6 +21,7 @@
 {
   int y = x + 4;
   printf ("in pendfunc1, x is %d\n", x);
+  y++;
 }
 
 void pendfunc (int x)


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

* Re: [Patch] Cannot set pending bp if condition set explicitly
  2012-07-25 20:31   ` Marc Khouzam
@ 2012-07-25 20:44     ` Tom Tromey
  2012-07-26 19:05     ` Pedro Alves
  1 sibling, 0 replies; 10+ messages in thread
From: Tom Tromey @ 2012-07-25 20:44 UTC (permalink / raw)
  To: Marc Khouzam; +Cc: 'gdb-patches@sourceware.org', Pedro Alves

Marc> I took the original line from print_one_exception_catchpoint()
Marc> when it figures out to print <PENDING>.

Yeah, I'm just not sure that this test is definitive in all cases.

Marc> But I changed it to use all_locations_are_pending() in the below 
Marc> patch, and it also solves the problem I was seeing.

I'd like Pedro's input on this patch.  I CC'd him.

Marc> How does it look for HEAD and 7_5 (not the tests
Marc> for 7_5 I gather)?

I think it is fine to put a new test onto the release branch.
The worst that can happen is a new FAIL -- but it isn't like the test
case is 0-FAIL in normal circumstances anyway.

Tom


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

* Re: [Patch] Cannot set pending bp if condition set explicitly
  2012-07-25 20:31   ` Marc Khouzam
  2012-07-25 20:44     ` Tom Tromey
@ 2012-07-26 19:05     ` Pedro Alves
  2012-07-27  2:45       ` Marc Khouzam
  2012-08-03  0:51       ` [Patch] Cannot set pending bp if condition set explicitly Pedro Alves
  1 sibling, 2 replies; 10+ messages in thread
From: Pedro Alves @ 2012-07-26 19:05 UTC (permalink / raw)
  To: Marc Khouzam; +Cc: 'Tom Tromey', 'gdb-patches@sourceware.org'

Hello,

On 07/25/2012 09:30 PM, Marc Khouzam wrote:
> Index: gdb/breakpoint.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/breakpoint.c,v
> retrieving revision 1.695
> diff -u -r1.695 breakpoint.c
> --- gdb/breakpoint.c    24 Jul 2012 17:37:56 -0000      1.695
> +++ gdb/breakpoint.c    25 Jul 2012 20:15:20 -0000
> @@ -230,6 +230,8 @@
>  
>  static void tcatch_command (char *arg, int from_tty);
>  
> +static int all_locations_are_pending (struct bp_location *loc);
> +
>  static void detach_single_step_breakpoints (void);
>  
>  static int single_step_breakpoint_inserted_here_p (struct address_space *,
> @@ -951,7 +953,12 @@
>        /* I don't know if it matters whether this is the string the user
>          typed in or the decompiled expression.  */
>        b->cond_string = xstrdup (arg);
> -      b->condition_not_parsed = 0;
> +
> +      /* For a pending breakpoint, the condition is not parsed yet.  */
> +      if (all_locations_are_pending (b->loc))
> +       b->condition_not_parsed = 1;
> +      else
> +       b->condition_not_parsed = 0;
>  
>        if (is_watchpoint (b))
>         {

It looks to me the sole reason of b->condition_not_parsed's existence, is that
when the user does

 break foo 1 == 1 thread 3

we need to split the "1 == 1" part from the "thread 3" part.  The expression
that results from this parse is just discarded.

E.g., see:

            /* 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 (arg, lsal->sals.sals[0].pc, &cond_string,
                                       &thread, &task, &rest);
            if (cond_string)
                make_cleanup (xfree, cond_string);
	    if (rest)
	      make_cleanup (xfree, rest);
	    if (rest)
	      extra_string = rest;


So "condition_not_parsed" is just a flag that means "find_condition_and_thread
not called yet, so I don't know yet where my condition string ends".

Unfortunately, the "1 == 1" part is language dependent, so it needs to be parsed
with some context.

Note that the result of such parsing is always discarded - the only thing
find_condition_and_thread is interested in, is in advancing the command arg pointer
past the condition.  Later, each location's condition expression is always reparsed
using each location as context, and that is what is stored in bloc->cond
or in ((struct watchpoint *)b)->cond_exp, for watchpoints.

Therefore, it seems to be the patch has unexpected consequences.

This currently works:

 (gdb) b main if 1 == 1 thread 1
 Breakpoint 2 at 0x4572bb: file ../../src/gdb/gdb.c, line 29.

But this does not:

 (gdb) condition 2 1 == 1 thread 1
 Junk at end of expression

However, for pending breakpoints, this will not produce an error:

 (gdb) condition 2 1 == 1 thread 1
 (gdb) info breakpoints
 Num     Type           Disp Enb Address    What
 2       breakpoint     keep y   <PENDING>  foo
         stop only if 1 == 1 thread 1

But later on, when the breakpoint's condition is finally
parsed, the "thread 1" part will not really be used for anything.
More on that below.

> @@ -951,7 +953,12 @@
>        /* I don't know if it matters whether this is the string the user
>          typed in or the decompiled expression.  */
>        b->cond_string = xstrdup (arg);
> -      b->condition_not_parsed = 0;
> +
> +      /* For a pending breakpoint, the condition is not parsed yet.  */
> +      if (all_locations_are_pending (b->loc))
> +       b->condition_not_parsed = 1;
> +      else
> +       b->condition_not_parsed = 0;
>

So in light of the above, this reads a bit odd.  This function is only
called from condition_command.  The "condition" command only supports
a real condition, not the "thread N" part.  So the passed in EXP to
set_condition_command already _is_ the condition, and we don't need to
call find_condition_and_thread.  Therefore, setting condition_not_parsed
seems wrong.  (if it were right, it would seem better to return immediately,
rather than continue and try to parse the condition expression for
each location, given we had just asserted we didn't know what the condition
string was!).

The reason setting "condition_not_parsed" fixes the problem, is that
when you "run", breakpoints end up being re_set, and that ends up
with:

  Error in re-setting breakpoint 5: No source file named pendshr.c.

seen here:

#0  addr_string_to_sals (b=0xf9ecc0, addr_string=0xe7dbe0 "pendshr.c:24", found=0x7fffffffd2ec) at ../../src/gdb/breakpoint.c:14002
#1  0x0000000000555483 in breakpoint_re_set_default (b=0xf9ecc0) at ../../src/gdb/breakpoint.c:14076
#2  0x000000000055306e in bkpt_re_set (b=0xf9ecc0) at ../../src/gdb/breakpoint.c:12812
#3  0x000000000055577f in breakpoint_re_set_one (bint=0xf9ecc0) at ../../src/gdb/breakpoint.c:14193
#4  0x00000000005ce097 in catch_errors (func=0x555747 <breakpoint_re_set_one>, func_args=0xf9ecc0, errstring=0x111a190 "Error in re-setting breakpoint 7: ", mask=6)
    at ../../src/gdb/exceptions.c:546
#5  0x0000000000555811 in breakpoint_re_set () at ../../src/gdb/breakpoint.c:14217
#6  0x00000000006df7c1 in solib_add (pattern=0x0, from_tty=0, target=0xc42100, readsyms=1) at ../../src/gdb/solib.c:930

static struct symtabs_and_lines
addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
{
  char *s;
  struct symtabs_and_lines sals = {0};
  volatile struct gdb_exception e;

  gdb_assert (b->ops != NULL);
  s = addr_string;

  TRY_CATCH (e, RETURN_MASK_ERROR)
    {
      b->ops->decode_linespec (b, &s, &sals);
    }
  if (e.reason < 0)
    {
      int not_found_and_ok = 0;
      /* For pending breakpoints, it's expected that parsing will
	 fail until the right shared library is loaded.  User has
	 already told to create pending breakpoints and don't need
	 extra messages.  If breakpoint is in bp_shlib_disabled
	 state, then user already saw the message about that
	 breakpoint being disabled, and don't want to see more
	 errors.  */
      if (e.error == NOT_FOUND_ERROR
	  && (b->condition_not_parsed
              ^^^^^^^^^^^^^^^^^^^^^^^
	      || (b->loc && b->loc->shlib_disabled)
	      || (b->loc && b->loc->pspace->executing_startup)
	      || b->enable_state == bp_disabled))
	not_found_and_ok = 1;

And "b->condition_not_parsed" being set results in not_found_and_ok
being set too.

When finally decode_linespec does not throw an error, because the
library is loaded in the inferior, and the breakpoint manages to
become resolvable, we reach:

  if (e.reason == 0 || e.error != NOT_FOUND_ERROR)
    {
      int i;

      for (i = 0; i < sals.nelts; ++i)
	resolve_sal_pc (&sals.sals[i]);
      if (b->condition_not_parsed && s && s[0])
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	{
	  char *cond_string, *extra_string;
	  int thread, task;

	  find_condition_and_thread (s, sals.sals[0].pc,
				     &cond_string, &thread, &task,
				     &extra_string);


But s[0] is \0, because s decode_linespace consumes the whole addr_string,
which was "pendshr.c:24".  So find_condition_and_thread is never called,
meaning the "thread N" never actually works, and, condition_not_parsed remains
set forever.  I am of the opinion that "condition BP thread N" should _not_
work (reserve that for a separate command, we have enough trouble due to
"thread/task" already), so "condition" for non-pending breakpoints should
remain as it is, and for pending breakpoints, thread "1 == 1 thread N" should
be treated as a bogus condition, just like "ninja fu" is an invalid
C condition.

I think create_breakpoint has a related latent bug.  The contract is:

/*                               (...) This function has two major
   modes of operations, selected by the PARSE_CONDITION_AND_THREAD
   parameter.  If non-zero, the function will parse arg, extracting
   breakpoint location, address and thread.  Otherwise, ARG is just
   the location of breakpoint, with condition and thread specified by
   the COND_STRING and THREAD parameters.  (...) */

But when a pending breakpoint is created, condition_not_parsed
is left set, even when PARSE_CONDITION_AND_THREAD was false, thus
ignoring the THREAD argument.

So given all that, I tried the alternate patch below.  IOW,
change how addr_string_to_sals knows a breakpoint is a pending breakpoint.
It also fixes the new test, and causes no regressions (x86_64 Fedora 17).

Not sure yet what is the best predicate to put there.
The whole condition looks a bit in need of TLC.  all_locations_are_pending would
return true if all locations had been shlib_disabled.  The condition does
also check for shlib_disabled, but only on the first location.  Especially now
that breakpoints can have locations anywhere, I think we might need to consider
what happens and what should happen to when only a few of the conditions
are shlib_disabled..

WDYT?  I'll try to give this predicate a bit more thought (but I'm running
out of day for today), but these are my thoughts so far.

 gdb/breakpoint.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 03719d4..ae21631 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -9558,7 +9558,10 @@ create_breakpoint (struct gdbarch *gdbarch,

       b->addr_string = copy_arg;
       if (parse_condition_and_thread)
-	b->cond_string = NULL;
+	{
+	  b->cond_string = NULL;
+	  b->condition_not_parsed = 1;
+	}
       else
 	{
 	  /* Create a private copy of condition string.  */
@@ -9572,7 +9575,6 @@ create_breakpoint (struct gdbarch *gdbarch,
       b->extra_string = NULL;
       b->ignore_count = ignore_count;
       b->disposition = tempflag ? disp_del : disp_donttouch;
-      b->condition_not_parsed = 1;
       b->enable_state = enabled ? bp_enabled : bp_disabled;
       if ((type_wanted != bp_breakpoint
            && type_wanted != bp_hardware_breakpoint) || thread != -1)
@@ -14008,7 +14010,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
 	 breakpoint being disabled, and don't want to see more
 	 errors.  */
       if (e.error == NOT_FOUND_ERROR
-	  && (b->condition_not_parsed
+	  && (b->loc == NULL
 	      || (b->loc && b->loc->shlib_disabled)
 	      || (b->loc && b->loc->pspace->executing_startup)
 	      || b->enable_state == bp_disabled))


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

* RE: [Patch] Cannot set pending bp if condition set explicitly
  2012-07-26 19:05     ` Pedro Alves
@ 2012-07-27  2:45       ` Marc Khouzam
  2012-07-30 15:19         ` Pedro Alves
  2012-08-03  0:51       ` [Patch] Cannot set pending bp if condition set explicitly Pedro Alves
  1 sibling, 1 reply; 10+ messages in thread
From: Marc Khouzam @ 2012-07-27  2:45 UTC (permalink / raw)
  To: Pedro Alves; +Cc: 'Tom Tromey', 'gdb-patches@sourceware.org'

> -----Original Message-----
> From: Pedro Alves [mailto:palves@redhat.com] 
> Sent: Thursday, July 26, 2012 3:05 PM
> To: Marc Khouzam
> Cc: 'Tom Tromey'; 'gdb-patches@sourceware.org'
> Subject: Re: [Patch] Cannot set pending bp if condition set explicitly
> 
> Hello,

Thanks Pedro for having taken the time to dig into this.

> On 07/25/2012 09:30 PM, Marc Khouzam wrote:
> > Index: gdb/breakpoint.c
> > ===================================================================
> > RCS file: /cvs/src/src/gdb/breakpoint.c,v
> > retrieving revision 1.695
> > diff -u -r1.695 breakpoint.c
> > --- gdb/breakpoint.c    24 Jul 2012 17:37:56 -0000      1.695
> > +++ gdb/breakpoint.c    25 Jul 2012 20:15:20 -0000
> > @@ -230,6 +230,8 @@
> >  
> >  static void tcatch_command (char *arg, int from_tty);
> >  
> > +static int all_locations_are_pending (struct bp_location *loc);
> > +
> >  static void detach_single_step_breakpoints (void);
> >  
> >  static int single_step_breakpoint_inserted_here_p (struct 
> address_space *,
> > @@ -951,7 +953,12 @@
> >        /* I don't know if it matters whether this is the 
> string the user
> >          typed in or the decompiled expression.  */
> >        b->cond_string = xstrdup (arg);
> > -      b->condition_not_parsed = 0;
> > +
> > +      /* For a pending breakpoint, the condition is not 
> parsed yet.  */
> > +      if (all_locations_are_pending (b->loc))
> > +       b->condition_not_parsed = 1;
> > +      else
> > +       b->condition_not_parsed = 0;
> >  
> >        if (is_watchpoint (b))
> >         {
> 
> It looks to me the sole reason of b->condition_not_parsed's 
> existence, is that
> when the user does
> 
>  break foo 1 == 1 thread 3
> 
> we need to split the "1 == 1" part from the "thread 3" part.  
> The expression
> that results from this parse is just discarded.
> 
> E.g., see:
> 
>             /* 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 (arg, 
> lsal->sals.sals[0].pc, &cond_string,
>                                        &thread, &task, &rest);
>             if (cond_string)
>                 make_cleanup (xfree, cond_string);
> 	    if (rest)
> 	      make_cleanup (xfree, rest);
> 	    if (rest)
> 	      extra_string = rest;
> 
> 
> So "condition_not_parsed" is just a flag that means 
> "find_condition_and_thread
> not called yet, so I don't know yet where my condition string ends".

Ok, I see that now.  

> Unfortunately, the "1 == 1" part is language dependent, so it 
> needs to be parsed
> with some context.
> 
> Note that the result of such parsing is always discarded - 
> the only thing
> find_condition_and_thread is interested in, is in advancing 
> the command arg pointer
> past the condition.  Later, each location's condition 
> expression is always reparsed
> using each location as context, and that is what is stored in 
> bloc->cond
> or in ((struct watchpoint *)b)->cond_exp, for watchpoints.

That makes me wonder why we need to jump
through hoops with having "condition_not_parsed"?  Why not 
always call find_condition_and_thread() inside of create_breakpoint()
even for pending breakpoints?  That way, b->cond_string,
b->thread, and b->extra_string would always be set after
create_breakpoint() and we wouldn't need to treat pending breakpoints
differently in this case.  It seems find_condition_and_thread() requires
an address, which would explain why it is not called for pending bp.
However, after reading your explanation, since find_condition_and_thread() 
is only interested in advancing the command arg pointer past the condition,
why do we need the address at all?  Should work fine for pending
breakpoints, no?  Maybe it is just a requirement for parse_exp_1()
which is the one that actually parse the command argument?

> Therefore, it seems to be the patch has unexpected consequences.
> 
> This currently works:
> 
>  (gdb) b main if 1 == 1 thread 1
>  Breakpoint 2 at 0x4572bb: file ../../src/gdb/gdb.c, line 29.
> 
> But this does not:
> 
>  (gdb) condition 2 1 == 1 thread 1
>  Junk at end of expression

On a side-note, I see that although there is an error printed and 
set_breakpoint_condition() is aborted, the bad condition is not
cleaned-up, as shown here:

(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x0804851d in main at ../../../src/gdb/testsuite/gdb.base/pending.c:26
        stop only if k==1 thread 1

Shouldn't there be some kind of cleanup in set_breakpoint_condition()?

> However, for pending breakpoints, this will not produce an error:
> 
>  (gdb) condition 2 1 == 1 thread 1
>  (gdb) info breakpoints
>  Num     Type           Disp Enb Address    What
>  2       breakpoint     keep y   <PENDING>  foo
>          stop only if 1 == 1 thread 1
> 
> But later on, when the breakpoint's condition is finally
> parsed, the "thread 1" part will not really be used for anything.
> More on that below.
> 
> > @@ -951,7 +953,12 @@
> >        /* I don't know if it matters whether this is the 
> string the user
> >          typed in or the decompiled expression.  */
> >        b->cond_string = xstrdup (arg);
> > -      b->condition_not_parsed = 0;
> > +
> > +      /* For a pending breakpoint, the condition is not 
> parsed yet.  */
> > +      if (all_locations_are_pending (b->loc))
> > +       b->condition_not_parsed = 1;
> > +      else
> > +       b->condition_not_parsed = 0;
> >
> 
> So in light of the above, this reads a bit odd.  This function is only
> called from condition_command.  The "condition" command only supports
> a real condition, not the "thread N" part.  So the passed in EXP to
> set_condition_command already _is_ the condition, and we don't need to
> call find_condition_and_thread.  Therefore, setting 
> condition_not_parsed
> seems wrong.  (if it were right, it would seem better to 
> return immediately,
> rather than continue and try to parse the condition expression for
> each location, given we had just asserted we didn't know what 
> the condition
> string was!).

Got it.

> The reason setting "condition_not_parsed" fixes the problem, is that
> when you "run", breakpoints end up being re_set, and that ends up
> with:
> 
>   Error in re-setting breakpoint 5: No source file named pendshr.c.
> 
> seen here:
> 
> #0  addr_string_to_sals (b=0xf9ecc0, addr_string=0xe7dbe0 
> "pendshr.c:24", found=0x7fffffffd2ec) at 
> ../../src/gdb/breakpoint.c:14002
> #1  0x0000000000555483 in breakpoint_re_set_default 
> (b=0xf9ecc0) at ../../src/gdb/breakpoint.c:14076
> #2  0x000000000055306e in bkpt_re_set (b=0xf9ecc0) at 
> ../../src/gdb/breakpoint.c:12812
> #3  0x000000000055577f in breakpoint_re_set_one 
> (bint=0xf9ecc0) at ../../src/gdb/breakpoint.c:14193
> #4  0x00000000005ce097 in catch_errors (func=0x555747 
> <breakpoint_re_set_one>, func_args=0xf9ecc0, 
> errstring=0x111a190 "Error in re-setting breakpoint 7: ", mask=6)
>     at ../../src/gdb/exceptions.c:546
> #5  0x0000000000555811 in breakpoint_re_set () at 
> ../../src/gdb/breakpoint.c:14217
> #6  0x00000000006df7c1 in solib_add (pattern=0x0, from_tty=0, 
> target=0xc42100, readsyms=1) at ../../src/gdb/solib.c:930
> 
> static struct symtabs_and_lines
> addr_string_to_sals (struct breakpoint *b, char *addr_string, 
> int *found)
> {
>   char *s;
>   struct symtabs_and_lines sals = {0};
>   volatile struct gdb_exception e;
> 
>   gdb_assert (b->ops != NULL);
>   s = addr_string;
> 
>   TRY_CATCH (e, RETURN_MASK_ERROR)
>     {
>       b->ops->decode_linespec (b, &s, &sals);
>     }
>   if (e.reason < 0)
>     {
>       int not_found_and_ok = 0;
>       /* For pending breakpoints, it's expected that parsing will
> 	 fail until the right shared library is loaded.  User has
> 	 already told to create pending breakpoints and don't need
> 	 extra messages.  If breakpoint is in bp_shlib_disabled
> 	 state, then user already saw the message about that
> 	 breakpoint being disabled, and don't want to see more
> 	 errors.  */
>       if (e.error == NOT_FOUND_ERROR
> 	  && (b->condition_not_parsed
>               ^^^^^^^^^^^^^^^^^^^^^^^
> 	      || (b->loc && b->loc->shlib_disabled)
> 	      || (b->loc && b->loc->pspace->executing_startup)
> 	      || b->enable_state == bp_disabled))
> 	not_found_and_ok = 1;
> 
> And "b->condition_not_parsed" being set results in not_found_and_ok
> being set too.
> 
> When finally decode_linespec does not throw an error, because the
> library is loaded in the inferior, and the breakpoint manages to
> become resolvable, we reach:
> 
>   if (e.reason == 0 || e.error != NOT_FOUND_ERROR)
>     {
>       int i;
> 
>       for (i = 0; i < sals.nelts; ++i)
> 	resolve_sal_pc (&sals.sals[i]);
>       if (b->condition_not_parsed && s && s[0])
>       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 	{
> 	  char *cond_string, *extra_string;
> 	  int thread, task;
> 
> 	  find_condition_and_thread (s, sals.sals[0].pc,
> 				     &cond_string, &thread, &task,
> 				     &extra_string);
> 
> 
> But s[0] is \0, because s decode_linespace consumes the whole 
> addr_string,
> which was "pendshr.c:24".  

Nice!  Thanks for clearing that up.

> So find_condition_and_thread is 
> never called,
> meaning the "thread N" never actually works, and, 
> condition_not_parsed remains
> set forever.  I am of the opinion that "condition BP thread 
> N" should _not_
> work (reserve that for a separate command, we have enough 
> trouble due to
> "thread/task" already), so "condition" for non-pending 
> breakpoints should
> remain as it is, and for pending breakpoints, thread "1 == 1 
> thread N" should
> be treated as a bogus condition, just like "ninja fu" is an invalid
> C condition.

Yes, that makes sense.  In that case, set_breakpoint_condition() 
would need to parse the condition even if the bp was pending.
This would fit well with needed cleanup of set_breakpoint_condition()
mentioned above.

Should I write a patch for this? (I'm leaving for vacation on Friday,
so this may not happen very soon.)
 
> I think create_breakpoint has a related latent bug.  The contract is:
> 
> /*                               (...) This function has two major
>    modes of operations, selected by the PARSE_CONDITION_AND_THREAD
>    parameter.  If non-zero, the function will parse arg, extracting
>    breakpoint location, address and thread.  Otherwise, ARG is just
>    the location of breakpoint, with condition and thread specified by
>    the COND_STRING and THREAD parameters.  (...) */
> 
> But when a pending breakpoint is created, condition_not_parsed
> is left set, even when PARSE_CONDITION_AND_THREAD was false, thus
> ignoring the THREAD argument.

That is in part my fault.  The handling of PARSE_CONDITION_AND_THREAD
was not done right for pending breakpoints.  I tried to fix it here:
http://sourceware.org/ml/gdb-patches/2012-07/msg00418.html
but I didn't deal with condition_not_parsed because if I set
it to 0 in that case, MI started showing the bug that we're trying to
fix in this patch.  But since you showed that setting 
condition_not_parsed to 1 only solves the problem by a side-effect,
MI was only working by chance in this case.

Another side-note is that when a pending breakpoint is created,
b->extra_string doesn't seem set properly, just like b->cond_string
was not.  I believe extra_string is for dprintf which cannot be set
using MI yet (I think), but once it will, this will become a problem.

> So given all that, I tried the alternate patch below.  IOW,
> change how addr_string_to_sals knows a breakpoint is a 
> pending breakpoint.
> It also fixes the new test, and causes no regressions (x86_64 
> Fedora 17).

That makes total sense.

> Not sure yet what is the best predicate to put there.
> The whole condition looks a bit in need of TLC.  
> all_locations_are_pending would
> return true if all locations had been shlib_disabled.  The 
> condition does
> also check for shlib_disabled, but only on the first 
> location.  Especially now
> that breakpoints can have locations anywhere, I think we 
> might need to consider
> what happens and what should happen to when only a few of the 
> conditions
> are shlib_disabled..
> 
> WDYT?  I'll try to give this predicate a bit more thought 
> (but I'm running
> out of day for today), but these are my thoughts so far.

I don't have much of an opinion.  I'm not yet grasping
all the details of breakpoints with multiple locations.
Maybe the breakpoint structure needs a pending flag?

>  gdb/breakpoint.c |    8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 03719d4..ae21631 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -9558,7 +9558,10 @@ create_breakpoint (struct gdbarch *gdbarch,
> 
>        b->addr_string = copy_arg;
>        if (parse_condition_and_thread)
> -	b->cond_string = NULL;
> +	{
> +	  b->cond_string = NULL;
> +	  b->condition_not_parsed = 1;
> +	}
>        else
>  	{
>  	  /* Create a private copy of condition string.  */
> @@ -9572,7 +9575,6 @@ create_breakpoint (struct gdbarch *gdbarch,
>        b->extra_string = NULL;
>        b->ignore_count = ignore_count;
>        b->disposition = tempflag ? disp_del : disp_donttouch;
> -      b->condition_not_parsed = 1;
>        b->enable_state = enabled ? bp_enabled : bp_disabled;
>        if ((type_wanted != bp_breakpoint
>             && type_wanted != bp_hardware_breakpoint) || thread != -1)
> @@ -14008,7 +14010,7 @@ addr_string_to_sals (struct 
> breakpoint *b, char *addr_string, int *found)
>  	 breakpoint being disabled, and don't want to see more
>  	 errors.  */
>        if (e.error == NOT_FOUND_ERROR
> -	  && (b->condition_not_parsed
> +	  && (b->loc == NULL
>  	      || (b->loc && b->loc->shlib_disabled)
>  	      || (b->loc && b->loc->pspace->executing_startup)
>  	      || b->enable_state == bp_disabled))

This patch works well from the basic testing I did.

Please let me know how you suggest I can go forward with
the different issues discussed above about bp conditions.

Thanks again!

Marc


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

* Re: [Patch] Cannot set pending bp if condition set explicitly
  2012-07-27  2:45       ` Marc Khouzam
@ 2012-07-30 15:19         ` Pedro Alves
  2012-07-30 15:36           ` Tom Tromey
  2012-08-03  0:44           ` disable breakpoints with invalid condition (Re: [Patch] Cannot set pending bp if condition set explicitly) Pedro Alves
  0 siblings, 2 replies; 10+ messages in thread
From: Pedro Alves @ 2012-07-30 15:19 UTC (permalink / raw)
  To: Marc Khouzam; +Cc: 'Tom Tromey', 'gdb-patches@sourceware.org'

On 07/27/2012 03:44 AM, Marc Khouzam wrote:

>> Unfortunately, the "1 == 1" part is language dependent, so it 
>> needs to be parsed
>> with some context.
>>
>> Note that the result of such parsing is always discarded - 
>> the only thing
>> find_condition_and_thread is interested in, is in advancing 
>> the command arg pointer
>> past the condition.  Later, each location's condition 
>> expression is always reparsed
>> using each location as context, and that is what is stored in 
>> bloc->cond
>> or in ((struct watchpoint *)b)->cond_exp, for watchpoints.
> 
> That makes me wonder why we need to jump
> through hoops with having "condition_not_parsed"?  Why not 
> always call find_condition_and_thread() inside of create_breakpoint()
> even for pending breakpoints?  That way, b->cond_string,
> b->thread, and b->extra_string would always be set after
> create_breakpoint() and we wouldn't need to treat pending breakpoints
> differently in this case.  It seems find_condition_and_thread() requires
> an address, which would explain why it is not called for pending bp.
> However, after reading your explanation, since find_condition_and_thread() 
> is only interested in advancing the command arg pointer past the condition,
> why do we need the address at all?  Should work fine for pending
> breakpoints, no?  Maybe it is just a requirement for parse_exp_1()
> which is the one that actually parse the command argument?

Yes, we parse the condition in the context of the breakpoint location,
for locals, etc., so we need the location's address.  We assume the condition
would parse more or less the same at any location, as in, gross validation,
and skipping past the condition, so we just pick the first location).

An alternative would be to restrict pending breakpoints conditions
to globals only.  Not sure whether that would fly.

> 
>> Therefore, it seems to be the patch has unexpected consequences.
>>
>> This currently works:
>>
>>  (gdb) b main if 1 == 1 thread 1
>>  Breakpoint 2 at 0x4572bb: file ../../src/gdb/gdb.c, line 29.
>>
>> But this does not:
>>
>>  (gdb) condition 2 1 == 1 thread 1
>>  Junk at end of expression
> 
> On a side-note, I see that although there is an error printed and 
> set_breakpoint_condition() is aborted, the bad condition is not
> cleaned-up, as shown here:
> 
> (gdb) info b
> Num     Type           Disp Enb Address    What
> 1       breakpoint     keep y   0x0804851d in main at ../../../src/gdb/testsuite/gdb.base/pending.c:26
>         stop only if k==1 thread 1
> 
> Shouldn't there be some kind of cleanup in set_breakpoint_condition()?

Indeed.  Hmm, that, or disable the location, with a warning.  We parse the condition in the
context of each location.  A condition might well make sense and parse okay
for a location, but not for another (e.g., different locals/parameters).  Disabling
is also what we do if we fail to parse a location later on with "break foo if bar".

> Yes, that makes sense.  In that case, set_breakpoint_condition() 
> would need to parse the condition even if the bp was pending.
> This would fit well with needed cleanup of set_breakpoint_condition()
> mentioned above.
> 

> Should I write a patch for this? (I'm leaving for vacation on Friday,
> so this may not happen very soon.)

I've already got something in the works.  Let me see if I can finish it.
And I'm leaving for vacation at the end of the week too.  :-)

-- 
Pedro Alves


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

* Re: [Patch] Cannot set pending bp if condition set explicitly
  2012-07-30 15:19         ` Pedro Alves
@ 2012-07-30 15:36           ` Tom Tromey
  2012-08-03  0:44           ` disable breakpoints with invalid condition (Re: [Patch] Cannot set pending bp if condition set explicitly) Pedro Alves
  1 sibling, 0 replies; 10+ messages in thread
From: Tom Tromey @ 2012-07-30 15:36 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Marc Khouzam, 'gdb-patches@sourceware.org'

>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> An alternative would be to restrict pending breakpoints conditions
Pedro> to globals only.  Not sure whether that would fly.

Yeah, I'd rather not.

For example, it would mean that a breakpoint that examines function
arguments would work fine if the function was in the main program; but
if you refactored the code to move it to a shared library, it would not
work.

Also it seems to me that you'd have to add extra semantics to decide
what to do in the re-run case, where a conditional breakpoint is set in
a .so that is loaded at some point during the run.  Here, won't the
breakpoint convert itself to pending, and then back when the .so is
loaded?  Would this then mean that the expression is interpreted
differently?

Tom


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

* disable breakpoints with invalid condition (Re: [Patch] Cannot set pending bp if condition set explicitly)
  2012-07-30 15:19         ` Pedro Alves
  2012-07-30 15:36           ` Tom Tromey
@ 2012-08-03  0:44           ` Pedro Alves
  1 sibling, 0 replies; 10+ messages in thread
From: Pedro Alves @ 2012-08-03  0:44 UTC (permalink / raw)
  Cc: Marc Khouzam, 'Tom Tromey', 'gdb-patches@sourceware.org'

On 07/30/2012 04:18 PM, Pedro Alves wrote:
>>> >> This currently works:
>>> >>
>>> >>  (gdb) b main if 1 == 1 thread 1
>>> >>  Breakpoint 2 at 0x4572bb: file ../../src/gdb/gdb.c, line 29.
>>> >>
>>> >> But this does not:
>>> >>
>>> >>  (gdb) condition 2 1 == 1 thread 1
>>> >>  Junk at end of expression
>> > 
>> > On a side-note, I see that although there is an error printed and 
>> > set_breakpoint_condition() is aborted, the bad condition is not
>> > cleaned-up, as shown here:
>> > 
>> > (gdb) info b
>> > Num     Type           Disp Enb Address    What
>> > 1       breakpoint     keep y   0x0804851d in main at ../../../src/gdb/testsuite/gdb.base/pending.c:26
>> >         stop only if k==1 thread 1
>> > 
>> > Shouldn't there be some kind of cleanup in set_breakpoint_condition()?
> Indeed.  Hmm, that, or disable the location, with a warning.  We parse the condition in the
> context of each location.  A condition might well make sense and parse okay
> for a location, but not for another (e.g., different locals/parameters).  Disabling
> is also what we do if we fail to parse a location later on with "break foo if bar".
> 

Here's a patch implementing this idea.  Examples (currently, the condition text
is left stale, and the breakpoint becomes uncondition):

(gdb) b main
Breakpoint 2 at 0x4572bb: file ../../src/gdb/gdb.c, line 29.
(gdb) condition 2 foo bar
warning: Breakpoint 2.1 disabled: No symbol "foo" in current context.
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   <MULTIPLE>
        stop only if foo bar
2.1                         n     0x00000000004572bb in main at ../../src/gdb/gdb.c:29
(gdb) condition 2
Breakpoint 2 now unconditional.
(gdb) enable 2.1
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004572bb in main at ../../src/gdb/gdb.c:29

(gdb) watch args
Hardware watchpoint 3: args
(gdb) condition 3
Breakpoint 3 now unconditional.
(gdb) condition 3 foo bar
warning: Watchpoint 3 disabled: No symbol "foo" in current context.
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004572bb in main at ../../src/gdb/gdb.c:29
3       hw watchpoint  keep n                      args
        stop only if foo bar
(gdb) condition 3 1 == 1 thread 1
warning: Watchpoint 3 disabled - junk at end of expression: thread 1
(gdb)

There are several little details we get wrong that I haven't addressed.
For instance, in this case, the re-enabling of a watchpoint is prevented:

(gdb) condition 3 asdf
warning: Watchpoint 3 disabled: No symbol "asdf" in current context.
(gdb) info breakpoints 3
Num     Type           Disp Enb Address            What
3       hw watchpoint  keep n                      args
        stop only if asdf
        breakpoint already hit 1 time
(gdb) enable 3
Cannot enable watchpoint 3: No symbol "asdf" in current context.

While this doesn't:

(gdb) condition 3 1 == 1 thread 1
warning: Watchpoint 3 disabled - junk at end of expression: thread 1
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004572bb in main at ../../src/gdb/gdb.c:29
3       hw watchpoint  keep n                      args
        stop only if 1 == 1 thread 1
        breakpoint already hit 1 time
(gdb) enable 3
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004572bb in main at ../../src/gdb/gdb.c:29
3       hw watchpoint  keep y                      args
        stop only if 1 == 1 thread 1
        breakpoint already hit 1 time
(gdb)

For regular breakpoints, you can always "enable" them, but when you let
the program run, you'll find they are unconditional, and if something causes
a re-set, they get disabled again:

warning: failed to reevaluate condition for breakpoint 4: blah blah.


I'd appreciate hearing opinions on whether this change is a good direction or not.

macscp.exp had a case of an invalid condition being set on a breakpoint, and then
the test assuming the breakpoint would be hit.

2012-08-02  Pedro Alves  <palves@redhat.com>

	gdb/
	* breakpoint.c (set_breakpoint_condition): If condition fails to
	parse, disable the watchpoint or breakpoint location, and warn.

	gdb/doc/
	* gdb.texinfo (condition command): Mention that locations are
	disabled when the condition has a problem.

	gdb/testsuite/
	* gdb.base/condbreak.exp: New tests for invalid conditions with
	"condition" command.
	* gdb.base/macscp.exp: After setting an invalid condition to a
	breakpoint, make the breakpoint unconditional and re-enable it.

---

 gdb/testsuite/gdb.base/condbreak.exp |    9 +++++++++
 gdb/testsuite/gdb.base/macscp.exp    |    7 +++++++
 2 files changed, 16 insertions(+)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 03719d4..b8484a7 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -956,26 +956,59 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
       if (is_watchpoint (b))
 	{
 	  struct watchpoint *w = (struct watchpoint *) b;
+	  volatile struct gdb_exception e;

 	  innermost_block = NULL;
 	  arg = exp;
-	  w->cond_exp = parse_exp_1 (&arg, 0, 0, 0);
-	  if (*arg)
-	    error (_("Junk at end of expression"));
-	  w->cond_exp_valid_block = innermost_block;
+	  TRY_CATCH (e, RETURN_MASK_ERROR)
+	    {
+	      w->cond_exp = parse_exp_1 (&arg, 0, 0, 0);
+	    }
+	  if (e.reason < 0)
+	    {
+	      b->enable_state = bp_disabled;
+	      warning (_("Watchpoint %d disabled: %s"),
+		     b->number, e.message);
+	    }
+	  else if (*arg)
+	    {
+	      b->enable_state = bp_disabled;
+	      warning (_("Watchpoint %d disabled - "
+		       "junk at end of expression: %s"),
+		     b->number, arg);
+	    }
+	  else
+	    w->cond_exp_valid_block = innermost_block;
 	}
       else
 	{
 	  struct bp_location *loc;
+	  int loc_n;

-	  for (loc = b->loc; loc; loc = loc->next)
+	  for (loc = b->loc, loc_n = 1; loc; loc = loc->next, loc_n++)
 	    {
+	      volatile struct gdb_exception e;
+
 	      arg = exp;
-	      loc->cond =
-		parse_exp_1 (&arg, loc->address,
-			     block_for_pc (loc->address), 0);
-	      if (*arg)
-		error (_("Junk at end of expression"));
+
+	      TRY_CATCH (e, RETURN_MASK_ERROR)
+		{
+		  loc->cond = parse_exp_1 (&arg, loc->address,
+					   block_for_pc (loc->address), 0);
+		}
+	      if (e.reason < 0)
+		{
+		  loc->enabled = 0;
+		  warning (_("Breakpoint %d.%d disabled: %s"),
+			   b->number, loc_n, e.message);
+		}
+	      else if (*arg)
+		{
+		  loc->enabled = 0;
+		  warning (_("Breakpoint %d.%d disabled - "
+			     "junk at end of expression: %s"),
+			   b->number, loc_n, arg);
+		}
 	    }
 	}
     }
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index facca8f..8518d2f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4487,11 +4487,12 @@ breakpoint @var{bnum} stops your program only if the value of
 @code{condition}, @value{GDBN} checks @var{expression} immediately for
 syntactic correctness, and to determine whether symbols in it have
 referents in the context of your breakpoint.  If @var{expression} uses
-symbols not referenced in the context of the breakpoint, @value{GDBN}
-prints an error message:
+symbols not referenced in the context any of the breakpoint's
+locations, @value{GDBN} prints a warning message and disables the
+corresponding location:

 @smallexample
-No symbol "foo" in current context.
+warning: Breakpoint 1.1 disabled: No symbol "foo" in current context.
 @end smallexample

 @noindent
diff --git a/gdb/testsuite/gdb.base/condbreak.exp b/gdb/testsuite/gdb.base/condbreak.exp
index e8e0d84..9d91fab 100644
--- a/gdb/testsuite/gdb.base/condbreak.exp
+++ b/gdb/testsuite/gdb.base/condbreak.exp
@@ -266,3 +266,12 @@ gdb_test "complete cond 1" "cond 1"
 gdb_test "set variable \$var = 1"
 gdb_test "complete cond \$v" "cond \\\$var"
 gdb_test "complete cond 1 values\[0\].a" "cond 1 values.0..a_field"
+
+gdb_test "cond 1 foo bar" ".*" "set invalid condition"
+
+gdb_test "info break 1" \
+    "Num     Type\[ \]+Disp Enb Address\[ \]+What.*
+1\[\t \]+breakpoint     keep y.* <MULTIPLE>.*
+\[\t \]+stop only if foo bar.*
+1.1\[\t \]+n\[\t \]+.*in main at .*$srcfile:$bp_location6.*" \
+    "location with invalid condition is disabled"
diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp
index 1f995d5..ad18245 100644
--- a/gdb/testsuite/gdb.base/macscp.exp
+++ b/gdb/testsuite/gdb.base/macscp.exp
@@ -444,6 +444,13 @@ gdb_test "cond \$bpnum foo == MACRO_TO_EXPAND" \
   "No symbol \"MACRO_TO_EXPAND\" in current context\." \
   "macro MACRO_TO_EXPAND not in scope at breakpoint"

+gdb_test "cond \$bpnum" \
+  "Breakpoint .* now unconditional\." \
+  "make breakpoint unconditional"
+
+gdb_test_no_output "enable \$bpnum.1" \
+  "re-enable breakpoint"
+
 # Note that we choose the condition so that this breakpoint never
 # stops.
 set l2 [gdb_get_line_number "set second breakpoint here"]


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

* Re: [Patch] Cannot set pending bp if condition set explicitly
  2012-07-26 19:05     ` Pedro Alves
  2012-07-27  2:45       ` Marc Khouzam
@ 2012-08-03  0:51       ` Pedro Alves
  1 sibling, 0 replies; 10+ messages in thread
From: Pedro Alves @ 2012-08-03  0:51 UTC (permalink / raw)
  To: 'gdb-patches@sourceware.org'; +Cc: Marc Khouzam, 'Tom Tromey'

On 07/26/2012 08:05 PM, Pedro Alves wrote:

> Not sure yet what is the best predicate to put there.
> The whole condition looks a bit in need of TLC.  all_locations_are_pending would
> return true if all locations had been shlib_disabled.  The condition does
> also check for shlib_disabled, but only on the first location.  Especially now
> that breakpoints can have locations anywhere, I think we might need to consider
> what happens and what should happen to when only a few of the conditions
> are shlib_disabled..
> 
> WDYT?  I'll try to give this predicate a bit more thought (but I'm running
> out of day for today), but these are my thoughts so far.

I left the condition as is for now.  A pending breakpoint has no locations, and when
a shared library is unloaded, the locations remain (though disabled), so I think
this should be equivalent to the original intention.  So essentially, this is the
same patch as before, now with ChangeLog and with your test.

2012-08-02  Pedro Alves  <palves@redhat.com>
	    Marc Khouzam  <marc.khouzam@ericsson.com>

	* breakpoint.c (create_breakpoint): Only set condition_not_parsed
	if PARSE_CONDITION_AND_THREAD is true.
	(addr_string_to_sals): Consider NOT_FOUND_ERROR okay when there
	are no locations yet, instead of when CONDITION_NOT_PARSED is
	true.

2012-08-02  Marc Khouzam  <marc.khouzam@ericsson.com>

	* gdb.base/pendshr.c: Extra line to set a new breakpoint.
	* gdb.base/pending.exp: Set an enabled pending breakpoint
	with an explicit condition.
---

 gdb/testsuite/gdb.base/pending.exp |   57 ++++++++++++++++++++++++++++++------
 gdb/testsuite/gdb.base/pendshr.c   |    1 +
 2 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index b8484a7..605dee2 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -9591,7 +9591,10 @@ create_breakpoint (struct gdbarch *gdbarch,

       b->addr_string = copy_arg;
       if (parse_condition_and_thread)
-	b->cond_string = NULL;
+	{
+	  b->cond_string = NULL;
+	  b->condition_not_parsed = 1;
+	}
       else
 	{
 	  /* Create a private copy of condition string.  */
@@ -9605,7 +9608,6 @@ create_breakpoint (struct gdbarch *gdbarch,
       b->extra_string = NULL;
       b->ignore_count = ignore_count;
       b->disposition = tempflag ? disp_del : disp_donttouch;
-      b->condition_not_parsed = 1;
       b->enable_state = enabled ? bp_enabled : bp_disabled;
       if ((type_wanted != bp_breakpoint
            && type_wanted != bp_hardware_breakpoint) || thread != -1)
@@ -14041,7 +14043,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
 	 breakpoint being disabled, and don't want to see more
 	 errors.  */
       if (e.error == NOT_FOUND_ERROR
-	  && (b->condition_not_parsed
+	  && (b->loc == NULL
 	      || (b->loc && b->loc->shlib_disabled)
 	      || (b->loc && b->loc->pspace->executing_startup)
 	      || b->enable_state == bp_disabled))
diff --git a/gdb/testsuite/gdb.base/pending.exp b/gdb/testsuite/gdb.base/pending.exp
index 79c4576..910c917 100644
--- a/gdb/testsuite/gdb.base/pending.exp
+++ b/gdb/testsuite/gdb.base/pending.exp
@@ -209,6 +209,32 @@ gdb_test "info break" \
 "multiple pending breakpoints 2"

 #
+# Try a pending break with an explicit condition which is enabled at startup
+#
+
+set bp5_loc [gdb_get_line_number "y++" ${libfile}.c]
+gdb_test_multiple "break pendshr.c:$bp5_loc" "Set pending breakpoint 4" {
+     -re ".*Make breakpoint pending.*y or \\\[n\\\]. $" {
+           gdb_test "y" "Breakpoint.*pendshr.c:$bp5_loc.*pending." \
+               "Set pending breakpoint 5"
+     }
+}
+
+gdb_test_no_output "condition 5 k == 1"
+
+gdb_test "info break" \
+    "Num     Type\[ \]+Disp Enb Address\[ \]+What.*
+\[0-9\]+\[\t \]+breakpoint     keep n.*PENDING.*pendfunc1.*
+\[\t \]+stop only if k == 1.*
+\[\t \]+print k.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in main at .*$srcfile:$mainline.*
+\[0-9\]+\[\t \]+breakpoint     keep y.*PENDING.*pendshr.c:$bp2_loc if x > 3.*
+\[0-9\]+\[\t \]+breakpoint     keep y.*PENDING.*pendshr.c:$bp3_loc.*ignore next 2 hits.*
+\[0-9\]+\[\t \]+breakpoint     keep y.*PENDING.*pendshr.c:$bp5_loc.*
+\[\t \]+stop only if k == 1.*" \
+"multiple pending breakpoints 3"
+
+#
 # Run to main which should resolve a pending breakpoint
 #

@@ -218,6 +244,24 @@ gdb_test "" \
 "running to main"

 #
+# Verify that all pending breakpoints have resolved.
+#
+gdb_test "info break" \
+    "Num     Type\[ \]+Disp Enb Address\[ \]+What.*
+\[0-9\]+\[\t \]+breakpoint     keep n.* in pendfunc1 at .*
+\[\t \]+stop only if k == 1.*
+\[\t \]+print k.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in main at .*$srcfile:$mainline.*
+\[\t \]+breakpoint already hit 1 time.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in pendfunc1 at .*pendshr.c:$bp2_loc.*
+\[\t \]+stop only if x > 3.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in pendfunc1 at .*pendshr.c:$bp3_loc.*
+\[\t \]+ignore next 2 hits.*
+\[0-9\]+\[\t \]+breakpoint     keep y.* in pendfunc1 at .*pendshr.c:$bp5_loc.*
+\[\t \]+stop only if k == 1.*" \
+"multiple pending breakpoints 4"
+
+#
 # Re-enable the first pending breakpoint which should resolve
 #

@@ -237,19 +281,14 @@ gdb_test "continue" \
 \[$\]1 = 1." \
 "continue to resolved breakpoint 1"

-#
-# Disable the other two breakpoints, and continue to the one with
-# the ignore count.  Make sure you hit it the third time, x should
-# be 3 then.
-#
-
-gdb_test "disable 7" "" "Disable other breakpoints"
-gdb_test "disable 5" "" "Disable other breakpoints"
-
 gdb_test "continue" \
 	 ".*Breakpoint.*pendfunc1.*\\\(x=3\\\) at.*pendshr.c:$bp3_loc.*printf.*;" \
 "continue to resolved breakpoint 3"

+gdb_test "continue" \
+        ".*Breakpoint.*pendfunc1.*\\\(x=3\\\) at.*pendshr.c:$bp5_loc.*y\\+\\+;" \
+"continue to resolved breakpoint 5"
+
 delete_breakpoints

 gdb_breakpoint "main"
diff --git a/gdb/testsuite/gdb.base/pendshr.c b/gdb/testsuite/gdb.base/pendshr.c
index bc3b9e3..c5b40fd 100644
--- a/gdb/testsuite/gdb.base/pendshr.c
+++ b/gdb/testsuite/gdb.base/pendshr.c
@@ -21,6 +21,7 @@ void pendfunc1 (int x)
 {
   int y = x + 4;
   printf ("in pendfunc1, x is %d\n", x);
+  y++;
 }

 void pendfunc (int x)


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

end of thread, other threads:[~2012-08-03  0:51 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-24 14:45 [Patch] Cannot set pending bp if condition set explicitly Marc Khouzam
2012-07-25 15:28 ` Tom Tromey
2012-07-25 20:31   ` Marc Khouzam
2012-07-25 20:44     ` Tom Tromey
2012-07-26 19:05     ` Pedro Alves
2012-07-27  2:45       ` Marc Khouzam
2012-07-30 15:19         ` Pedro Alves
2012-07-30 15:36           ` Tom Tromey
2012-08-03  0:44           ` disable breakpoints with invalid condition (Re: [Patch] Cannot set pending bp if condition set explicitly) Pedro Alves
2012-08-03  0:51       ` [Patch] Cannot set pending bp if condition set explicitly Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox