]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
* breakpoint.c (fetch_watchpoint_value): New function.
authorDaniel Jacobowitz <drow@false.org>
Mon, 3 Mar 2008 13:24:12 +0000 (13:24 +0000)
committerDaniel Jacobowitz <drow@false.org>
Mon, 3 Mar 2008 13:24:12 +0000 (13:24 +0000)
(update_watchpoint): Set and clear val_valid.  Use
fetch_watchpoint_value.  Handle unreadable values on the
value chain.  Correct check for user-requested array watchpoints.
(breakpoint_init_inferior): Clear val_valid.
(watchpoint_value_print): New function.
(print_it_typical): Use it.  Do not free or clear old_val.  Print
watchpoints even if old_val == NULL.
(watchpoint_check): Use fetch_watchpoint_value.  Check for values
becoming readable or unreadable.
(watch_command_1): Use fetch_watchpoint_value.  Set val_valid.
(do_enable_watchpoint): Likewise.
* breakpoint.h (struct breakpoint): Update comment for val.  Add
val_valid.
* NEWS: Mention watchpoints on inaccessible memory.

* gdb.base/watchpoint.c (global_ptr, func4): New.
(main): Call func4.
* gdb.base/watchpoint.exp: Call test_inaccessible_watchpoint.
(test_inaccessible_watchpoint): New.

* gdb.texinfo (Set Watchpoints): Mention watchpoints on
unreadable memory.  Delete obsolete SPARClite reference.

gdb/ChangeLog
gdb/NEWS
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/watchpoint.c
gdb/testsuite/gdb.base/watchpoint.exp

index f23214c80be6fbf2e9df91bf8fac96dfc674427f..4d21120cf8867d1f4a38f999a52d1a6c24f9a6db 100644 (file)
@@ -1,3 +1,21 @@
+2008-03-03  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * breakpoint.c (fetch_watchpoint_value): New function.
+       (update_watchpoint): Set and clear val_valid.  Use
+       fetch_watchpoint_value.  Handle unreadable values on the
+       value chain.  Correct check for user-requested array watchpoints.
+       (breakpoint_init_inferior): Clear val_valid.
+       (watchpoint_value_print): New function.
+       (print_it_typical): Use it.  Do not free or clear old_val.  Print
+       watchpoints even if old_val == NULL.
+       (watchpoint_check): Use fetch_watchpoint_value.  Check for values
+       becoming readable or unreadable.
+       (watch_command_1): Use fetch_watchpoint_value.  Set val_valid.
+       (do_enable_watchpoint): Likewise.
+       * breakpoint.h (struct breakpoint): Update comment for val.  Add
+       val_valid.
+       * NEWS: Mention watchpoints on inaccessible memory.
+
 2007-02-29  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * Makefile.in (i386-nat.o): Update.
index 6bcd129c58c1acf13b6a9958bfc08ad766c23246..b689f8cdcfd7a6f3c36fb8a4ca4eaf44685a13c9 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -9,6 +9,9 @@ set debug timetstamp
 show debug timestamp
   Display timestamps with GDB debugging output.
 
+* Watchpoints can now be set on unreadable memory locations, e.g. addresses
+which will be allocated using malloc later in program execution.
+
 *** Changes in GDB 6.8
 
 * New native configurations
index a689e3ae44f6c677ea0e819a89679f5e945cb67c..8dc6f40127d3c6e863bbe1448213a9f98db1dfbc 100644 (file)
@@ -55,6 +55,7 @@
 #include "memattr.h"
 #include "ada-lang.h"
 #include "top.h"
+#include "wrapper.h"
 
 #include "gdb-events.h"
 #include "mi/mi-common.h"
@@ -826,7 +827,65 @@ is_hardware_watchpoint (struct breakpoint *bpt)
          || bpt->type == bp_access_watchpoint);
 }
 
