From 43cc5389bc4662b31cad02a9f13358bd367d0ab3 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Sun, 14 May 2017 11:12:14 -0600 Subject: [PATCH] Use watchpoint's language when re-parsing expression 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 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) : 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 PR rust/21484: * gdb.rust/watch.exp: New file. * gdb.rust/watch.rs: New file. --- gdb/ChangeLog | 24 ++++++++++++++++++++++ gdb/ada-lang.c | 1 + gdb/breakpoint.c | 11 ++-------- gdb/c-lang.c | 14 +++++++++++++ gdb/c-lang.h | 3 +++ gdb/d-lang.c | 1 + gdb/f-lang.c | 1 + gdb/go-lang.c | 1 + gdb/language.c | 4 ++++ gdb/language.h | 6 ++++++ gdb/m2-lang.c | 1 + gdb/objc-lang.c | 1 + gdb/opencl-lang.c | 1 + gdb/p-lang.c | 2 ++ gdb/rust-lang.c | 15 ++++++++++++++ gdb/testsuite/ChangeLog | 6 ++++++ gdb/testsuite/gdb.rust/watch.exp | 35 ++++++++++++++++++++++++++++++++ gdb/testsuite/gdb.rust/watch.rs | 24 ++++++++++++++++++++++ 18 files changed, 142 insertions(+), 9 deletions(-) create mode 100644 gdb/testsuite/gdb.rust/watch.exp create mode 100644 gdb/testsuite/gdb.rust/watch.rs diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 59fa9510c02..1cc5dc9d59e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,27 @@ +2017-05-19 Tom Tromey + + 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) + : 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 PR tui/21482 diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 58c8a2efc90..25c49c589fc 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -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, diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 9d6a2f4eb8d..150b08ca9d4 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -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); diff --git a/gdb/c-lang.c b/gdb/c-lang.c index 19a8608a01a..a6d533d082f 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -712,7 +712,17 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp, } return evaluate_subexp_standard (expect_type, exp, pos, noside); } + +/* la_watch_location_expression for C. */ +gdb::unique_xmalloc_ptr +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 + (xstrprintf ("* (%s *) %s", name.c_str (), core_addr_to_string (addr))); +} /* 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, diff --git a/gdb/c-lang.h b/gdb/c-lang.h index 97462389724..5ce64861c42 100644 --- a/gdb/c-lang.h +++ b/gdb/c-lang.h @@ -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 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 *, diff --git a/gdb/d-lang.c b/gdb/d-lang.c index 3ffdbdf5083..434b2e6ba5f 100644 --- a/gdb/d-lang.c +++ b/gdb/d-lang.c @@ -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, diff --git a/gdb/f-lang.c b/gdb/f-lang.c index 3c30d75627c..a9663d415bc 100644 --- a/gdb/f-lang.c +++ b/gdb/f-lang.c @@ -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, diff --git a/gdb/go-lang.c b/gdb/go-lang.c index 88ddfb66be7..3b80cec4452 100644 --- a/gdb/go-lang.c +++ b/gdb/go-lang.c @@ -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, diff --git a/gdb/language.c b/gdb/language.c index ee0101db74a..e9d9803aeee 100644 --- a/gdb/language.c +++ b/gdb/language.c @@ -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, diff --git a/gdb/language.h b/gdb/language.h index 58bcbe8faec..cc0df8c5ce2 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -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 (*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. diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c index 03b955cb63a..35840bf56f9 100644 --- a/gdb/m2-lang.c +++ b/gdb/m2-lang.c @@ -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, diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c index e102b800aa5..934d9c6d168 100644 --- a/gdb/objc-lang.c +++ b/gdb/objc-lang.c @@ -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, diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c index 6e4c185a646..df57b615299 100644 --- a/gdb/opencl-lang.c +++ b/gdb/opencl-lang.c @@ -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, diff --git a/gdb/p-lang.c b/gdb/p-lang.c index 1b069ef17fe..c4fe2f6c2a0 100644 --- a/gdb/p-lang.c +++ b/gdb/p-lang.c @@ -30,6 +30,7 @@ #include "valprint.h" #include "value.h" #include +#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, diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c index 898eddaba24..dce184ced0e 100644 --- a/gdb/rust-lang.c +++ b/gdb/rust-lang.c @@ -2122,6 +2122,20 @@ rust_sniff_from_mangled_name (const char *mangled, char **demangled) +/* la_watch_location_expression for Rust. */ + +static gdb::unique_xmalloc_ptr +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 + (xstrprintf ("*(%s as *mut %s)", core_addr_to_string (addr), + name.c_str ())); +} + + + 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, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index a3a75bcb7f4..adbf3989b60 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2017-05-19 Tom Tromey + + PR rust/21484: + * gdb.rust/watch.exp: New file. + * gdb.rust/watch.rs: New file. + 2017-05-18 Tom Tromey * 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 index 00000000000..0a3c055b2a6 --- /dev/null +++ b/gdb/testsuite/gdb.rust/watch.exp @@ -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 . + +# 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 index 00000000000..4146ecbbbdd --- /dev/null +++ b/gdb/testsuite/gdb.rust/watch.rs @@ -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 . + +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_assignments)] + +fn main() { + let mut y = 7; + y = y + 1; // set breakpoint here + y = y + 1; +}