[v4,1/2] gdb: add annotation in 'info locals' command for variables shadowing case

Message ID 20230919164700.19891-2-abdul.b.ijaz@intel.com
State New
Headers
Series add annotation in 'info locals' command for variables shadowing case |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Testing passed

Commit Message

Ijaz, Abdul B Sept. 19, 2023, 4:46 p.m. UTC
  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>

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.
---
 gdb/doc/gdb.texinfo                           | 13 +++
 gdb/printcmd.c                                | 11 ++-
 gdb/stack.c                                   | 64 +++++++++++--
 gdb/stack.h                                   |  3 +-
 gdb/testsuite/gdb.ada/var_shadowing.exp       | 38 ++++++++
 .../gdb.ada/var_shadowing/var_shadowing.adb   | 30 +++++++
 gdb/testsuite/gdb.base/var-shadowing.c        | 49 ++++++++++
 gdb/testsuite/gdb.base/var-shadowing.exp      | 90 +++++++++++++++++++
 gdb/testsuite/gdb.base/var-shadowing2.c       | 16 ++++
 gdb/testsuite/gdb.rust/var_reuse.exp          | 32 +++++++
 gdb/testsuite/gdb.rust/var_reuse.rs           | 20 +++++
 gdb/tracepoint.c                              |  3 +-
 gdb/value.h                                   |  4 +-
 13 files changed, 362 insertions(+), 11 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
  

Comments

Guinevere Larsen Oct. 12, 2023, 9:39 a.m. UTC | #1
On 19/09/2023 18:46, Abdul Basit Ijaz via Gdb-patches wrote:
> 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>
>
> 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.
Thanks for working on this!

This patch seems to have slipped through the cracks and needs a small 
rebase, but the conflict was pretty trivial to resolve locally 
(inferior.h is also being added to printcmd.c)

I see a failure on the newly added test on my fedora37 machine:

Breakpoint 1, var_reuse::main () at 
../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
19          let _y = 8;       // set breakpoint here
(gdb) info local _x
_x = 0
(gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable

I don't think this is related to the conflict, but I don't really have 
the time to diagnose what is going on.

> ---
>   gdb/doc/gdb.texinfo                           | 13 +++
>   gdb/printcmd.c                                | 11 ++-
>   gdb/stack.c                                   | 64 +++++++++++--
>   gdb/stack.h                                   |  3 +-
>   gdb/testsuite/gdb.ada/var_shadowing.exp       | 38 ++++++++
>   .../gdb.ada/var_shadowing/var_shadowing.adb   | 30 +++++++
>   gdb/testsuite/gdb.base/var-shadowing.c        | 49 ++++++++++
>   gdb/testsuite/gdb.base/var-shadowing.exp      | 90 +++++++++++++++++++
>   gdb/testsuite/gdb.base/var-shadowing2.c       | 16 ++++
>   gdb/testsuite/gdb.rust/var_reuse.exp          | 32 +++++++
>   gdb/testsuite/gdb.rust/var_reuse.rs           | 20 +++++
>   gdb/tracepoint.c                              |  3 +-
>   gdb/value.h                                   |  4 +-
>   13 files changed, 362 insertions(+), 11 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 9b7e06f3156..6a22bbf2531 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -8831,6 +8831,19 @@ 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; // breakpt
> +4: @}
> +(gdb) info locals
> +x = 4	<file.c:3>
> +x = 3	<file.c:1, shadowed>
> +@end smallexample
> +
> +If a variable is shadowed, then location information is printed and for
> +the outermost scope variables "shadowed" string is printed as well.
> +
>   @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 8d7d04231fe..83008e5c3f3 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -55,6 +55,7 @@
>   #include "gdbsupport/gdb_optional.h"
>   #include "gdbsupport/gdb-safe-ctype.h"
>   #include "gdbsupport/rsp-low.h"
> +#include "include/libiberty.h"
>   
>   /* Chain containing all defined memory-tag subcommands.  */
>   
> @@ -2401,7 +2402,8 @@ clear_dangling_display_expressions (struct objfile *objfile)
>   void
>   print_variable_and_value (const char *name, struct symbol *var,
>   			  frame_info_ptr frame,
> -			  struct ui_file *stream, int indent)
> +			  struct ui_file *stream, int indent,
> +			  bool shadowed, bool printed)
>   {
>   
>     if (!name)
> @@ -2414,6 +2416,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
> @@ -2424,6 +2427,12 @@ print_variable_and_value (const char *name, struct symbol *var,
>         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" : "");
> +
>         /* common_val_print invalidates FRAME when a pretty printer calls inferior
>   	 function.  */
>         frame = NULL;
> diff --git a/gdb/stack.c b/gdb/stack.c
> index 0b35d62f82f..0173e7341e9 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -56,6 +56,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.  */
> @@ -2211,10 +2212,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:
> @@ -2227,7 +2234,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)
> +	      && 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 latest declaration of variable
> +	     is accessible.  So print only the first instance and there is no
> +	     need of printing duplicates.  */
> +	  else if (current_language->la_language == language_rust
> +		   && shadowed && already_printed)
> +	    break;
> +	  else
> +	    cb (name, sym, false, false);
>   	  break;
>   
>   	default:
> @@ -2244,9 +2269,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 ();
> +    }
> +
> +  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.  */
> @@ -2268,14 +2315,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;
>   
> @@ -2295,7 +2344,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);
>   
>     /* print_variable_and_value invalidates FRAME.  */
>     frame = NULL;
> @@ -2478,7 +2528,7 @@ iterate_over_block_arg_vars (const struct block *b,
>   	  struct symbol *sym2
>   	    = lookup_symbol_search_name (sym->search_name (),
>   					 b, 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 1b0c2b342a4..72d843b66fb 100644
> --- a/gdb/stack.h
> +++ b/gdb/stack.h
> @@ -24,7 +24,8 @@ gdb::unique_xmalloc_ptr<char> find_frame_funname (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..da279da258d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing.exp
> @@ -0,0 +1,38 @@
> +# Copyright 2023 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" ${testdir}/var_shadowing.adb]
> +set i_level2 [gdb_get_line_number "I-Level2" ${testdir}/var_shadowing.adb]
> +set i_level3 [gdb_get_line_number "I-Level3" ${testdir}/var_shadowing.adb]
> +set bp_location [gdb_get_line_number "BREAK" ${testdir}/var_shadowing.adb]
> +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..93cef5f0d6c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> @@ -0,0 +1,30 @@
> +--  Copyright 2023 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..18963514bbf
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.c
> @@ -0,0 +1,49 @@
> +/* Copyright (C) 2023 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;  /* 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 = 0; /* 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..c7e1e9eae2e
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.exp
> @@ -0,0 +1,90 @@
> +# Copyright 2023 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] {
> +    untested "failed to run to main"
> +    return -1
> +}
> +
> +set bp_line1 [gdb_get_line_number "bp for locals 1" ${srcfile}]
> +set bp_line2 [gdb_get_line_number "bp for locals 2" ${srcfile}]
> +set bp_line3 [gdb_get_line_number "bp for locals 3" ${srcfile}]
> +set bp_line4 [gdb_get_line_number "bp for locals 4" ${srcfile}]
> +set bp_line5 [gdb_get_line_number "bp for locals 5" ${srcfile}]
> +
> +set val1_d1 [gdb_get_line_number "val1-d1" ${srcfile}]
> +set val1_d2 [gdb_get_line_number "val1-d2" ${srcfile}]
> +set val1_d3 [gdb_get_line_number "val1-d3" ${srcfile}]
> +set val2_d1 [gdb_get_line_number "val2-d1" ${srcfile}]
> +set val2_d2 [gdb_get_line_number "val2-d2" ${srcfile}]
> +set val2_d3 [gdb_get_line_number "val2-d3" ${srcfile}]
> +set val3_d1 [gdb_get_line_number "val3-d1" ${srcfile}]
> +set val3_d2 [gdb_get_line_number "val3-d2" ${srcfile}]
> +set a_line [gdb_get_line_number "bp for entry" ${srcfile}]
> +
> +gdb_breakpoint $srcfile:$bp_line1
> +gdb_test "continue" ".*bp for locals 1.*" "continue to outermost level"
> +gdb_test "info locals"  [multi_line \
> +    "val1 = 1"  \
> +    "val2 = 2"  \
> +    ] "info locals at outermost level"
> +
> +gdb_breakpoint $srcfile:$bp_line2
> +gdb_test "continue" ".*bp for locals 2.*" "continue to first level"
> +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_test "continue" ".*bp for locals 3.*" "continue to second level"
> +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_test "continue" ".*bp for locals 4.*" "continue to innermost level"
> +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_test "continue" ".*bp for locals 5.*" "continue to outermost level last"
> +gdb_test "info locals" [multi_line \
> +    "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..9bc55f95a84
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing2.c
> @@ -0,0 +1,16 @@
> +/* Copyright (C) 2023 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.rust/var_reuse.exp b/gdb/testsuite/gdb.rust/var_reuse.exp
> new file mode 100755
> index 00000000000..58b85518f55
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.exp
> @@ -0,0 +1,32 @@
> +# Copyright 2023 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
> +}
> +
> +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..03be7981ff1
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.rs
> @@ -0,0 +1,20 @@
> +// Copyright (C) 2023 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 205380476b3..02669b3d909 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -1048,7 +1048,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 1d5a0018f92..879fce544c3 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -1537,7 +1537,9 @@ extern void print_variable_and_value (const char *name,
>   				      struct symbol *var,
>   				      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);
  
Ijaz, Abdul B Nov. 20, 2023, 8:26 a.m. UTC | #2
Hi Larsen,

Thanks for the feedback.

>> 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.
> Thanks for working on this!

> This patch seems to have slipped through the cracks and needs a small rebase, but the conflict was pretty trivial to resolve locally (inferior.h is also being added to printcmd.c)

> I see a failure on the newly added test on my fedora37 machine:

> Breakpoint 1, var_reuse::main () at
> ../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
> 19          let _y = 8;       // set breakpoint here
> (gdb) info local _x
> _x = 0
> (gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable

> I don't think this is related to the conflict, but I don't really have the time to diagnose what is going on

 I have rebased locally where also saw this inferior.h minor conflict and fixed it. So far ran on ubuntu22 where test ran fine. Need to test once on Fedora 37 and then will push the patch but from the failure in your logs,  issue does not look related to this patch as the value of variable in rust language is shown wrong in Fedora 37 logs. For rust we only don’t print the shadowed variables but had to retry once on Fedora 37 then will confirm and push the v5 series for review.
Ubuntu22 logs:
~~~
Breakpoint 1, var_reuse::main () at sources/gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
19          let _y = 8;       // set breakpoint here
(gdb) info local _x
_x = 12
(gdb) PASS: gdb.rust/var_reuse.exp: print local _x variable
testcase sources/gdb/gdb/testsuite/gdb.rust/var_reuse.exp completed in 7 seconds
~~~

Thanks & Best Regards
Abdul Basit

-----Original Message-----
From: Guinevere Larsen <blarsen@redhat.com> 
Sent: Thursday, October 12, 2023 11:40 AM
To: Ijaz, Abdul B <abdul.b.ijaz@intel.com>; gdb-patches@sourceware.org
Cc: lsix@lancelotsix.com; pedro@palves.net
Subject: Re: [PATCH v4 1/2] gdb: add annotation in 'info locals' command for variables shadowing case

On 19/09/2023 18:46, Abdul Basit Ijaz via Gdb-patches wrote:
> 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>
>
> 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.
Thanks for working on this!

This patch seems to have slipped through the cracks and needs a small rebase, but the conflict was pretty trivial to resolve locally (inferior.h is also being added to printcmd.c)

I see a failure on the newly added test on my fedora37 machine:

Breakpoint 1, var_reuse::main () at
../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
19          let _y = 8;       // set breakpoint here
(gdb) info local _x
_x = 0
(gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable

I don't think this is related to the conflict, but I don't really have the time to diagnose what is going on.

> ---
>   gdb/doc/gdb.texinfo                           | 13 +++
>   gdb/printcmd.c                                | 11 ++-
>   gdb/stack.c                                   | 64 +++++++++++--
>   gdb/stack.h                                   |  3 +-
>   gdb/testsuite/gdb.ada/var_shadowing.exp       | 38 ++++++++
>   .../gdb.ada/var_shadowing/var_shadowing.adb   | 30 +++++++
>   gdb/testsuite/gdb.base/var-shadowing.c        | 49 ++++++++++
>   gdb/testsuite/gdb.base/var-shadowing.exp      | 90 +++++++++++++++++++
>   gdb/testsuite/gdb.base/var-shadowing2.c       | 16 ++++
>   gdb/testsuite/gdb.rust/var_reuse.exp          | 32 +++++++
>   gdb/testsuite/gdb.rust/var_reuse.rs           | 20 +++++
>   gdb/tracepoint.c                              |  3 +-
>   gdb/value.h                                   |  4 +-
>   13 files changed, 362 insertions(+), 11 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 
> 9b7e06f3156..6a22bbf2531 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -8831,6 +8831,19 @@ 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; // breakpt
> +4: @}
> +(gdb) info locals
> +x = 4	<file.c:3>
> +x = 3	<file.c:1, shadowed>
> +@end smallexample
> +
> +If a variable is shadowed, then location information is printed and 
> +for the outermost scope variables "shadowed" string is printed as well.
> +
>   @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 
> 8d7d04231fe..83008e5c3f3 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -55,6 +55,7 @@
>   #include "gdbsupport/gdb_optional.h"
>   #include "gdbsupport/gdb-safe-ctype.h"
>   #include "gdbsupport/rsp-low.h"
> +#include "include/libiberty.h"
>   
>   /* Chain containing all defined memory-tag subcommands.  */
>   
> @@ -2401,7 +2402,8 @@ clear_dangling_display_expressions (struct objfile *objfile)
>   void
>   print_variable_and_value (const char *name, struct symbol *var,
>   			  frame_info_ptr frame,
> -			  struct ui_file *stream, int indent)
> +			  struct ui_file *stream, int indent,
> +			  bool shadowed, bool printed)
>   {
>   
>     if (!name)
> @@ -2414,6 +2416,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 
> @@ -2424,6 +2427,12 @@ print_variable_and_value (const char *name, struct symbol *var,
>         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" : "");
> +
>         /* common_val_print invalidates FRAME when a pretty printer calls inferior
>   	 function.  */
>         frame = NULL;
> diff --git a/gdb/stack.c b/gdb/stack.c index 0b35d62f82f..0173e7341e9 
> 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -56,6 +56,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.  */
> @@ -2211,10 +2212,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:
> @@ -2227,7 +2234,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)
> +	      && 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 latest declaration of variable
> +	     is accessible.  So print only the first instance and there is no
> +	     need of printing duplicates.  */
> +	  else if (current_language->la_language == language_rust
> +		   && shadowed && already_printed)
> +	    break;
> +	  else
> +	    cb (name, sym, false, false);
>   	  break;
>   
>   	default:
> @@ -2244,9 +2269,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 ();
> +    }
> +
> +  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.  */
> @@ -2268,14 +2315,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;
>   
> @@ -2295,7 +2344,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);
>   
>     /* print_variable_and_value invalidates FRAME.  */
>     frame = NULL;
> @@ -2478,7 +2528,7 @@ iterate_over_block_arg_vars (const struct block *b,
>   	  struct symbol *sym2
>   	    = lookup_symbol_search_name (sym->search_name (),
>   					 b, 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 1b0c2b342a4..72d843b66fb 
> 100644
> --- a/gdb/stack.h
> +++ b/gdb/stack.h
> @@ -24,7 +24,8 @@ gdb::unique_xmalloc_ptr<char> find_frame_funname (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..da279da258d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing.exp
> @@ -0,0 +1,38 @@
> +# Copyright 2023 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" 
> +${testdir}/var_shadowing.adb] set i_level2 [gdb_get_line_number 
> +"I-Level2" ${testdir}/var_shadowing.adb] set i_level3 
> +[gdb_get_line_number "I-Level3" ${testdir}/var_shadowing.adb] set 
> +bp_location [gdb_get_line_number "BREAK" ${testdir}/var_shadowing.adb] 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..93cef5f0d6c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> @@ -0,0 +1,30 @@
> +--  Copyright 2023 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..18963514bbf
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.c
> @@ -0,0 +1,49 @@
> +/* Copyright (C) 2023 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;  /* 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 = 0; /* 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..c7e1e9eae2e
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.exp
> @@ -0,0 +1,90 @@
> +# Copyright 2023 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] {
> +    untested "failed to run to main"
> +    return -1
> +}
> +
> +set bp_line1 [gdb_get_line_number "bp for locals 1" ${srcfile}] set 
> +bp_line2 [gdb_get_line_number "bp for locals 2" ${srcfile}] set 
> +bp_line3 [gdb_get_line_number "bp for locals 3" ${srcfile}] set 
> +bp_line4 [gdb_get_line_number "bp for locals 4" ${srcfile}] set 
> +bp_line5 [gdb_get_line_number "bp for locals 5" ${srcfile}]
> +
> +set val1_d1 [gdb_get_line_number "val1-d1" ${srcfile}] set val1_d2 
> +[gdb_get_line_number "val1-d2" ${srcfile}] set val1_d3 
> +[gdb_get_line_number "val1-d3" ${srcfile}] set val2_d1 
> +[gdb_get_line_number "val2-d1" ${srcfile}] set val2_d2 
> +[gdb_get_line_number "val2-d2" ${srcfile}] set val2_d3 
> +[gdb_get_line_number "val2-d3" ${srcfile}] set val3_d1 
> +[gdb_get_line_number "val3-d1" ${srcfile}] set val3_d2 
> +[gdb_get_line_number "val3-d2" ${srcfile}] set a_line 
> +[gdb_get_line_number "bp for entry" ${srcfile}]
> +
> +gdb_breakpoint $srcfile:$bp_line1
> +gdb_test "continue" ".*bp for locals 1.*" "continue to outermost level"
> +gdb_test "info locals"  [multi_line \
> +    "val1 = 1"  \
> +    "val2 = 2"  \
> +    ] "info locals at outermost level"
> +
> +gdb_breakpoint $srcfile:$bp_line2
> +gdb_test "continue" ".*bp for locals 2.*" "continue to first level"
> +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_test "continue" ".*bp for locals 3.*" "continue to second level"
> +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_test "continue" ".*bp for locals 4.*" "continue to innermost level"
> +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_test "continue" ".*bp for locals 5.*" "continue to outermost level last"
> +gdb_test "info locals" [multi_line \
> +    "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..9bc55f95a84
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing2.c
> @@ -0,0 +1,16 @@
> +/* Copyright (C) 2023 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.rust/var_reuse.exp 
> b/gdb/testsuite/gdb.rust/var_reuse.exp
> new file mode 100755
> index 00000000000..58b85518f55
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.exp
> @@ -0,0 +1,32 @@
> +# Copyright 2023 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
> +}
> +
> +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..03be7981ff1
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.rs
> @@ -0,0 +1,20 @@
> +// Copyright (C) 2023 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 
> 205380476b3..02669b3d909 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -1048,7 +1048,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 1d5a0018f92..879fce544c3 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -1537,7 +1537,9 @@ extern void print_variable_and_value (const char *name,
>   				      struct symbol *var,
>   				      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);


--
Cheers,
Guinevere Larsen
She/Her/Hers

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
  
Ijaz, Abdul B Nov. 20, 2023, 10:26 a.m. UTC | #3
Hi Larsen,

>> Breakpoint 1, var_reuse::main () at
>> ../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
>> 19          let _y = 8;       // set breakpoint here
>> (gdb) info local _x
>> _x = 0
>> (gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable

>> I don't think this is related to the conflict, but I don't really have 
>> the time to diagnose what is going on

 >I have rebased locally where also saw this inferior.h minor conflict and fixed it. So far ran on ubuntu22 where test ran fine. Need to test once on Fedora 37 and then will push the patch but from the failure in your logs

I can confirm that Fedora issue is not related to this patch as for the RUST language case in Fedora if we set breakpoints at line 18 and 19 of this test then we can see line 19 is always executed first so even with vanilla gdb on Fedora 37 we see the same behavior.  I am not sure if this is known issue in GDB for RUST language otherwise  please let me know if it will be fine with you to raise a GDB Bugzilla and add a kfail in this patch as issue is completely unrelated to this patch. (Note: issue is so far only valid for Fedora as it is not seen on Ubuntu). 

Fedora 37 Logs:
~~~
Reading symbols from gdb/testsuite/outputs/gdb.rust/var_reuse/var_reuse...
(gdb) b 18
Breakpoint 1 at 0x8654: file gdb/testsuite/gdb.rust/var_reuse.rs, line 18.
(gdb) b 19
Breakpoint 2 at 0x864c: file gdb/testsuite/gdb.rust/var_reuse.rs, line 19.
(gdb) r
Starting program: gdb/testsuite/outputs/gdb.rust/var_reuse/var_reuse
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 2, var_reuse::main () at gdb/testsuite/gdb.rust/var_reuse.rs:19
19          let _y = 8;       // set breakpoint here
(gdb) info locals
_y = 0
_x = 0
_x = 5
(gdb) c
Continuing.

Breakpoint 1, var_reuse::main () at gdb/testsuite/gdb.rust/var_reuse.rs:18
18          let _x = _x + 7;
(gdb) info locals
_x = 5
~~~

Thanks & Best Regards
Abdul Basit

-----Original Message-----
From: Ijaz, Abdul B 
Sent: Monday, November 20, 2023 9:26 AM
To: Guinevere Larsen <blarsen@redhat.com>; gdb-patches@sourceware.org
Cc: lsix@lancelotsix.com; pedro@palves.net
Subject: RE: [PATCH v4 1/2] gdb: add annotation in 'info locals' command for variables shadowing case

Hi Larsen,

Thanks for the feedback.

>> 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.
> Thanks for working on this!

> This patch seems to have slipped through the cracks and needs a small 
> rebase, but the conflict was pretty trivial to resolve locally 
> (inferior.h is also being added to printcmd.c)

> I see a failure on the newly added test on my fedora37 machine:

> Breakpoint 1, var_reuse::main () at
> ../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
> 19          let _y = 8;       // set breakpoint here
> (gdb) info local _x
> _x = 0
> (gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable

> I don't think this is related to the conflict, but I don't really have 
> the time to diagnose what is going on

 I have rebased locally where also saw this inferior.h minor conflict and fixed it. So far ran on ubuntu22 where test ran fine. Need to test once on Fedora 37 and then will push the patch but from the failure in your logs,  issue does not look related to this patch as the value of variable in rust language is shown wrong in Fedora 37 logs. For rust we only don’t print the shadowed variables but had to retry once on Fedora 37 then will confirm and push the v5 series for review.
Ubuntu22 logs:
~~~
Breakpoint 1, var_reuse::main () at sources/gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
19          let _y = 8;       // set breakpoint here
(gdb) info local _x
_x = 12
(gdb) PASS: gdb.rust/var_reuse.exp: print local _x variable testcase sources/gdb/gdb/testsuite/gdb.rust/var_reuse.exp completed in 7 seconds ~~~

Thanks & Best Regards
Abdul Basit

-----Original Message-----
From: Guinevere Larsen <blarsen@redhat.com>
Sent: Thursday, October 12, 2023 11:40 AM
To: Ijaz, Abdul B <abdul.b.ijaz@intel.com>; gdb-patches@sourceware.org
Cc: lsix@lancelotsix.com; pedro@palves.net
Subject: Re: [PATCH v4 1/2] gdb: add annotation in 'info locals' command for variables shadowing case

On 19/09/2023 18:46, Abdul Basit Ijaz via Gdb-patches wrote:
> 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>
>
> 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.
Thanks for working on this!

This patch seems to have slipped through the cracks and needs a small rebase, but the conflict was pretty trivial to resolve locally (inferior.h is also being added to printcmd.c)

I see a failure on the newly added test on my fedora37 machine:

Breakpoint 1, var_reuse::main () at
../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
19          let _y = 8;       // set breakpoint here
(gdb) info local _x
_x = 0
(gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable

I don't think this is related to the conflict, but I don't really have the time to diagnose what is going on.

> ---
>   gdb/doc/gdb.texinfo                           | 13 +++
>   gdb/printcmd.c                                | 11 ++-
>   gdb/stack.c                                   | 64 +++++++++++--
>   gdb/stack.h                                   |  3 +-
>   gdb/testsuite/gdb.ada/var_shadowing.exp       | 38 ++++++++
>   .../gdb.ada/var_shadowing/var_shadowing.adb   | 30 +++++++
>   gdb/testsuite/gdb.base/var-shadowing.c        | 49 ++++++++++
>   gdb/testsuite/gdb.base/var-shadowing.exp      | 90 +++++++++++++++++++
>   gdb/testsuite/gdb.base/var-shadowing2.c       | 16 ++++
>   gdb/testsuite/gdb.rust/var_reuse.exp          | 32 +++++++
>   gdb/testsuite/gdb.rust/var_reuse.rs           | 20 +++++
>   gdb/tracepoint.c                              |  3 +-
>   gdb/value.h                                   |  4 +-
>   13 files changed, 362 insertions(+), 11 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
> 9b7e06f3156..6a22bbf2531 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -8831,6 +8831,19 @@ 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; // breakpt
> +4: @}
> +(gdb) info locals
> +x = 4	<file.c:3>
> +x = 3	<file.c:1, shadowed>
> +@end smallexample
> +
> +If a variable is shadowed, then location information is printed and 
> +for the outermost scope variables "shadowed" string is printed as well.
> +
>   @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
> 8d7d04231fe..83008e5c3f3 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -55,6 +55,7 @@
>   #include "gdbsupport/gdb_optional.h"
>   #include "gdbsupport/gdb-safe-ctype.h"
>   #include "gdbsupport/rsp-low.h"
> +#include "include/libiberty.h"
>   
>   /* Chain containing all defined memory-tag subcommands.  */
>   
> @@ -2401,7 +2402,8 @@ clear_dangling_display_expressions (struct objfile *objfile)
>   void
>   print_variable_and_value (const char *name, struct symbol *var,
>   			  frame_info_ptr frame,
> -			  struct ui_file *stream, int indent)
> +			  struct ui_file *stream, int indent,
> +			  bool shadowed, bool printed)
>   {
>   
>     if (!name)
> @@ -2414,6 +2416,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 
> @@ -2424,6 +2427,12 @@ print_variable_and_value (const char *name, struct symbol *var,
>         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" : "");
> +
>         /* common_val_print invalidates FRAME when a pretty printer calls inferior
>   	 function.  */
>         frame = NULL;
> diff --git a/gdb/stack.c b/gdb/stack.c index 0b35d62f82f..0173e7341e9
> 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -56,6 +56,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.  */
> @@ -2211,10 +2212,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:
> @@ -2227,7 +2234,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)
> +	      && 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 latest declaration of variable
> +	     is accessible.  So print only the first instance and there is no
> +	     need of printing duplicates.  */
> +	  else if (current_language->la_language == language_rust
> +		   && shadowed && already_printed)
> +	    break;
> +	  else
> +	    cb (name, sym, false, false);
>   	  break;
>   
>   	default:
> @@ -2244,9 +2269,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 ();
> +    }
> +
> +  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.  */
> @@ -2268,14 +2315,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;
>   
> @@ -2295,7 +2344,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);
>   
>     /* print_variable_and_value invalidates FRAME.  */
>     frame = NULL;
> @@ -2478,7 +2528,7 @@ iterate_over_block_arg_vars (const struct block *b,
>   	  struct symbol *sym2
>   	    = lookup_symbol_search_name (sym->search_name (),
>   					 b, 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 1b0c2b342a4..72d843b66fb
> 100644
> --- a/gdb/stack.h
> +++ b/gdb/stack.h
> @@ -24,7 +24,8 @@ gdb::unique_xmalloc_ptr<char> find_frame_funname (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..da279da258d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing.exp
> @@ -0,0 +1,38 @@
> +# Copyright 2023 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" 
> +${testdir}/var_shadowing.adb] set i_level2 [gdb_get_line_number 
> +"I-Level2" ${testdir}/var_shadowing.adb] set i_level3 
> +[gdb_get_line_number "I-Level3" ${testdir}/var_shadowing.adb] set 
> +bp_location [gdb_get_line_number "BREAK" ${testdir}/var_shadowing.adb] 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..93cef5f0d6c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> @@ -0,0 +1,30 @@
> +--  Copyright 2023 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..18963514bbf
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.c
> @@ -0,0 +1,49 @@
> +/* Copyright (C) 2023 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;  /* 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 = 0; /* 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..c7e1e9eae2e
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.exp
> @@ -0,0 +1,90 @@
> +# Copyright 2023 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] {
> +    untested "failed to run to main"
> +    return -1
> +}
> +
> +set bp_line1 [gdb_get_line_number "bp for locals 1" ${srcfile}] set
> +bp_line2 [gdb_get_line_number "bp for locals 2" ${srcfile}] set
> +bp_line3 [gdb_get_line_number "bp for locals 3" ${srcfile}] set
> +bp_line4 [gdb_get_line_number "bp for locals 4" ${srcfile}] set
> +bp_line5 [gdb_get_line_number "bp for locals 5" ${srcfile}]
> +
> +set val1_d1 [gdb_get_line_number "val1-d1" ${srcfile}] set val1_d2 
> +[gdb_get_line_number "val1-d2" ${srcfile}] set val1_d3 
> +[gdb_get_line_number "val1-d3" ${srcfile}] set val2_d1 
> +[gdb_get_line_number "val2-d1" ${srcfile}] set val2_d2 
> +[gdb_get_line_number "val2-d2" ${srcfile}] set val2_d3 
> +[gdb_get_line_number "val2-d3" ${srcfile}] set val3_d1 
> +[gdb_get_line_number "val3-d1" ${srcfile}] set val3_d2 
> +[gdb_get_line_number "val3-d2" ${srcfile}] set a_line 
> +[gdb_get_line_number "bp for entry" ${srcfile}]
> +
> +gdb_breakpoint $srcfile:$bp_line1
> +gdb_test "continue" ".*bp for locals 1.*" "continue to outermost level"
> +gdb_test "info locals"  [multi_line \
> +    "val1 = 1"  \
> +    "val2 = 2"  \
> +    ] "info locals at outermost level"
> +
> +gdb_breakpoint $srcfile:$bp_line2
> +gdb_test "continue" ".*bp for locals 2.*" "continue to first level"
> +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_test "continue" ".*bp for locals 3.*" "continue to second level"
> +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_test "continue" ".*bp for locals 4.*" "continue to innermost level"
> +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_test "continue" ".*bp for locals 5.*" "continue to outermost level last"
> +gdb_test "info locals" [multi_line \
> +    "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..9bc55f95a84
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing2.c
> @@ -0,0 +1,16 @@
> +/* Copyright (C) 2023 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.rust/var_reuse.exp
> b/gdb/testsuite/gdb.rust/var_reuse.exp
> new file mode 100755
> index 00000000000..58b85518f55
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.exp
> @@ -0,0 +1,32 @@
> +# Copyright 2023 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
> +}
> +
> +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..03be7981ff1
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.rs
> @@ -0,0 +1,20 @@
> +// Copyright (C) 2023 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
> 205380476b3..02669b3d909 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -1048,7 +1048,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 1d5a0018f92..879fce544c3 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -1537,7 +1537,9 @@ extern void print_variable_and_value (const char *name,
>   				      struct symbol *var,
>   				      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);


--
Cheers,
Guinevere Larsen
She/Her/Hers

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
  
Guinevere Larsen Nov. 20, 2023, 5:21 p.m. UTC | #4
On 20/11/2023 11:26, Ijaz, Abdul B wrote:
> Hi Larsen,
>
>>> Breakpoint 1, var_reuse::main () at
>>> ../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
>>> 19          let _y = 8;       // set breakpoint here
>>> (gdb) info local _x
>>> _x = 0
>>> (gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable
>>> I don't think this is related to the conflict, but I don't really have
>>> the time to diagnose what is going on
>   >I have rebased locally where also saw this inferior.h minor conflict and fixed it. So far ran on ubuntu22 where test ran fine. Need to test once on Fedora 37 and then will push the patch but from the failure in your logs
>
> I can confirm that Fedora issue is not related to this patch as for the RUST language case in Fedora if we set breakpoints at line 18 and 19 of this test then we can see line 19 is always executed first so even with vanilla gdb on Fedora 37 we see the same behavior.  I am not sure if this is known issue in GDB for RUST language otherwise  please let me know if it will be fine with you to raise a GDB Bugzilla and add a kfail in this patch as issue is completely unrelated to this patch. (Note: issue is so far only valid for Fedora as it is not seen on Ubuntu).

Thanks for double checking this!  I also tested on fedora Rawhide and it 
also fails there.

It must be a change of behavior in the compiler... Fedora 37's version 
is 1.73, rawhide is 1.76 and Ubuntu's seems to be 1.66 (source: 
https://packages.ubuntu.com/jammy/rustc). Using `disas /m` on the test 
case, I see the reordered instructions, so there is some optimization 
sneaking into the testcase, if you have the time, it would be nice to 
check the proc used to compile to see if we need to add a new default 
flag to rustc, but if you can't fix it (time, interest, compiler bug, 
...) I think the way to go about this is to setup an XFAIL when rustc is 
too new.
  
Ijaz, Abdul B Nov. 21, 2023, 8:30 a.m. UTC | #5
Hi Larsen,

> It must be a change of behavior in the compiler... Fedora 37's version is 1.73, rawhide is 1.76 and Ubuntu's seems to be 1.66 (source: 
https://packages.ubuntu.com/jammy/rustc). Using `disas /m` on the test case, I see the reordered instructions, so there is some optimization sneaking into the testcase, if you have the time, it would be nice to check the proc used to compile to see if we need to add a new default flag to rustc, but if you can't fix it (time, interest, compiler bug,
...) I think the way to go about this is to setup an XFAIL when rustc is too new.

Thanks for the feedback. I found these two related options for rustc compiler " -C debuginfo=full -C opt-level=0" where opt-level by default is already 0 (minimum optimization) and debuginfo is also by default 0 (all debug info but just to be sure also try to use keywork full) in rustc.   So we are not needed to update these default values as these are already  what we need for debugging with gdb. If this would have worked then I could update the default compiler options in gdb.exp library file but as there is no affect so I have raised following bug (https://sourceware.org/bugzilla/show_bug.cgi?id=31079)  for gdb and added the XFAIL as it could be rustc issue. I will now send out v5 series for review so please have a look on it.

Thanks & Best Regards
Abdul Basit

-----Original Message-----
From: Guinevere Larsen <blarsen@redhat.com> 
Sent: Monday, November 20, 2023 6:21 PM
To: Ijaz, Abdul B <abdul.b.ijaz@intel.com>; gdb-patches@sourceware.org
Cc: lsix@lancelotsix.com; pedro@palves.net
Subject: Re: [PATCH v4 1/2] gdb: add annotation in 'info locals' command for variables shadowing case

On 20/11/2023 11:26, Ijaz, Abdul B wrote:
> Hi Larsen,
>
>>> Breakpoint 1, var_reuse::main () at
>>> ../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
>>> 19          let _y = 8;       // set breakpoint here
>>> (gdb) info local _x
>>> _x = 0
>>> (gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable I don't 
>>> think this is related to the conflict, but I don't really have the 
>>> time to diagnose what is going on
>   >I have rebased locally where also saw this inferior.h minor 
> conflict and fixed it. So far ran on ubuntu22 where test ran fine. 
> Need to test once on Fedora 37 and then will push the patch but from 
> the failure in your logs
>
> I can confirm that Fedora issue is not related to this patch as for the RUST language case in Fedora if we set breakpoints at line 18 and 19 of this test then we can see line 19 is always executed first so even with vanilla gdb on Fedora 37 we see the same behavior.  I am not sure if this is known issue in GDB for RUST language otherwise  please let me know if it will be fine with you to raise a GDB Bugzilla and add a kfail in this patch as issue is completely unrelated to this patch. (Note: issue is so far only valid for Fedora as it is not seen on Ubuntu).

Thanks for double checking this!  I also tested on fedora Rawhide and it also fails there.

It must be a change of behavior in the compiler... Fedora 37's version is 1.73, rawhide is 1.76 and Ubuntu's seems to be 1.66 (source: 
https://packages.ubuntu.com/jammy/rustc). Using `disas /m` on the test case, I see the reordered instructions, so there is some optimization sneaking into the testcase, if you have the time, it would be nice to check the proc used to compile to see if we need to add a new default flag to rustc, but if you can't fix it (time, interest, compiler bug,
...) I think the way to go about this is to setup an XFAIL when rustc is too new.

--
Cheers,
Guinevere Larsen
She/Her/Hers

>
> Fedora 37 Logs:
> ~~~
> Reading symbols from gdb/testsuite/outputs/gdb.rust/var_reuse/var_reuse...
> (gdb) b 18
> Breakpoint 1 at 0x8654: file gdb/testsuite/gdb.rust/var_reuse.rs, line 18.
> (gdb) b 19
> Breakpoint 2 at 0x864c: file gdb/testsuite/gdb.rust/var_reuse.rs, line 19.
> (gdb) r
> Starting program: gdb/testsuite/outputs/gdb.rust/var_reuse/var_reuse
> [Thread debugging using libthread_db enabled] Using host libthread_db 
> library "/lib64/libthread_db.so.1".
>
> Breakpoint 2, var_reuse::main () at gdb/testsuite/gdb.rust/var_reuse.rs:19
> 19          let _y = 8;       // set breakpoint here
> (gdb) info locals
> _y = 0
> _x = 0
> _x = 5
> (gdb) c
> Continuing.
>
> Breakpoint 1, var_reuse::main () at gdb/testsuite/gdb.rust/var_reuse.rs:18
> 18          let _x = _x + 7;
> (gdb) info locals
> _x = 5
> ~~~
>
> Thanks & Best Regards
> Abdul Basit
>
> -----Original Message-----
> From: Ijaz, Abdul B
> Sent: Monday, November 20, 2023 9:26 AM
> To: Guinevere Larsen <blarsen@redhat.com>; gdb-patches@sourceware.org
> Cc: lsix@lancelotsix.com; pedro@palves.net
> Subject: RE: [PATCH v4 1/2] gdb: add annotation in 'info locals' 
> command for variables shadowing case
>
> Hi Larsen,
>
> Thanks for the feedback.
>
>>> 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.
>> Thanks for working on this!
>> This patch seems to have slipped through the cracks and needs a small 
>> rebase, but the conflict was pretty trivial to resolve locally 
>> (inferior.h is also being added to printcmd.c) I see a failure on the 
>> newly added test on my fedora37 machine:
>> Breakpoint 1, var_reuse::main () at
>> ../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
>> 19          let _y = 8;       // set breakpoint here
>> (gdb) info local _x
>> _x = 0
>> (gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable I don't 
>> think this is related to the conflict, but I don't really have the 
>> time to diagnose what is going on
>   I have rebased locally where also saw this inferior.h minor conflict and fixed it. So far ran on ubuntu22 where test ran fine. Need to test once on Fedora 37 and then will push the patch but from the failure in your logs,  issue does not look related to this patch as the value of variable in rust language is shown wrong in Fedora 37 logs. For rust we only don’t print the shadowed variables but had to retry once on Fedora 37 then will confirm and push the v5 series for review.
> Ubuntu22 logs:
> ~~~
> Breakpoint 1, var_reuse::main () at sources/gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
> 19          let _y = 8;       // set breakpoint here
> (gdb) info local _x
> _x = 12
> (gdb) PASS: gdb.rust/var_reuse.exp: print local _x variable testcase 
> sources/gdb/gdb/testsuite/gdb.rust/var_reuse.exp completed in 7 
> seconds ~~~
>
> Thanks & Best Regards
> Abdul Basit
>
> -----Original Message-----
> From: Guinevere Larsen <blarsen@redhat.com>
> Sent: Thursday, October 12, 2023 11:40 AM
> To: Ijaz, Abdul B <abdul.b.ijaz@intel.com>; gdb-patches@sourceware.org
> Cc: lsix@lancelotsix.com; pedro@palves.net
> Subject: Re: [PATCH v4 1/2] gdb: add annotation in 'info locals' 
> command for variables shadowing case
>
> On 19/09/2023 18:46, Abdul Basit Ijaz via Gdb-patches wrote:
>> 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>
>>
>> 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.
> Thanks for working on this!
>
> This patch seems to have slipped through the cracks and needs a small 
> rebase, but the conflict was pretty trivial to resolve locally 
> (inferior.h is also being added to printcmd.c)
>
> I see a failure on the newly added test on my fedora37 machine:
>
> Breakpoint 1, var_reuse::main () at
> ../../../downstream-gdb/gdb/testsuite/gdb.rust/var_reuse.rs:19
> 19          let _y = 8;       // set breakpoint here
> (gdb) info local _x
> _x = 0
> (gdb) FAIL: gdb.rust/var_reuse.exp: print local _x variable
>
> I don't think this is related to the conflict, but I don't really have the time to diagnose what is going on.
>
>> ---
>>    gdb/doc/gdb.texinfo                           | 13 +++
>>    gdb/printcmd.c                                | 11 ++-
>>    gdb/stack.c                                   | 64 +++++++++++--
>>    gdb/stack.h                                   |  3 +-
>>    gdb/testsuite/gdb.ada/var_shadowing.exp       | 38 ++++++++
>>    .../gdb.ada/var_shadowing/var_shadowing.adb   | 30 +++++++
>>    gdb/testsuite/gdb.base/var-shadowing.c        | 49 ++++++++++
>>    gdb/testsuite/gdb.base/var-shadowing.exp      | 90 +++++++++++++++++++
>>    gdb/testsuite/gdb.base/var-shadowing2.c       | 16 ++++
>>    gdb/testsuite/gdb.rust/var_reuse.exp          | 32 +++++++
>>    gdb/testsuite/gdb.rust/var_reuse.rs           | 20 +++++
>>    gdb/tracepoint.c                              |  3 +-
>>    gdb/value.h                                   |  4 +-
>>    13 files changed, 362 insertions(+), 11 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
>> 9b7e06f3156..6a22bbf2531 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -8831,6 +8831,19 @@ 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; // breakpt
>> +4: @}
>> +(gdb) info locals
>> +x = 4	<file.c:3>
>> +x = 3	<file.c:1, shadowed>
>> +@end smallexample
>> +
>> +If a variable is shadowed, then location information is printed and 
>> +for the outermost scope variables "shadowed" string is printed as well.
>> +
>>    @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
>> 8d7d04231fe..83008e5c3f3 100644
>> --- a/gdb/printcmd.c
>> +++ b/gdb/printcmd.c
>> @@ -55,6 +55,7 @@
>>    #include "gdbsupport/gdb_optional.h"
>>    #include "gdbsupport/gdb-safe-ctype.h"
>>    #include "gdbsupport/rsp-low.h"
>> +#include "include/libiberty.h"
>>    
>>    /* Chain containing all defined memory-tag subcommands.  */
>>    
>> @@ -2401,7 +2402,8 @@ clear_dangling_display_expressions (struct objfile *objfile)
>>    void
>>    print_variable_and_value (const char *name, struct symbol *var,
>>    			  frame_info_ptr frame,
>> -			  struct ui_file *stream, int indent)
>> +			  struct ui_file *stream, int indent,
>> +			  bool shadowed, bool printed)
>>    {
>>    
>>      if (!name)
>> @@ -2414,6 +2416,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 @@ -2424,6 +2427,12 @@ print_variable_and_value (const char *name, struct symbol *var,
>>          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" : "");
>> +
>>          /* common_val_print invalidates FRAME when a pretty printer calls inferior
>>    	 function.  */
>>          frame = NULL;
>> diff --git a/gdb/stack.c b/gdb/stack.c index 0b35d62f82f..0173e7341e9
>> 100644
>> --- a/gdb/stack.c
>> +++ b/gdb/stack.c
>> @@ -56,6 +56,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.  */
>> @@ -2211,10 +2212,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:
>> @@ -2227,7 +2234,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)
>> +	      && 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 latest declaration of variable
>> +	     is accessible.  So print only the first instance and there is no
>> +	     need of printing duplicates.  */
>> +	  else if (current_language->la_language == language_rust
>> +		   && shadowed && already_printed)
>> +	    break;
>> +	  else
>> +	    cb (name, sym, false, false);
>>    	  break;
>>    
>>    	default:
>> @@ -2244,9 +2269,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 ();
>> +    }
>> +
>> +  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.  */
>> @@ -2268,14 +2315,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;
>>    
>> @@ -2295,7 +2344,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);
>>    
>>      /* print_variable_and_value invalidates FRAME.  */
>>      frame = NULL;
>> @@ -2478,7 +2528,7 @@ iterate_over_block_arg_vars (const struct block *b,
>>    	  struct symbol *sym2
>>    	    = lookup_symbol_search_name (sym->search_name (),
>>    					 b, 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 1b0c2b342a4..72d843b66fb
>> 100644
>> --- a/gdb/stack.h
>> +++ b/gdb/stack.h
>> @@ -24,7 +24,8 @@ gdb::unique_xmalloc_ptr<char> find_frame_funname (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..da279da258d
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.ada/var_shadowing.exp
>> @@ -0,0 +1,38 @@
>> +# Copyright 2023 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"
>> +${testdir}/var_shadowing.adb] set i_level2 [gdb_get_line_number 
>> +"I-Level2" ${testdir}/var_shadowing.adb] set i_level3 
>> +[gdb_get_line_number "I-Level3" ${testdir}/var_shadowing.adb] set 
>> +bp_location [gdb_get_line_number "BREAK" ${testdir}/var_shadowing.adb] 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..93cef5f0d6c
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
>> @@ -0,0 +1,30 @@
>> +--  Copyright 2023 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..18963514bbf
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.base/var-shadowing.c
>> @@ -0,0 +1,49 @@
>> +/* Copyright (C) 2023 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;  /* 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 = 0; /* 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..c7e1e9eae2e
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.base/var-shadowing.exp
>> @@ -0,0 +1,90 @@
>> +# Copyright 2023 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] {
>> +    untested "failed to run to main"
>> +    return -1
>> +}
>> +
>> +set bp_line1 [gdb_get_line_number "bp for locals 1" ${srcfile}] set
>> +bp_line2 [gdb_get_line_number "bp for locals 2" ${srcfile}] set
>> +bp_line3 [gdb_get_line_number "bp for locals 3" ${srcfile}] set
>> +bp_line4 [gdb_get_line_number "bp for locals 4" ${srcfile}] set
>> +bp_line5 [gdb_get_line_number "bp for locals 5" ${srcfile}]
>> +
>> +set val1_d1 [gdb_get_line_number "val1-d1" ${srcfile}] set val1_d2 
>> +[gdb_get_line_number "val1-d2" ${srcfile}] set val1_d3 
>> +[gdb_get_line_number "val1-d3" ${srcfile}] set val2_d1 
>> +[gdb_get_line_number "val2-d1" ${srcfile}] set val2_d2 
>> +[gdb_get_line_number "val2-d2" ${srcfile}] set val2_d3 
>> +[gdb_get_line_number "val2-d3" ${srcfile}] set val3_d1 
>> +[gdb_get_line_number "val3-d1" ${srcfile}] set val3_d2 
>> +[gdb_get_line_number "val3-d2" ${srcfile}] set a_line 
>> +[gdb_get_line_number "bp for entry" ${srcfile}]
>> +
>> +gdb_breakpoint $srcfile:$bp_line1
>> +gdb_test "continue" ".*bp for locals 1.*" "continue to outermost level"
>> +gdb_test "info locals"  [multi_line \
>> +    "val1 = 1"  \
>> +    "val2 = 2"  \
>> +    ] "info locals at outermost level"
>> +
>> +gdb_breakpoint $srcfile:$bp_line2
>> +gdb_test "continue" ".*bp for locals 2.*" "continue to first level"
>> +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_test "continue" ".*bp for locals 3.*" "continue to second level"
>> +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_test "continue" ".*bp for locals 4.*" "continue to innermost level"
>> +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_test "continue" ".*bp for locals 5.*" "continue to outermost level last"
>> +gdb_test "info locals" [multi_line \
>> +    "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..9bc55f95a84
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.base/var-shadowing2.c
>> @@ -0,0 +1,16 @@
>> +/* Copyright (C) 2023 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.rust/var_reuse.exp
>> b/gdb/testsuite/gdb.rust/var_reuse.exp
>> new file mode 100755
>> index 00000000000..58b85518f55
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.rust/var_reuse.exp
>> @@ -0,0 +1,32 @@
>> +# Copyright 2023 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
>> +}
>> +
>> +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..03be7981ff1
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.rust/var_reuse.rs
>> @@ -0,0 +1,20 @@
>> +// Copyright (C) 2023 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
>> 205380476b3..02669b3d909 100644
>> --- a/gdb/tracepoint.c
>> +++ b/gdb/tracepoint.c
>> @@ -1048,7 +1048,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 1d5a0018f92..879fce544c3 100644
>> --- a/gdb/value.h
>> +++ b/gdb/value.h
>> @@ -1537,7 +1537,9 @@ extern void print_variable_and_value (const char *name,
>>    				      struct symbol *var,
>>    				      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);
>
> --
> Cheers,
> Guinevere Larsen
> She/Her/Hers
>
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de> Managing 
> Directors: Christin Eisenschmid, Sharon Heck, 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 <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
  

Patch

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9b7e06f3156..6a22bbf2531 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -8831,6 +8831,19 @@  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; // breakpt
+4: @}
+(gdb) info locals
+x = 4	<file.c:3>
+x = 3	<file.c:1, shadowed>
+@end smallexample
+
+If a variable is shadowed, then location information is printed and for
+the outermost scope variables "shadowed" string is printed as well.
+
 @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 8d7d04231fe..83008e5c3f3 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -55,6 +55,7 @@ 
 #include "gdbsupport/gdb_optional.h"
 #include "gdbsupport/gdb-safe-ctype.h"
 #include "gdbsupport/rsp-low.h"
+#include "include/libiberty.h"
 
 /* Chain containing all defined memory-tag subcommands.  */
 
@@ -2401,7 +2402,8 @@  clear_dangling_display_expressions (struct objfile *objfile)
 void
 print_variable_and_value (const char *name, struct symbol *var,
 			  frame_info_ptr frame,
-			  struct ui_file *stream, int indent)
+			  struct ui_file *stream, int indent,
+			  bool shadowed, bool printed)
 {
 
   if (!name)
@@ -2414,6 +2416,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
@@ -2424,6 +2427,12 @@  print_variable_and_value (const char *name, struct symbol *var,
       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" : "");
+
       /* common_val_print invalidates FRAME when a pretty printer calls inferior
 	 function.  */
       frame = NULL;
diff --git a/gdb/stack.c b/gdb/stack.c
index 0b35d62f82f..0173e7341e9 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -56,6 +56,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.  */
@@ -2211,10 +2212,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:
@@ -2227,7 +2234,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)
+	      && 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 latest declaration of variable
+	     is accessible.  So print only the first instance and there is no
+	     need of printing duplicates.  */
+	  else if (current_language->la_language == language_rust
+		   && shadowed && already_printed)
+	    break;
+	  else
+	    cb (name, sym, false, false);
 	  break;
 
 	default:
@@ -2244,9 +2269,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 ();
+    }
+
+  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.  */
@@ -2268,14 +2315,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;
 
@@ -2295,7 +2344,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);
 
   /* print_variable_and_value invalidates FRAME.  */
   frame = NULL;
@@ -2478,7 +2528,7 @@  iterate_over_block_arg_vars (const struct block *b,
 	  struct symbol *sym2
 	    = lookup_symbol_search_name (sym->search_name (),
 					 b, 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 1b0c2b342a4..72d843b66fb 100644
--- a/gdb/stack.h
+++ b/gdb/stack.h
@@ -24,7 +24,8 @@  gdb::unique_xmalloc_ptr<char> find_frame_funname (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..da279da258d
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/var_shadowing.exp
@@ -0,0 +1,38 @@ 
+# Copyright 2023 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" ${testdir}/var_shadowing.adb]
+set i_level2 [gdb_get_line_number "I-Level2" ${testdir}/var_shadowing.adb]
+set i_level3 [gdb_get_line_number "I-Level3" ${testdir}/var_shadowing.adb]
+set bp_location [gdb_get_line_number "BREAK" ${testdir}/var_shadowing.adb]
+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..93cef5f0d6c
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
@@ -0,0 +1,30 @@ 
+--  Copyright 2023 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..18963514bbf
--- /dev/null
+++ b/gdb/testsuite/gdb.base/var-shadowing.c
@@ -0,0 +1,49 @@ 
+/* Copyright (C) 2023 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;  /* 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 = 0; /* 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..c7e1e9eae2e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/var-shadowing.exp
@@ -0,0 +1,90 @@ 
+# Copyright 2023 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] {
+    untested "failed to run to main"
+    return -1
+}
+
+set bp_line1 [gdb_get_line_number "bp for locals 1" ${srcfile}]
+set bp_line2 [gdb_get_line_number "bp for locals 2" ${srcfile}]
+set bp_line3 [gdb_get_line_number "bp for locals 3" ${srcfile}]
+set bp_line4 [gdb_get_line_number "bp for locals 4" ${srcfile}]
+set bp_line5 [gdb_get_line_number "bp for locals 5" ${srcfile}]
+
+set val1_d1 [gdb_get_line_number "val1-d1" ${srcfile}]
+set val1_d2 [gdb_get_line_number "val1-d2" ${srcfile}]
+set val1_d3 [gdb_get_line_number "val1-d3" ${srcfile}]
+set val2_d1 [gdb_get_line_number "val2-d1" ${srcfile}]
+set val2_d2 [gdb_get_line_number "val2-d2" ${srcfile}]
+set val2_d3 [gdb_get_line_number "val2-d3" ${srcfile}]
+set val3_d1 [gdb_get_line_number "val3-d1" ${srcfile}]
+set val3_d2 [gdb_get_line_number "val3-d2" ${srcfile}]
+set a_line [gdb_get_line_number "bp for entry" ${srcfile}]
+
+gdb_breakpoint $srcfile:$bp_line1
+gdb_test "continue" ".*bp for locals 1.*" "continue to outermost level"
+gdb_test "info locals"  [multi_line \
+    "val1 = 1"  \
+    "val2 = 2"  \
+    ] "info locals at outermost level"
+
+gdb_breakpoint $srcfile:$bp_line2
+gdb_test "continue" ".*bp for locals 2.*" "continue to first level"
+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_test "continue" ".*bp for locals 3.*" "continue to second level"
+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_test "continue" ".*bp for locals 4.*" "continue to innermost level"
+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_test "continue" ".*bp for locals 5.*" "continue to outermost level last"
+gdb_test "info locals" [multi_line \
+    "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..9bc55f95a84
--- /dev/null
+++ b/gdb/testsuite/gdb.base/var-shadowing2.c
@@ -0,0 +1,16 @@ 
+/* Copyright (C) 2023 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.rust/var_reuse.exp b/gdb/testsuite/gdb.rust/var_reuse.exp
new file mode 100755
index 00000000000..58b85518f55
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/var_reuse.exp
@@ -0,0 +1,32 @@ 
+# Copyright 2023 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
+}
+
+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..03be7981ff1
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/var_reuse.rs
@@ -0,0 +1,20 @@ 
+// Copyright (C) 2023 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 205380476b3..02669b3d909 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -1048,7 +1048,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 1d5a0018f92..879fce544c3 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1537,7 +1537,9 @@  extern void print_variable_and_value (const char *name,
 				      struct symbol *var,
 				      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);