-/* Assuming that B is a hardware breakpoint:
+/* Find the current value of a watchpoint on EXP.  Return the value in
+   *VALP and *RESULTP and the chain of intermediate and final values
+   in *VAL_CHAIN.  RESULTP and VAL_CHAIN may be NULL if the caller does
+   not need them.
+
+   If an error occurs while evaluating the expression, *RESULTP will
+   be set to NULL.  *RESULTP may be a lazy value, if the result could
+   not be read from memory.  It is used to determine whether a value
+   is user-specified (we should watch the whole value) or intermediate
+   (we should watch only the bit used to locate the final value).
+
+   If the final value, or any intermediate value, could not be read
+   from memory, *VALP will be set to NULL.  *VAL_CHAIN will still be
+   set to any referenced values.  *VALP will never be a lazy value.
+   This is the value which we store in struct breakpoint.
+
+   If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
+   value chain.  The caller must free the values individually.  If
+   VAL_CHAIN is NULL, all generated values will be left on the value
+   chain.  */
+
+static void
+fetch_watchpoint_value (struct expression *exp, struct value **valp,
+                       struct value **resultp, struct value **val_chain)
+{
+  struct value *mark, *new_mark, *result;
+
+  *valp = NULL;
+  if (resultp)
+    *resultp = NULL;
+  if (val_chain)
+    *val_chain = NULL;
+
+  /* Evaluate the expression.  */
+  mark = value_mark ();
+  result = NULL;
+  gdb_evaluate_expression (exp, &result);
+  new_mark = value_mark ();
+  if (mark == new_mark)
+    return;
+  if (resultp)
+    *resultp = result;
+
+  /* Make sure it's not lazy, so that after the target stops again we
+     have a non-lazy previous value to compare with.  */
+  if (result != NULL
+      && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
+    *valp = result;
+
+  if (val_chain)
+    {
+      /* Return the chain of intermediate values.  We use this to
+        decide which addresses to watch.  */
+      *val_chain = new_mark;
+      value_release_to_mark (mark);
+    }
+}
+
+/* Assuming that B is a hardware watchpoint:
    - Reparse watchpoint expression, is REPARSE is non-zero
    - Evaluate expression and store the result in B->val
    - Update the list of values that must be watched in B->loc.
@@ -837,7 +896,6 @@ static void
 update_watchpoint (struct breakpoint *b, int reparse)
 {
   int within_current_scope;
-  struct value *mark = value_mark ();
   struct frame_id saved_frame_id;
   struct bp_location *loc;
   bpstat bs;
@@ -889,9 +947,9 @@ update_watchpoint (struct breakpoint *b, int reparse)
         to the user when the old value and the new value may actually
         be completely different objects.  */
       value_free (b->val);
-      b->val = NULL;      
+      b->val = NULL;
+      b->val_valid = 0;
     }
