[PATCH v7 1/2] gdb: add annotation in 'info locals' command for variables shadowing case
Ijaz, Abdul B
abdul.b.ijaz@intel.com
Fri Dec 13 16:09:06 GMT 2024
Hi Andrew,
Thanks a lot for the feedback. Please see my response below:
> (gdb) info locals
> x = 99 <file.c:3>
> y = 52
> x = 42 <file.c:1, shadowed>
Andrew> I suspect that we'll end up wanting to add location information for every local. I know when I look at that output I immediately wonder why 'y' doesn't have a location when 'x' does.
Abdul > Location info for such shadowed variables was added based on these discussions. As the main issue was to easily distinguish between two or multiple nested variables with same name in the output. For other variable like 'y' in this case this info may not be that useful. As location only make it easier here to identify the variable with same name otherwise it is unnecessary. This is regarding only for explaining the "why" part but let me know what you think would be better here, as adding location info to all variable may just be extra info IMHO.
https://sourceware.org/pipermail/gdb-patches/2022-January/184822.html
https://sourceware.org/pipermail/gdb-patches/2022-January/184819.html
Also just FYI and may be not related there was an additional print option discussed here also regarding these "shadowed" variables , so that we may also have another option to just completely disable printing of these shadowed variables if someone does not want to see this.
https://sourceware.org/pipermail/gdb-patches/2023-November/203961.html
> +(gdb) info locals
> +x = 4 <file.c:3>
> +x = 3 <file.c:1, shadowed>
> +@end smallexample
Andrew>Given my comment about location information above. If we are sticking with the current approach, then I think this example needs to be expanded to include a local without location information, and the text below should explain why some locals get a location, and others don't.
Abdul>I see. Will handle it then accordingly update it. E.g. " <shadowed: Line info is not available>" will be added in such a case, will this be fine with you instead of line number for such cases.
> + /* Print location and shadowed variable information. */
> + fprintf_styled (stream, metadata_style.style (),
> + _("\t<%s:%d%s>"), file_name,
> + var->line (), printed ? ", shadowed" : "");
Andrew>I don't think this styling is correct. I think the 'shadowed' makes sense to have the metadata style, but 'file_name' should have the file_name_style. The other character '<', ',', and '>' should be unstyled.
Abdul> Thanks for pointing this out, will verify and then it will be fixed in V8.
> + if ((current_language->la_language == language_c
> + || current_language->la_language == language_cplus
> + || current_language->la_language == language_fortran
> + || current_language->la_language == language_ada)
Andrew>It would be better to have a new method on the language, something like 'bool allows_variable_shadowing () const', and then override this in each language that does to return true.
Andrew>Or maybe instead of allows_variable_shadowing(), have a function that returns a shadowing mode enum? With choices something like none, shadow, replace ? Then you'd be able to switch between the two types of language.
Abdul> Sure it can be updated. For the second case mentioned above "shadowing mode" enum, what is meant by "replace". Also I have mentioned about adding of a print option above which will allow using print option to hide shadowed variables completely. So in this case as per my understanding first case of adding a method on language to handle it per language sounds better to me. So far only override function is needed for rust. But let me know I will then update it accordingly.
Andrew>It seems weird to me that you use different logic to build the list of shadowed locals than you do to print the list of locals. It feels like there might be some nasty edge case bugs lurking where something is counted by the shadowing loop, but not counted by the printing loop.
Abdul> For building list of shadowed variable it is simple formula that if variable come twice it is shadowed but printing list was required in order to decide for printing the extra location + shadowed information for shadowed variables or nothing for other variables. As printing of variables in GDB starts from innermost block and then goes to outermost. So always first the original/current scope variable is printed and then the shadowed variable and here shadowing list help to distinguish such variables from rest. Then later printing list decide if only location should be added or "shadowed" text should also be added for all the variable in shadowed_vars list. All this implementation is during the gdb printing variables from inner to outer most blocks so it should be handling all cases. As these lists just add info to normal printing of locals in gdb and if a local variable with same name is been printed second time in gdb then it will have extra "shadowed" related info but if you already have any such source code e.g. for this scenario in mind then let me know I will try and then we can discuss accordingly.
Here is the info for each of this list.
First shadowed variable list is populated using this:
collected_vars -> To collect each name of variable once.
shadowed_vars -> Using the above list maintains list of variables to decide if it already exist in above list then should be consider shadowed and later use this list while printing.
Lastly:
printed_vars -> During printing of variables, using the shadowed_vars list for the shadowed variables first it help to distinguish shadowed vs non-shadowed variables. Secondly for shadowed variables , for the variable which is been shadowed by other we only print location and while for the shadowed variables we add location plus "shadowed" text. But as mentioned above GDB start from innermost scope so we need to know while priting that this variable is shadowed later on.
Andrew >I think it would be nicer if we could make use of the same iterate_over_block_locals with a callback to capture the shadowing information in someway, if this was possible?
Abdul> This would have been possible if iterate_over_block_locals was collecting all info and then printing at once all this info in second step. But right now GDB prints variable while processing them block by block and hence to decide whether to print location only or "shadowed" text also or nothing extra is needed while printing a variable during processing of a block , this shadowed information is required before stepping into this printing process.
Thanks & Best Regards
Abdul Basit
-----Original Message-----
From: Andrew Burgess <aburgess@redhat.com>
Sent: Monday, November 25, 2024 6:26 PM
To: Ijaz, Abdul B <abdul.b.ijaz@intel.com>; gdb-patches@sourceware.org
Cc: pedro@palves.net; philippe.waroquiers@skynet.be; Aktemur, Tankut Baris <tankut.baris.aktemur@intel.com>; Schimpe, Christina <christina.schimpe@intel.com>; lsix@lancelotsix.com; eliz@gnu.org; Ijaz, Abdul B <abdul.b.ijaz@intel.com>
Subject: Re: [PATCH v7 1/2] gdb: add annotation in 'info locals' command for variables shadowing case
Abdul Basit Ijaz <abdul.b.ijaz@intel.com> writes:
> From: "Ijaz, Abdul B" <abdul.b.ijaz@intel.com>
>
> For C/C++/Fortran/Ada languages GDB prints same name variable multiple
> times in case of variable shadowing and it is confusing for user to
> identify which variable belongs to the current scope. So for such
> cases add location info to the innermost listed variables and for
> super block variables add "shadowed" annotation in the form of "<file.c:line, shadowed>".
>
> Suppose we have
>
> 1:int x = 42;
> 2: {
> 3: int x = 99;
> 4: int y = 52;
> 5: x = 99; /* break here */
> 6: }
>
> Currently:
>
> (gdb) info locals
> x = 99
> x = 42
> y = 52
>
> After applying this patch, we obtain:
>
> (gdb) info locals
> x = 99 <file.c:3>
> y = 52
> x = 42 <file.c:1, shadowed>
I suspect that we'll end up wanting to add location information for every local. I know when I look at that output I immediately wonder why 'y' doesn't have a location when 'x' does.
>
> The patch adds the location annotations by keeping track of inner
> block and already printed variables to identify shadowing. So, GDB
> now prints "<file.c:line, shadowed>" for shadowed super-block
> variables and "<file.c:line>" for innermost declarations of such variables only.
>
> The location annotations are printed for shadowed variables in case of
> C/C++/Fortran/Ada languages. In Rust, it is possible to declare a
> variable with the same name many times. So in this case, just the
> first instance of the variable is printed. RUST language test "var_reuse.exp"
> fails with rustc compiler version >= 1.73 so XFAIL is added accordingly.
>
> Fix regex expression in gdb.opt/inline-locals.exp test according to
> this change.
> ---
> gdb/doc/gdb.texinfo | 16 ++++
> gdb/printcmd.c | 13 ++-
> gdb/stack.c | 64 +++++++++++--
> gdb/stack.h | 3 +-
> gdb/testsuite/gdb.ada/var_shadowing.exp | 39 ++++++++
> .../gdb.ada/var_shadowing/var_shadowing.adb | 30 ++++++
> gdb/testsuite/gdb.base/var-shadowing.c | 49 ++++++++++
> gdb/testsuite/gdb.base/var-shadowing.exp | 92 +++++++++++++++++++
> gdb/testsuite/gdb.base/var-shadowing2.c | 16 ++++
> gdb/testsuite/gdb.opt/inline-locals.exp | 21 +++--
> gdb/testsuite/gdb.rust/var_reuse.exp | 34 +++++++
> gdb/testsuite/gdb.rust/var_reuse.rs | 20 ++++
> gdb/tracepoint.c | 3 +-
> gdb/value.h | 4 +-
> 14 files changed, 385 insertions(+), 19 deletions(-) create mode
> 100644 gdb/testsuite/gdb.ada/var_shadowing.exp
> create mode 100644
> gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> create mode 100755 gdb/testsuite/gdb.base/var-shadowing.c
> create mode 100755 gdb/testsuite/gdb.base/var-shadowing.exp
> create mode 100644 gdb/testsuite/gdb.base/var-shadowing2.c
> create mode 100755 gdb/testsuite/gdb.rust/var_reuse.exp
> create mode 100755 gdb/testsuite/gdb.rust/var_reuse.rs
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index
> 46ca62ec0c3..cd62756f4a1 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -8888,6 +8888,22 @@ The optional flag @samp{-q}, which stands for
> @samp{quiet}, disables printing header information and messages
> explaining why no local variables have been printed.
>
> +@smallexample
> +1: int x = 3;
> +2: @{
> +3: int x = 4;
> +4: x = 99; // breakpt
> +5: @}
> +(gdb) info locals
> +x = 4 <file.c:3>
> +x = 3 <file.c:1, shadowed>
> +@end smallexample
Given my comment about location information above. If we are sticking with the current approach, then I think this example needs to be expanded to include a local without location information, and the text below should explain why some locals get a location, and others don't.
> +
> +A variable is shadowed when there's another variable by the same
Replace 'by' with 'with' on this line I think.
> +name which is declared within an inner scope (decision block, method,
> +or inner class). For such cases, its location for the outermost
> +scope is followed by @samp{shadowed}.
> +
> @item info locals [-q] [-t @var{type_regexp}] [@var{regexp}] Like
> @kbd{info locals}, but only print the local variables selected with
> the provided regexp(s).
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c index
> f1aaa644042..d2c5c4f5998 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -58,6 +58,7 @@
> #include "gdbsupport/gdb-safe-ctype.h"
> #include "gdbsupport/rsp-low.h"
> #include "inferior.h"
> +#include "include/libiberty.h"
>
> /* Chain containing all defined memory-tag subcommands. */
>
> @@ -2333,7 +2334,8 @@ clear_dangling_display_expressions (struct
> objfile *objfile) void print_variable_and_value (const char *name,
> struct symbol *var,
> const frame_info_ptr &frame,
> - struct ui_file *stream, int indent)
> + struct ui_file *stream, int indent,
> + bool shadowed, bool printed)
> {
>
> if (!name)
> @@ -2346,6 +2348,7 @@ print_variable_and_value (const char *name, struct symbol *var,
> {
> struct value *val;
> struct value_print_options opts;
> + const char *file_name = lbasename
> + (var->owner.symtab->filename);
>
> /* READ_VAR_VALUE needs a block in order to deal with non-local
> references (i.e. to handle nested functions). In this context, we
> @@ -2355,6 +2358,14 @@ print_variable_and_value (const char *name, struct symbol *var,
> get_user_print_options (&opts);
> opts.deref_ref = true;
> common_val_print_checked (val, stream, indent, &opts,
> current_language);
> +
> + if (shadowed)
> + {
> + /* Print location and shadowed variable information. */
> + fprintf_styled (stream, metadata_style.style (),
> + _("\t<%s:%d%s>"), file_name,
> + var->line (), printed ? ", shadowed" : "");
I don't think this styling is correct. I think the 'shadowed' makes sense to have the metadata style, but 'file_name' should have the file_name_style. The other character '<', ',', and '>' should be unstyled.
> + }
> }
> catch (const gdb_exception_error &except)
> {
> diff --git a/gdb/stack.c b/gdb/stack.c index 4a3e7e4ff00..fcb0b7331de
> 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -58,6 +58,7 @@
> #include "cli/cli-option.h"
> #include "cli/cli-style.h"
> #include "gdbsupport/buildargv.h"
> +#include <unordered_set>
>
> /* The possible choices of "set print frame-arguments", and the value
> of this setting. */
> @@ -2214,10 +2215,16 @@ backtrace_command_completer (struct
> cmd_list_element *ignore,
>
> static void
> iterate_over_block_locals (const struct block *b,
> - iterate_over_block_arg_local_vars_cb cb)
> + iterate_over_block_arg_local_vars_cb cb,
> + const std::unordered_set<std::string> *shadowed_vars,
> + std::unordered_set<std::string> &printed_vars)
> {
> for (struct symbol *sym : block_iterator_range (b))
> {
> + const char *name = sym->print_name ();
> + bool already_printed = !printed_vars.insert (name).second;
> + bool shadowed = shadowed_vars->find (name) !=
> + shadowed_vars->end ();
> +
> switch (sym->aclass ())
> {
> case LOC_CONST:
> @@ -2230,7 +2237,25 @@ iterate_over_block_locals (const struct block *b,
> break;
> if (sym->domain () == COMMON_BLOCK_DOMAIN)
> break;
> - cb (sym->print_name (), sym);
> + /* Only for C/C++/Fortran/Ada languages, in case of variables
> + shadowing print <file:line, shadowed> annotation after
> + the superblock variable. Iteration of block starts from inner
> + block which is printed only with location information. */
> + if ((current_language->la_language == language_c
> + || current_language->la_language == language_cplus
> + || current_language->la_language == language_fortran
> + || current_language->la_language == language_ada)
It would be better to have a new method on the language, something like 'bool allows_variable_shadowing () const', and then override this in each language that does to return true.
> + && shadowed)
> + cb (name, sym, true, already_printed);
> + /* In case of Rust language it is possible to declare variable with
> + same name multiple times and only innermost instance of variable
> + is accessible. So print only the innermost instance and there is
> + no need of printing duplicates. */
> + else if (current_language->la_language == language_rust
> + && shadowed && already_printed)
Or maybe instead of allows_variable_shadowing(), have a function that returns a shadowing mode enum? With choices something like none, shadow, replace ? Then you'd be able to switch between the two types of language.
> + break;
> + else
> + cb (name, sym, false, false);
> break;
>
> default:
> @@ -2247,9 +2272,31 @@ void
> iterate_over_block_local_vars (const struct block *block,
> iterate_over_block_arg_local_vars_cb cb) {
> + std::unordered_set<std::string> collected_vars, shadowed_vars,
> + printed_vars; const struct block *orig_block = block;
> +
> + /* Iterate over all the local variables in a block and store the list of
> + shadowed variables to later distinguish them from other
> +variables. */
> + while (block != nullptr)
> + {
> + for (struct symbol *sym : block_iterator_range (block))
> + {
> + if (!sym->is_argument ())
> + {
> + const char *name = sym->print_name ();
> + if (!collected_vars.insert (name).second)
> + shadowed_vars.insert (name);
> + }
> + }
> + if (block->function ())
> + break;
> + block = block->superblock ();
> + }
It seems weird to me that you use different logic to build the list of shadowed locals than you do to print the list of locals. It feels like there might be some nasty edge case bugs lurking where something is counted by the shadowing loop, but not counted by the printing loop.
I think it would be nicer if we could make use of the same iterate_over_block_locals with a callback to capture the shadowing information in someway, if this was possible?
Thanks,
Andrew
> +
> + block = orig_block;
> while (block)
> {
> - iterate_over_block_locals (block, cb);
> + iterate_over_block_locals (block, cb, &shadowed_vars,
> + printed_vars);
> /* After handling the function's top-level block, stop. Don't
> continue to its superblock, the block of per-file
> symbols. */
> @@ -2271,14 +2318,16 @@ struct print_variable_and_value_data
> struct ui_file *stream;
> int values_printed;
>
> - void operator() (const char *print_name, struct symbol *sym);
> + void operator() (const char *print_name, struct symbol *sym, bool shadowed,
> + bool printed);
> };
>
> /* The callback for the locals and args iterators. */
>
> void
> print_variable_and_value_data::operator() (const char *print_name,
> - struct symbol *sym)
> + struct symbol *sym,
> + bool shadowed, bool printed)
> {
> frame_info_ptr frame;
>
> @@ -2298,7 +2347,8 @@ print_variable_and_value_data::operator() (const char *print_name,
> return;
> }
>
> - print_variable_and_value (print_name, sym, frame, stream,
> num_tabs);
> + print_variable_and_value (print_name, sym, frame, stream, num_tabs, shadowed,
> + printed);
>
> values_printed = 1;
> }
> @@ -2476,7 +2526,7 @@ iterate_over_block_arg_vars (const struct block *b,
> struct symbol *sym2
> = lookup_symbol_search_name (sym->search_name (),
> b, SEARCH_VAR_DOMAIN).symbol;
> - cb (sym->print_name (), sym2);
> + cb (sym->print_name (), sym2, false, false);
> }
> }
> }
> diff --git a/gdb/stack.h b/gdb/stack.h index e7242c71036..37aa6844cf3
> 100644
> --- a/gdb/stack.h
> +++ b/gdb/stack.h
> @@ -24,7 +24,8 @@ gdb::unique_xmalloc_ptr<char> find_frame_funname (const frame_info_ptr &frame,
> enum language *funlang,
> struct symbol **funcp);
>
> -typedef gdb::function_view<void (const char *print_name, struct
> symbol *sym)>
> +typedef gdb::function_view<void (const char *print_name, struct symbol *sym,
> + bool shadowed, bool printed)>
> iterate_over_block_arg_local_vars_cb;
>
> void iterate_over_block_arg_vars (const struct block *block, diff
> --git a/gdb/testsuite/gdb.ada/var_shadowing.exp
> b/gdb/testsuite/gdb.ada/var_shadowing.exp
> new file mode 100644
> index 00000000000..9d446790254
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing.exp
> @@ -0,0 +1,39 @@
> +# Copyright 2023-2024 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/>.
> +
> +load_lib "ada.exp"
> +
> +require allow_ada_tests
> +
> +standard_ada_testfile var_shadowing
> +
> +if {[gdb_compile_ada "${srcfile}" "${binfile}" \
> + executable [list debug]] != "" } {
> + return -1
> +}
> +
> +clean_restart ${testfile}
> +
> +set i_level1 [gdb_get_line_number "I-Level1"] set i_level2
> +[gdb_get_line_number "I-Level2"] set i_level3 [gdb_get_line_number
> +"I-Level3"] set bp_location [gdb_get_line_number "BREAK"] runto
> +"var_shadowing.adb:$bp_location"
> +
> +gdb_test "info locals" [multi_line \
> + "i = 111\t<$testfile.adb:$i_level3>" \
> + "i = 11\t<$testfile.adb:$i_level2, shadowed>" \
> + "i = 1\t<$testfile.adb:$i_level1, shadowed>" \ ] "info locals at
> +innermost level"
> diff --git a/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> new file mode 100644
> index 00000000000..55be43b77e2
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> @@ -0,0 +1,30 @@
> +-- Copyright 2023-2024 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/>.
> +
> +with Ada.Text_IO; use Ada.Text_IO;
> +
> +procedure Varshadow is
> + I : Integer := 1; -- I-Level1
> +begin
> + declare
> + I : Integer := 11; -- I-Level2
> + begin
> + declare
> + I : Integer := 111; -- I-Level3
> + begin
> + Put_Line ("hello"); -- BREAK
> + end;
> + end;
> +end;
> diff --git a/gdb/testsuite/gdb.base/var-shadowing.c
> b/gdb/testsuite/gdb.base/var-shadowing.c
> new file mode 100755
> index 00000000000..a0763419b38
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.c
> @@ -0,0 +1,49 @@
> +/* Copyright (C) 2023-2024 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/>. */
> +
> +#include <stdlib.h>
> +
> +void
> +shadowing (void)
> +{
> + int a = 100; /* bp for entry */
> + unsigned int val1 = 1; /* val1-d1 */
> + unsigned int val2 = 2; /* val2-d1 */
> + a = 101; /* bp for locals 1 */
> + {
> + unsigned int val2 = 3; /* val2-d2 */
> + unsigned int val3 = 4; /* val3-d1 */
> + a = 102; /* bp for locals 2 */
> + {
> + unsigned int val1 = 5; /* val1-d2 */
> + a = 103; /* bp for locals 3 */
> + {
> + #include "var-shadowing2.c"
> + unsigned int val1 = 6; /* val1-d3 */
> + unsigned int val2 = 7; /* val2-d3 */
> + unsigned int val3 = 8; /* val3-d2 */
> + a = 104; /* bp for locals 4 */
> + }
> + }
> + }
> + a = 105;
> +} /* bp for locals 5 */
> +
> +int
> +main (void)
> +{
> + shadowing ();
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/var-shadowing.exp
> b/gdb/testsuite/gdb.base/var-shadowing.exp
> new file mode 100755
> index 00000000000..68372091330
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.exp
> @@ -0,0 +1,92 @@
> +# Copyright 2023-2024 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/>.
> +
> +standard_testfile
> +if [prepare_for_testing "failed to prepare" $testfile $srcfile] {
> + return -1
> +}
> +
> +if ![runto_main] {
> + return -1
> +}
> +
> +set bp_line1 [gdb_get_line_number "bp for locals 1"] set bp_line2
> +[gdb_get_line_number "bp for locals 2"] set bp_line3
> +[gdb_get_line_number "bp for locals 3"] set bp_line4
> +[gdb_get_line_number "bp for locals 4"] set bp_line5
> +[gdb_get_line_number "bp for locals 5"]
> +
> +set val1_d1 [gdb_get_line_number "val1-d1"] set val1_d2
> +[gdb_get_line_number "val1-d2"] set val1_d3 [gdb_get_line_number
> +"val1-d3"] set val2_d1 [gdb_get_line_number "val2-d1"] set val2_d2
> +[gdb_get_line_number "val2-d2"] set val2_d3 [gdb_get_line_number
> +"val2-d3"] set val3_d1 [gdb_get_line_number "val3-d1"] set val3_d2
> +[gdb_get_line_number "val3-d2"] set a_line [gdb_get_line_number "bp
> +for entry"]
> +
> +gdb_breakpoint $srcfile:$bp_line1
> +gdb_continue_to_breakpoint "continue to outermost level" \
> + ".*$srcfile:$bp_line1.*"
> +gdb_test "info locals" [multi_line \
> + "val1 = 1" \
> + "val2 = 2" \
> + ] "info locals at outermost level"
> +
> +gdb_breakpoint $srcfile:$bp_line2
> +gdb_continue_to_breakpoint "continue to first level" ".*$srcfile:$bp_line2.*"
> +gdb_test "info locals" [multi_line \
> + "val2 = 3\t<$srcfile:$val2_d2>" \
> + "val3 = 4" \
> + "a = 101" \
> + "val1 = 1" \
> + "val2 = 2\t<$srcfile:$val2_d1, shadowed>" \
> + ] "info locals first level"
> +
> +gdb_breakpoint $srcfile:$bp_line3
> +gdb_continue_to_breakpoint "continue to second level" ".*$srcfile:$bp_line3.*"
> +gdb_test "info locals" [multi_line \
> + "val1 = 5\t<$srcfile:$val1_d2>" \
> + "val2 = 3\t<$srcfile:$val2_d2>" \
> + "val3 = 4" \
> + "a = 102" \
> + "val1 = 1\t<$srcfile:$val1_d1, shadowed>" \
> + "val2 = 2\t<$srcfile:$val2_d1, shadowed>" \
> + ] "info locals second level"
> +
> +gdb_breakpoint $srcfile:$bp_line4
> +gdb_continue_to_breakpoint "continue to innermost level" ".*$srcfile:$bp_line4.*"
> +gdb_test "info locals" [multi_line \
> + "a = 999\t<${testfile}2.c:16>" \
> + "val1 = 6\t<$srcfile:$val1_d3>" \
> + "val2 = 7\t<$srcfile:$val2_d3>" \
> + "val3 = 8\t<$srcfile:$val3_d2>" \
> + "val1 = 5\t<$srcfile:$val1_d2, shadowed>" \
> + "val2 = 3\t<$srcfile:$val2_d2, shadowed>" \
> + "val3 = 4\t<$srcfile:$val3_d1, shadowed>" \
> + "a = 103\t<$srcfile:$a_line, shadowed>" \
> + "val1 = 1\t<$srcfile:$val1_d1, shadowed>" \
> + "val2 = 2\t<$srcfile:$val2_d1, shadowed>" \
> + ] "info locals at innermost level"
> +
> +gdb_breakpoint $srcfile:$bp_line5
> +gdb_continue_to_breakpoint "continue to outermost level last" \
> + ".*$srcfile:$bp_line5.*"
> +gdb_test "info locals" [multi_line \
> + "a = 105" \
> + "val1 = 1" \
> + "val2 = 2" \
> + ] "info locals at outermost level last"
> diff --git a/gdb/testsuite/gdb.base/var-shadowing2.c
> b/gdb/testsuite/gdb.base/var-shadowing2.c
> new file mode 100644
> index 00000000000..8223e11ec17
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing2.c
> @@ -0,0 +1,16 @@
> +/* Copyright (C) 2023-2024 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/>. */
> +
> +int a = 999;
> diff --git a/gdb/testsuite/gdb.opt/inline-locals.exp
> b/gdb/testsuite/gdb.opt/inline-locals.exp
> index 358a8d29d89..e12f79fa94e 100644
> --- a/gdb/testsuite/gdb.opt/inline-locals.exp
> +++ b/gdb/testsuite/gdb.opt/inline-locals.exp
> @@ -42,9 +42,11 @@ if { ! $no_frames } {
> "backtrace from bar 2"
> gdb_test "up" "#1 .*func1 .* at .*" "up from bar 2"
> gdb_test "info frame" ".*inlined into frame.*" "func1 inlined 2"
> - set pass_re "array = \\{0 <repeats 64 times>\\}"
> + set shadowed_pass_re "\t<$srcfile:$decimal>"
> + set shadowed_fail_re "\t<$srcfile:$decimal, shadowed>"
> + set pass_re "array = \\{0 <repeats 64 times>\\}($shadowed_pass_re)?"
> set kfail_re [multi_line $pass_re \
> - "array = <optimized out>"]
> + "array = <optimized out>$shadowed_fail_re"]
> gdb_test_multiple "info locals" "info locals above bar 2" {
> -re -wrap $pass_re {
> pass $gdb_test_name
> @@ -91,9 +93,9 @@ if { ! $no_frames } {
> "backtrace from bar 3"
> gdb_test "up" "#1 .*func1 .* at .*" "up from bar 3"
> gdb_test "info frame" ".*inlined into frame.*" "func1 inlined 3"
> - set pass_re "array = {$decimal, \[^\r\n\]*}"
> + set pass_re "array = {$decimal, \[^\r\n\]*}($shadowed_pass_re)?"
> set kfail_re [multi_line $pass_re \
> - "array = <optimized out>"]
> + "array = <optimized out>$shadowed_fail_re"]
> gdb_test_multiple "info locals" "info locals above bar 3" {
> -re -wrap $pass_re {
> pass $gdb_test_name
> @@ -133,7 +135,8 @@ proc check_scoped_locals {bp_label pass_re} {
> gdb_breakpoint $srcfile:$locals_bp
>
> gdb_continue_to_breakpoint "$bp_label" ".*$srcfile:$locals_bp.*"
> - set kfail_re [multi_line $pass_re ".*<optimized out>"]
> + set kfail_re [multi_line $pass_re \
> + ".*<optimized out>(.*<$srcfile:$::decimal, shadowed>)?"]
> gdb_test_multiple "info locals" "scoped info locals at $bp_label" {
> -re -wrap $pass_re {
> pass $gdb_test_name
> @@ -149,7 +152,9 @@ proc check_scoped_locals {bp_label pass_re} { }
>
> if {! $no_frames } {
> - check_scoped_locals "bp for locals 1" "loc2 = 20\r\nloc1 = 10"
> - check_scoped_locals "bp for locals 2" "loc3 = 30\r\nloc2 = 20\r\nloc1 = 10"
> - check_scoped_locals "bp for locals 3" "loc1 = 10"
> + check_scoped_locals "bp for locals 1" \
> + "loc2 = 20(\t<$srcfile:$decimal>)?\r\nloc1 = 10(\t<$srcfile:$decimal>)?"
> + check_scoped_locals "bp for locals 2" \
> + "loc3 = 30(\t<$srcfile:$decimal>)?\r\nloc2 = 20(\t<$srcfile:$decimal>)?\r\nloc1 = 10(\t<$srcfile:$decimal>)?"
> + check_scoped_locals "bp for locals 3" "loc1 = 10(\t<$srcfile:$decimal>)?"
> }
> diff --git a/gdb/testsuite/gdb.rust/var_reuse.exp
> b/gdb/testsuite/gdb.rust/var_reuse.exp
> new file mode 100755
> index 00000000000..1ed96830556
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.exp
> @@ -0,0 +1,34 @@
> +# Copyright 2023-2024 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/>.
> +
> +load_lib rust-support.exp
> +require allow_rust_tests
> +require {can_compile rust}
> +
> +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
> +}
> +
> +# Wrong local values are shown for rustc version >= 1.73.
> +setup_xfail "*-*-*" "gdb/31079"
> +gdb_test "info local _x" "_x = 12" "print local _x variable"
> diff --git a/gdb/testsuite/gdb.rust/var_reuse.rs
> b/gdb/testsuite/gdb.rust/var_reuse.rs
> new file mode 100755
> index 00000000000..09f2fcd008c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.rs
> @@ -0,0 +1,20 @@
> +// Copyright (C) 2023-2024 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/>.
> +
> +fn main() {
> + let _x = 5;
> + let _x = _x + 7;
> + let _y = 8; // set breakpoint here
> +}
> diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index
> d11c3f8a6be..cfce3002dd9 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -1046,7 +1046,8 @@ collection_list::add_local_symbols (struct gdbarch *gdbarch, CORE_ADDR pc,
> int count = 0;
>
> auto do_collect_symbol = [&] (const char *print_name,
> - struct symbol *sym)
> + struct symbol *sym,
> + bool shadowed, bool printed)
> {
> collect_symbol (sym, gdbarch, frame_regno,
> frame_offset, pc, trace_string); diff --git a/gdb/value.h
> b/gdb/value.h index 13cfb007aa2..069bcffa5cc 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -1559,7 +1559,9 @@ extern void print_variable_and_value (const char *name,
> struct symbol *var,
> const frame_info_ptr &frame,
> struct ui_file *stream,
> - int indent);
> + int indent,
> + bool shadowed,
> + bool printed);
>
> extern void typedef_print (struct type *type, struct symbol *news,
> struct ui_file *stream);
> --
> 2.34.1
>
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de
> Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon
> Silva Chairperson of the Supervisory Board: Nicole Lau Registered
> Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
More information about the Gdb-patches
mailing list