Use watchpoint's language when re-parsing expression
authorTom Tromey <tom@tromey.com>
Sun, 14 May 2017 17:12:14 +0000 (11:12 -0600)
committerTom Tromey <tom@tromey.com>
Sat, 20 May 2017 03:23:16 +0000 (21:23 -0600)
PR rust/21484 notes that watch -location does not work with Rust:

    (gdb) watch -location a
    syntax error in expression, near `) 0x00007fffffffe0f4'.

update_watchpoint tries to tell gdb that the new expression it creates
has C syntax:

      /* The above expression is in C.  */
      b->language = language_c;

However, update_watchpoint doesn't actually use this language when
re-parsing the expression.

Originally I was going to fix this by saving and restoring the
language in update_watchpoint, but this regressed
gdb.dlang/watch-loc.exp, because the constructed expression actually
has D syntax (specifically the name is not parseable by C).

Next I looked at directly constructing an expression, and not relying
on the parser at all; but it seemed to me that upon a re-set, we'd
want to reparse the type, and there is no existing API to do this
correctly.

So, in the end I made a hook to let each language choose what
expression to use.  I made all the languages other than Rust use the C
expression, because that is the status quo ante.  However, this is
probably not truly correct.  After this patch, at least, it is easy to
correct by someone who knows the language(s) in question.

Regtested by the buildbot.

ChangeLog
2017-05-19  Tom Tromey  <tom@tromey.com>

PR rust/21484:
* rust-lang.c (exp_descriptor_rust): New function.
(rust_language_defn): Use it.
* p-lang.c (pascal_language_defn): Update.
* opencl-lang.c (opencl_language_defn): Update.
* objc-lang.c (objc_language_defn): Update.
* m2-lang.c (m2_language_defn): Update.
* language.h (struct language_defn)
<la_watch_location_expression>: New member.
* language.c (unknown_language_defn, auto_language_defn)
(local_language_defn): Update.
* go-lang.c (go_language_defn): Update.
* f-lang.c (f_language_defn): Update.
* d-lang.c (d_language_defn): Update.
* c-lang.h (c_watch_location_expression): Declare.
* c-lang.c (c_watch_location_expression): New function.
(c_language_defn, cplus_language_defn, asm_language_defn)
(minimal_language_defn): Use it.
* breakpoint.c (watch_command_1): Call
la_watch_location_expression.
* ada-lang.c (ada_language_defn): Update.

testsuite/ChangeLog
2017-05-19  Tom Tromey  <tom@tromey.com>

PR rust/21484:
* gdb.rust/watch.exp: New file.
* gdb.rust/watch.rs: New file.

18 files changed:
gdb/ChangeLog
gdb/ada-lang.c
gdb/breakpoint.c
gdb/c-lang.c
gdb/c-lang.h
gdb/d-lang.c
gdb/f-lang.c
gdb/go-lang.c
gdb/language.c
gdb/language.h
gdb/m2-lang.c
gdb/objc-lang.c
gdb/opencl-lang.c
gdb/p-lang.c
gdb/rust-lang.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.rust/watch.exp [new file with mode: 0644]
gdb/testsuite/gdb.rust/watch.rs [new file with mode: 0644]

index 59fa9510c02d67da1df16cb94dfa20d99723a455..1cc5dc9d59e5a8654bb39441eb6f0b4c9ed2feea 100644 (file)
@@ -1,3 +1,27 @@
+2017-05-19  Tom Tromey  <tom@tromey.com>
+
+       PR rust/21484:
+       * rust-lang.c (exp_descriptor_rust): New function.
+       (rust_language_defn): Use it.
+       * p-lang.c (pascal_language_defn): Update.
+       * opencl-lang.c (opencl_language_defn): Update.
+       * objc-lang.c (objc_language_defn): Update.
+       * m2-lang.c (m2_language_defn): Update.
+       * language.h (struct language_defn)
+       <la_watch_location_expression>: New member.
+       * language.c (unknown_language_defn, auto_language_defn)
+       (local_language_defn): Update.
+       * go-lang.c (go_language_defn): Update.
+       * f-lang.c (f_language_defn): Update.
+       * d-lang.c (d_language_defn): Update.
+       * c-lang.h (c_watch_location_expression): Declare.
+       * c-lang.c (c_watch_location_expression): New function.
+       (c_language_defn, cplus_language_defn, asm_language_defn)
+       (minimal_language_defn): Use it.
+       * breakpoint.c (watch_command_1): Call
+       la_watch_location_expression.
+       * ada-lang.c (ada_language_defn): Update.
+
 2017-05-19  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        PR tui/21482
index 58c8a2efc90cd1300c7027a1d6c2e046ea6751e8..25c49c589fc7a64292138f764d03f6b4291cf491 100644 (file)
@@ -14047,6 +14047,7 @@ const struct language_defn ada_language_defn = {
   ada_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   ada_get_symbol_name_cmp,     /* la_get_symbol_name_cmp */
   ada_iterate_over_symbols,
   &ada_varobj_ops,
index 9d6a2f4eb8de6ac1fae06b443481cb08253dced4..150b08ca9d44aecc09783e349a4acf42ef920ef7 100644 (file)
@@ -11256,18 +11256,11 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
       struct type *t = value_type (val);
       CORE_ADDR addr = value_as_address (val);
 
-      t = check_typedef (TYPE_TARGET_TYPE (check_typedef (t)));
-
-      std::string name = type_to_string (t);
-
-      w->exp_string_reparse = xstrprintf ("* (%s *) %s", name.c_str (),
-                                         core_addr_to_string (addr));
+      w->exp_string_reparse
+       = current_language->la_watch_location_expression (t, addr).release ();
 
       w->exp_string = xstrprintf ("-location %.*s",
                                  (int) (exp_end - exp_start), exp_start);
-
-      /* The above expression is in C.  */
-      b->language = language_c;
     }
   else
     w->exp_string = savestring (exp_start, exp_end - exp_start);
index 19a8608a01ae251ba2d74ac2732bf8a1721fcd24..a6d533d082feec8a233a25f45c787cc8d18522d5 100644 (file)
@@ -712,7 +712,17 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
     }
   return evaluate_subexp_standard (expect_type, exp, pos, noside);
 }
+\f
+/* la_watch_location_expression for C.  */
 
+gdb::unique_xmalloc_ptr<char>
+c_watch_location_expression (struct type *type, CORE_ADDR addr)
+{
+  type = check_typedef (TYPE_TARGET_TYPE (check_typedef (type)));
+  std::string name = type_to_string (type);
+  return gdb::unique_xmalloc_ptr<char>
+    (xstrprintf ("* (%s *) %s", name.c_str (), core_addr_to_string (addr)));
+}
 
 \f
 /* Table mapping opcodes into strings for printing operators
@@ -865,6 +875,7 @@ const struct language_defn c_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &c_varobj_ops,
@@ -1008,6 +1019,7 @@ const struct language_defn cplus_language_defn =
   default_print_array_index,
   cp_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &cplus_varobj_ops,
@@ -1060,6 +1072,7 @@ const struct language_defn asm_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
@@ -1112,6 +1125,7 @@ const struct language_defn minimal_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index 974623897247c77e1756036985620f125fa1370e..5ce64861c42dfd03831eead0ee7dc3711803ea6a 100644 (file)
@@ -112,6 +112,9 @@ extern void c_emit_char (int c, struct type *type,
 
 extern const struct op_print c_op_print_tab[];
 
+extern gdb::unique_xmalloc_ptr<char> c_watch_location_expression
+     (struct type *type, CORE_ADDR addr);
+
 /* These are in c-typeprint.c: */
 
 extern void c_type_print_base (struct type *, struct ui_file *,
index 3ffdbdf5083db9b1f2aaeac40bd8a5311c0a695c..434b2e6ba5f3b4399ccc327c1b4e7926fc544f59 100644 (file)
@@ -244,6 +244,7 @@ static const struct language_defn d_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index 3c30d75627c52bf106be73f62222b907d706913f..a9663d415bcac1e0f247f4274bfff462ecc34e86 100644 (file)
@@ -287,6 +287,7 @@ const struct language_defn f_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index 88ddfb66be733745e1b6b4842a6e272e9114de5c..3b80cec4452baa1bb1d235ad05e9378d6456289b 100644 (file)
@@ -605,6 +605,7 @@ static const struct language_defn go_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,
   iterate_over_symbols,
   &default_varobj_ops,
index ee0101db74af2cb108b4e053dbdbc699d847639a..e9d9803aeee7401efc4a9ae1655785fe6f83bafa 100644 (file)
@@ -43,6 +43,7 @@
 #include "symfile.h"
 #include "cp-support.h"
 #include "frame.h"
+#include "c-lang.h"
 
 extern void _initialize_language (void);
 
@@ -859,6 +860,7 @@ const struct language_defn unknown_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
@@ -908,6 +910,7 @@ const struct language_defn auto_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
@@ -955,6 +958,7 @@ const struct language_defn local_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index 58bcbe8faec0f948000c7f4698a487d20b6f546c..cc0df8c5ce2747840f98c983843e91309f28c21f 100644 (file)
@@ -358,6 +358,12 @@ struct language_defn
     void (*la_get_string) (struct value *value, gdb_byte **buffer, int *length,
                           struct type **chartype, const char **charset);
 
+    /* Return an expression that can be used for a location
+       watchpoint.  TYPE is a pointer type that points to the memory
+       to watch, and ADDR is the address of the watched memory.  */
+    gdb::unique_xmalloc_ptr<char> (*la_watch_location_expression)
+         (struct type *type, CORE_ADDR addr);
+
     /* Return a pointer to the function that should be used to match
        a symbol name against LOOKUP_NAME. This is mostly for languages
        such as Ada where the matching algorithm depends on LOOKUP_NAME.
index 03b955cb63a889a94edd24a5e56010d39c0102d5..35840bf56f91b7bf0a5cc6f8de29a2743d8aaf87 100644 (file)
@@ -393,6 +393,7 @@ const struct language_defn m2_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index e102b800aa53cd305cab3e143dab430bb024603e..934d9c6d168fa5f797767b62f56143851326012c 100644 (file)
@@ -402,6 +402,7 @@ const struct language_defn objc_language_defn = {
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index 6e4c185a64606f64793b2aa91837a14564333d3b..df57b61529981acee4b2bd231427d01e42735bbf 100644 (file)
@@ -1082,6 +1082,7 @@ const struct language_defn opencl_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index 1b069ef17fe37c96a55e4e13a407d0dc9b73c9f9..c4fe2f6c2a02e99ed1ac61c488833e23571490db 100644 (file)
@@ -30,6 +30,7 @@
 #include "valprint.h"
 #include "value.h"
 #include <ctype.h>
+#include "c-lang.h"
 
 extern void _initialize_pascal_language (void);
 
@@ -455,6 +456,7 @@ const struct language_defn pascal_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   default_get_string,
+  c_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index 898eddaba24ad53184abaf20be4df72ce873aec2..dce184ced0ebb2ed052c2f5616d0a5800901e27b 100644 (file)
@@ -2122,6 +2122,20 @@ rust_sniff_from_mangled_name (const char *mangled, char **demangled)
 
 \f
 
+/* la_watch_location_expression for Rust.  */
+
+static gdb::unique_xmalloc_ptr<char>
+rust_watch_location_expression (struct type *type, CORE_ADDR addr)
+{
+  type = check_typedef (TYPE_TARGET_TYPE (check_typedef (type)));
+  std::string name = type_to_string (type);
+  return gdb::unique_xmalloc_ptr<char>
+    (xstrprintf ("*(%s as *mut %s)", core_addr_to_string (addr),
+                name.c_str ()));
+}
+
+\f
+
 static const struct exp_descriptor exp_descriptor_rust = 
 {
   rust_print_subexp,
@@ -2176,6 +2190,7 @@ static const struct language_defn rust_language_defn =
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
+  rust_watch_location_expression,
   NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
index a3a75bcb7f4f0798d42d6fdbad4c9cd6651919ae..adbf3989b605158afb0936214b8d487f67e5ea1f 100644 (file)
@@ -1,3 +1,9 @@
+2017-05-19  Tom Tromey  <tom@tromey.com>
+
+       PR rust/21484:
+       * gdb.rust/watch.exp: New file.
+       * gdb.rust/watch.rs: New file.
+
 2017-05-18  Tom Tromey  <tom@tromey.com>
 
        * gdb.rust/simple.exp: Allow Box to be qualified.
diff --git a/gdb/testsuite/gdb.rust/watch.exp b/gdb/testsuite/gdb.rust/watch.exp
new file mode 100644 (file)
index 0000000..0a3c055
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (C) 2017 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 watch -location with Rust.
+
+load_lib rust-support.exp
+if {[skip_rust_tests]} {
+    continue
+}
+
+standard_testfile .rs
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug rust}]} {
+    return -1
+}
+
+set line [gdb_get_line_number "set breakpoint here"]
+if {![runto ${srcfile}:$line]} {
+    untested "could not run to breakpoint"
+    return -1
+}
+
+# Just setting a watchpoint was enough to trigger the bug.
+gdb_test "watch -location y" ".*watchpoint .* -location .*"
diff --git a/gdb/testsuite/gdb.rust/watch.rs b/gdb/testsuite/gdb.rust/watch.rs
new file mode 100644 (file)
index 0000000..4146ecb
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (C) 2017 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/>.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+fn main() {
+    let mut y = 7;
+    y = y + 1;                  // set breakpoint here
+    y = y + 1;
+}