-  
 
   /* If we failed to parse the expression, for example because
      it refers to a global variable in a not-yet-loaded shared library,
@@ -900,43 +958,37 @@ update_watchpoint (struct breakpoint *b, int reparse)
      is different from out-of-scope watchpoint.  */
   if (within_current_scope && b->exp)
     {
-      struct value *v, *next;
+      struct value *val_chain, *v, *result, *next;
 
-      /* Evaluate the expression and make sure it's not lazy, so that
-        after target stops again, we have a non-lazy previous value
-        to compare with. Also, making the value non-lazy will fetch
-        intermediate values as needed, which we use to decide which
-        addresses to watch.
+      fetch_watchpoint_value (b->exp, &v, &result, &val_chain);
 
-        The value returned by evaluate_expression is stored in b->val.
-        In addition, we look at all values which were created
-        during evaluation, and set watchoints at addresses as needed.
-        Those values are explicitly deleted here.  */
-      v = evaluate_expression (b->exp);
       /* Avoid setting b->val if it's already set.  The meaning of
         b->val is 'the last value' user saw, and we should update
         it only if we reported that last value to user.  As it
         happens, the code that reports it updates b->val directly.  */
-      if (b->val == NULL)
-       b->val = v;
-      value_contents (v);
-      value_release_to_mark (mark);
+      if (!b->val_valid)
+       {
+         b->val = v;
+         b->val_valid = 1;
+       }
 
       /* Look at each value on the value chain.  */
-      for (; v; v = next)
+      for (v = val_chain; v; v = next)
        {
          /* If it's a memory location, and GDB actually needed
             its contents to evaluate the expression, then we
-            must watch it.  */
+            must watch it.  If the first value returned is
+            still lazy, that means an error occurred reading it;
+            watch it anyway in case it becomes readable.  */
          if (VALUE_LVAL (v) == lval_memory
-             && ! value_lazy (v))
+             && (v == val_chain || ! value_lazy (v)))
            {
              struct type *vtype = check_typedef (value_type (v));
 
              /* We only watch structs and arrays if user asked
                 for it explicitly, never if they just happen to
                 appear in the middle of some value chain.  */
-             if (v == b->val
+             if (v == result
                  || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
                      && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
                {
@@ -1681,6 +1733,7 @@ breakpoint_init_inferior (enum inf_context context)
            if (b->val)
              value_free (b->val);
            b->val = NULL;
+           b->val_valid = 0;
          }
        break;
       default:
@@ -2103,6 +2156,17 @@ top:
   do_cleanups (old_chain);
 }
 
+/* Print out the (old or new) value associated with a watchpoint.  */
+
+static void
+watchpoint_value_print (struct value *val, struct ui_file *stream)
+{
+  if (val == NULL)
+    fprintf_unfiltered (stream, _("<unreadable>"));
+  else
+    value_print (val, stream, 0, Val_pretty_default);
+}
+
 /* This is the normal print function for a bpstat.  In the future,
    much of this logic could (should?) be moved to bpstat_stop_status,
    by having it set different print_it values.
@@ -2221,26 +2285,21 @@ print_it_typical (bpstat bs)
 
     case bp_watchpoint:
     case bp_hardware_watchpoint:
-      if (bs->old_val != NULL)
-       {
-         annotate_watchpoint (b->number);
-         if (ui_out_is_mi_like_p (uiout))
-           ui_out_field_string
-             (uiout, "reason",
-              async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
-         mention (b);
-         ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-         ui_out_text (uiout, "\nOld value = ");
-         value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
-         ui_out_field_stream (uiout, "old", stb);
-         ui_out_text (uiout, "\nNew value = ");
-         value_print (b->val, stb->stream, 0, Val_pretty_default);
-         ui_out_field_stream (uiout, "new", stb);
-         do_cleanups (ui_out_chain);
-         ui_out_text (uiout, "\n");
-         value_free (bs->old_val);
-         bs->old_val = NULL;
-       }
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+       ui_out_field_string
+         (uiout, "reason",
+          async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      mention (b);
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+      ui_out_text (uiout, "\nOld value = ");
+      watchpoint_value_print (bs->old_val, stb->stream);
+      ui_out_field_stream (uiout, "old", stb);
+      ui_out_text (uiout, "\nNew value = ");
+      watchpoint_value_print (b->val, stb->stream);
+      ui_out_field_stream (uiout, "new", stb);
+      do_cleanups (ui_out_chain);
+      ui_out_text (uiout, "\n");
       /* More than one watchpoint may have been triggered.  */
       return PRINT_UNKNOWN;
       break;
@@ -2253,7 +2312,7 @@ print_it_typical (bpstat bs)
       mention (b);
       ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
       ui_out_text (uiout, "\nValue = ");
-      value_print (b->val, stb->stream, 0, Val_pretty_default);
+      watchpoint_value_print (b->val, stb->stream);
       ui_out_field_stream (uiout, "value", stb);
       do_cleanups (ui_out_chain);
       ui_out_text (uiout, "\n");
@@ -2261,7 +2320,7 @@ print_it_typical (bpstat bs)
       break;
 
     case bp_access_watchpoint:
-      if (bs->old_val != NULL)     
+      if (bs->old_val != NULL)
        {
          annotate_watchpoint (b->number);
          if (ui_out_is_mi_like_p (uiout))
@@ -2271,10 +2330,8 @@ print_it_typical (bpstat bs)
          mention (b);
          ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
          ui_out_text (uiout, "\nOld value = ");
-         value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
+         watchpoint_value_print (bs->old_val, stb->stream);
          ui_out_field_stream (uiout, "old", stb);
-         value_free (bs->old_val);
-         bs->old_val = NULL;
          ui_out_text (uiout, "\nNew value = ");
        }
       else 
@@ -2287,7 +2344,7 @@ print_it_typical (bpstat bs)
          ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
          ui_out_text (uiout, "\nValue = ");
        }
-      value_print (b->val, stb->stream, 0,Val_pretty_default);
+      watchpoint_value_print (b->val, stb->stream);
       ui_out_field_stream (uiout, "new", stb);
       do_cleanups (ui_out_chain);
       ui_out_text (uiout, "\n");
@@ -2574,13 +2631,20 @@ watchpoint_check (void *p)
          we might be in the middle of evaluating a function call.  */
 
       struct value *mark = value_mark ();
-      struct value *new_val = evaluate_expression (b->exp);
-      if (!value_equal (b->val, new_val))
+      struct value *new_val;
+
+      fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
+      if ((b->val != NULL) != (new_val != NULL)
+         || (b->val != NULL && !value_equal (b->val, new_val)))
        {
-         release_value (new_val);
-         value_free_to_mark (mark);
+         if (new_val != NULL)
+           {
+             release_value (new_val);
+             value_free_to_mark (mark);
+           }
          bs->old_val = b->val;
          b->val = new_val;
+         b->val_valid = 1;
          /* We will stop here */
          return WP_VALUE_CHANGED;
        }
@@ -5746,10 +5810,9 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
   exp_end = arg;
   exp_valid_block = innermost_block;
   mark = value_mark ();
-  val = evaluate_expression (exp);
-  release_value (val);
-  if (value_lazy (val))
-    value_fetch_lazy (val);
+  fetch_watchpoint_value (exp, &val, NULL, NULL);
+  if (val != NULL)
+    release_value (val);
 
   tok = arg;
   while (*tok == ' ' || *tok == '\t')
@@ -5838,6 +5901,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
   b->exp_valid_block = exp_valid_block;
   b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
+  b->val_valid = 1;
   b->loc->cond = cond;
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -7721,11 +7785,11 @@ is valid is not currently in scope.\n"), bpt->number);
       if (bpt->val)
        value_free (bpt->val);
       mark = value_mark ();
-      bpt->val = evaluate_expression (bpt->exp);
-      release_value (bpt->val);
-      if (value_lazy (bpt->val))
-       value_fetch_lazy (bpt->val);
-      
+      fetch_watchpoint_value (bpt->exp, &bpt->val, NULL, NULL);
+      if (bpt->val)
+       release_value (bpt->val);
+      bpt->val_valid = 1;
+
       if (bpt->type == bp_hardware_watchpoint ||
          bpt->type == bp_read_watchpoint ||
          bpt->type == bp_access_watchpoint)
index 41730c0b311f108b59bc82684962b458561c1da4..16bb927c6fbd65e53b65e3818ad66bc8d8e8cd53 100644 (file)
@@ -391,8 +391,13 @@ struct breakpoint
     /* The largest block within which it is valid, or NULL if it is
        valid anywhere (e.g. consists just of global symbols).  */
     struct block *exp_valid_block;
-    /* Value of the watchpoint the last time we checked it.  */
+    /* Value of the watchpoint the last time we checked it, or NULL
+       when we do not know the value yet or the value was not
+       readable.  VAL is never lazy.  */
     struct value *val;
+    /* Nonzero if VAL is valid.  If VAL_VALID is set but VAL is NULL,
+       then an error occurred reading the value.  */
+    int val_valid;
 
     /* Holds the address of the related watchpoint_scope breakpoint
        when using watchpoints on local variables (might the concept
index 95d94d99d97b29ba8725ee821d6fbecbaf99dc70..6e688990f5ba19bc5a3c27232cfbba7c5a38c01f 100644 (file)
@@ -1,3 +1,8 @@
+2008-03-03  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.texinfo (Set Watchpoints): Mention watchpoints on
+       unreadable memory.  Delete obsolete SPARClite reference.
+
 2008-02-28  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * gdb.texinfo (Starting): Mention always-running targets.
index dfc6e813a894dac5ff3bb41c3cb48374de4ec6e7..1a0e9d263e0bab75eb1d38dedaf49c941cbf7624 100644 (file)
@@ -3211,6 +3211,16 @@ expression can use any operators valid in the program's native
 language (@pxref{Languages}).
 @end itemize
 
+You can set a watchpoint on an expression even if the expression can
+not be evaluated yet.  For instance, you can set a watchpoint on
+@samp{*global_ptr} before @samp{global_ptr} is initialized.
+@value{GDBN} will stop when your program sets @samp{global_ptr} and
+the expression produces a valid value.  If the expression becomes
+valid in some other way than changing a variable (e.g.@: if the memory
+pointed to by @samp{*global_ptr} becomes readable as the result of a
+@code{malloc} call), @value{GDBN} may not stop until the next time
+the expression changes.
+
 @cindex software watchpoints
 @cindex hardware watchpoints
 Depending on your system, watchpoints may be implemented in software or
@@ -3338,17 +3348,6 @@ exhaust the resources available for hardware-assisted watchpoints.
 That's because @value{GDBN} needs to watch every variable in the
 expression with separately allocated resources.
 
-The SPARClite DSU will generate traps when a program accesses some data
-or instruction address that is assigned to the debug registers.  For the
-data addresses, DSU facilitates the @code{watch} command.  However the
-hardware breakpoint registers can only take two data watchpoints, and
-both watchpoints must be the same kind.  For example, you can set two
-watchpoints with @code{watch} commands, two with @code{rwatch} commands,
-@strong{or} two with @code{awatch} commands, but you cannot set one
-watchpoint with one command and the other with a different command.
-@value{GDBN} will reject the command if you try to mix watchpoints.
-Delete or disable unused watchpoint commands before setting new ones.
-
 If you call a function interactively using @code{print} or @code{call},
 any watchpoints you have set will be inactive until @value{GDBN} reaches another
 kind of breakpoint or the call completes.
index 3886227fd8878fcda006acf3b3bcfb5310dd1742..fc2a39ca5d6aa58cdefe255931a5377f17ac811d 100644 (file)
@@ -1,3 +1,10 @@
+2008-03-03  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.base/watchpoint.c (global_ptr, func4): New.
+       (main): Call func4.
+       * gdb.base/watchpoint.exp: Call test_inaccessible_watchpoint.
+       (test_inaccessible_watchpoint): New.
+
 2008-02-29  Maciej W. Rozycki  <macro@mips.com>
 
        * lib/gdb.exp (gdb_expect): Of all the timeouts provided always
index 1a61ba1652147231afbd6bda1036742397e6e134..bba97fad99de867bd981a6437cb50c035752ebb9 100644 (file)
@@ -39,6 +39,8 @@ struct foo struct1, struct2, *ptr1, *ptr2;
 
 int doread = 0;
 
+char *global_ptr;
+
 void marker1 ()
 {
 }
@@ -110,6 +112,14 @@ func1 ()
   return 73;
 }
 
+void
+func4 ()
+{
+  buf[0] = 3;
+  global_ptr = buf;
+  buf[0] = 7;
+}
+
 int main ()
 {
 #ifdef usestubs
@@ -185,5 +195,7 @@ int main ()
 
   func3 ();
 
+  func4 ();
+
   return 0;
 }
index d27179de667a3f0a657a20710daf80d9cf6f9949..3c20d10e4fbccac7407f862bb80effcaa4c79cc7 100644 (file)
@@ -645,6 +645,30 @@ proc test_watchpoint_and_breakpoint {} {
     }
 }
     
+proc test_inaccessible_watchpoint {} {
+    global gdb_prompt
+
+    # This is a test for watchpoints on currently inaccessible (but later
+    # valid) memory.
+
+    if [runto func4] then {
+       gdb_test "watch *global_ptr" ".*atchpoint \[0-9\]+: \\*global_ptr"
+       gdb_test "next" ".*global_ptr = buf.*"
+       gdb_test_multiple "next" "next over ptr init" {
+           -re ".*atchpoint \[0-9\]+: \\*global_ptr\r\n\r\nOld value = .*\r\nNew value = 3 .*\r\n.*$gdb_prompt $" {
+               # We can not test for <unknown> here because NULL may be readable.
+               # This test does rely on *NULL != 3.
+               pass "next over ptr init"
+           }
+       }
+       gdb_test_multiple "next" "next over buffer set" {
+           -re ".*atchpoint \[0-9\]+: \\*global_ptr\r\n\r\nOld value = 3 .*\r\nNew value = 7 .*\r\n.*$gdb_prompt $" {
+               pass "next over buffer set"
+           }
+       }
+    }
+}
+    
 # Start with a fresh gdb.
 
 gdb_exit
@@ -797,6 +821,8 @@ if [initialize] then {
       }
     }
 
+    test_inaccessible_watchpoint
+
     # See above.
     if [istarget "mips-idt-*"] then {
        gdb_exit