public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] add annotation in 'info locals' command for variables shadowing case
@ 2021-07-28 17:43 abdul.b.ijaz
  2021-07-28 17:43 ` [PATCH 1/2] gdb: " abdul.b.ijaz
  2021-07-28 17:43 ` [PATCH 2/2] gdb: add shadowed field in '-stack-list-locals/variables' mi commands abdul.b.ijaz
  0 siblings, 2 replies; 5+ messages in thread
From: abdul.b.ijaz @ 2021-07-28 17:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: abdul.b.ijaz, jonah, Tankut.Baris.Aktemur

Hi All,

For variable shadowing case these patches add annotation "shadowed" to the
shadowed variables so that it is easier for end user to identify which
variable was shadowed.

@jonah can you please provide your feedback for this change since second
patch will change the response of '-stack-list-locals' and
'-stack-list-variables' command.

GDB Testsuite is executed on Ubuntu18.04 OS and there is no regression
seen with this change.

Best Regards,
Abdul Basit

Abdul Basit Ijaz (2):
  gdb: add annotation in 'info locals' command for variables shadowing
    case
  gdb: add shadowed field in '-stack-list-locals/variables' mi commands

 gdb/mi/mi-cmd-stack.c                         |  33 ++++-
 gdb/printcmd.c                                |   8 +-
 gdb/stack.c                                   |  40 +++++-
 gdb/stack.h                                   |   3 +-
 gdb/testsuite/gdb.base/var-shadowing.c        |  52 +++++++
 gdb/testsuite/gdb.base/var-shadowing.exp      |  79 +++++++++++
 gdb/testsuite/gdb.mi/mi-var-shadowing.c       |  48 +++++++
 gdb/testsuite/gdb.mi/mi-var-shadowing.exp     | 132 ++++++++++++++++++
 .../gdb.mi/mi2-amd64-entry-value.exp          |  18 +--
 gdb/testsuite/gdb.opt/inline-locals.exp       |   6 +-
 gdb/testsuite/gdb.rust/var_reuse.exp          |  33 +++++
 gdb/testsuite/gdb.rust/var_reuse.rs           |  20 +++
 gdb/testsuite/gdb.trace/entry-values.exp      |   2 +-
 gdb/tracepoint.c                              |   3 +-
 gdb/value.h                                   |   3 +-
 15 files changed, 454 insertions(+), 26 deletions(-)
 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.mi/mi-var-shadowing.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-var-shadowing.exp
 create mode 100755 gdb/testsuite/gdb.rust/var_reuse.exp
 create mode 100755 gdb/testsuite/gdb.rust/var_reuse.rs

-- 
2.31.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] gdb: add annotation in 'info locals' command for variables shadowing case
  2021-07-28 17:43 [PATCH 0/2] add annotation in 'info locals' command for variables shadowing case abdul.b.ijaz
@ 2021-07-28 17:43 ` abdul.b.ijaz
  2021-07-31 10:43   ` Philippe Waroquiers
  2021-07-28 17:43 ` [PATCH 2/2] gdb: add shadowed field in '-stack-list-locals/variables' mi commands abdul.b.ijaz
  1 sibling, 1 reply; 5+ messages in thread
From: abdul.b.ijaz @ 2021-07-28 17:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: abdul.b.ijaz, jonah, Tankut.Baris.Aktemur

For C/C++/Fortran 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 add '<shadowed>' annotation after
value of super-block shadowed variable.

Suppose we have

int x = 42;
  {
    int x = 99;
    x = 99; /* break here */
  }

The "info locals" command at the "break here" line gives the following
output:

(gdb) info locals
x = 99
x = 42

So far this scenario is only known case for C/C++/Fortran language so
to tackle in this case, when iterating over the stack frame variables keep
the track of inner block variables and when same variable is found in the
outer-block then print <shadowed> after its value.  Iteration of stack frame
variables always starts with inner block so gdb now print <shadowed> for
super-block duplicate variables like this:

(gdb) info locals
x = 99
x = 42	<shadowed>

In case of rust language it is possible to declare variable with same name
many times so in this case just print first instance of variable.

gdb/ChangeLog:
2021-07-28  Abdul Basit Ijaz  <abdul.b.ijaz@intel.com>

	* printcmd.c (print_variable_and_value): Print <shadowed>
	after the value of super-block variable in case of variable
	shadowing.
	* stack.c (iterate_over_block_locals): Detect variable shadowing
	using vector to track the inner block variables.
	(iterate_over_block_local_vars): Declare unordered_set type object
	and pass it to function 'iterate_over_block_locals'.
	(do_print_variable_and_value): Add Boolean variable in call back
	function to indicate variable shadowing.
	* stack.h (iterate_over_block_arg_local_vars_cb) : Ditto.
	* tracepoint.c (do_collect_symbol): Ditto.
	* value.h (print_variable_and_value): Add Boolean variable in
	function declaration to indicate variable shadowing.

gdb/testsuite/ChangeLog:
2021-07-28  Abdul Basit Ijaz  <abdul.b.ijaz@intel.com>

	* gdb.opt/inline-locals.exp: Update regex expressions for testing
	'info locals' command output to handle <shadowed> annotation.
	* gdb.base/var-shadowing.c: New file.
	* gdb.base/var-shadowing.exp: New file.
	* gdb.rust/var_reuse.exp: New file.
	* gdb.rust/var_reuse.rs: New file.

2021-07-28 Abdul Basit Ijaz <abdul.b.ijaz@intel.com>
---
 gdb/printcmd.c                           |  8 ++-
 gdb/stack.c                              | 40 ++++++++++--
 gdb/stack.h                              |  3 +-
 gdb/testsuite/gdb.base/var-shadowing.c   | 52 ++++++++++++++++
 gdb/testsuite/gdb.base/var-shadowing.exp | 79 ++++++++++++++++++++++++
 gdb/testsuite/gdb.opt/inline-locals.exp  |  6 +-
 gdb/testsuite/gdb.rust/var_reuse.exp     | 33 ++++++++++
 gdb/testsuite/gdb.rust/var_reuse.rs      | 20 ++++++
 gdb/tracepoint.c                         |  3 +-
 gdb/value.h                              |  3 +-
 10 files changed, 234 insertions(+), 13 deletions(-)
 create mode 100755 gdb/testsuite/gdb.base/var-shadowing.c
 create mode 100755 gdb/testsuite/gdb.base/var-shadowing.exp
 create mode 100755 gdb/testsuite/gdb.rust/var_reuse.exp
 create mode 100755 gdb/testsuite/gdb.rust/var_reuse.rs

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 416b87c69c..3c697db852 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -2388,7 +2388,8 @@ clear_dangling_display_expressions (struct objfile *objfile)
 void
 print_variable_and_value (const char *name, struct symbol *var,
 			  struct frame_info *frame,
-			  struct ui_file *stream, int indent)
+			  struct ui_file *stream, int indent,
+			  bool shadowed)
 {
 
   if (!name)
@@ -2411,6 +2412,11 @@ print_variable_and_value (const char *name, struct symbol *var,
       opts.deref_ref = 1;
       common_val_print_checked (val, stream, indent, &opts, current_language);
 
+      /* Print <shadowed> after the variable value only when it is variable
+	 shadowing case.  */
+      if (shadowed)
+	fprintf_styled (stream, metadata_style.style (), _("\t<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 aa20018ad9..765f7ac057 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -55,6 +55,7 @@
 #include "gdbsupport/def-vector.h"
 #include "cli/cli-option.h"
 #include "cli/cli-style.h"
+#include <unordered_set>
 
 /* The possible choices of "set print frame-arguments", and the value
    of this setting.  */
@@ -2248,13 +2249,17 @@ 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,
-			   void *cb_data)
+			   void *cb_data,
+			   std::unordered_set<std::string> &collected_vars)
 {
   struct block_iterator iter;
   struct symbol *sym;
 
   ALL_BLOCK_SYMBOLS (b, iter, sym)
     {
+      const char *name = sym->print_name ();
+      bool already_collected
+	= collected_vars.find (name) != collected_vars.end ();
       switch (SYMBOL_CLASS (sym))
 	{
 	case LOC_CONST:
@@ -2267,7 +2272,27 @@ iterate_over_block_locals (const struct block *b,
 	    break;
 	  if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN)
 	    break;
-	  (*cb) (sym->print_name (), sym, cb_data);
+	  /* Only for C/C++/Fortran languages, in case of variables shadowing
+	     print <shadowed> after the superblock variable.  Iteration of
+	     block starts from inner block so collected_vars variable keeps
+	     track of the variables in the innerblock.  */
+	  if ((current_language->la_language == language_c
+	       || current_language->la_language == language_cplus
+	       || current_language->la_language == language_fortran)
+	      && already_collected)
+	    (*cb) (name, sym, cb_data, true);
+	  /* 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
+		   && already_collected)
+	    break;
+	  else
+	    {
+	      collected_vars.insert (name);
+	      (*cb) (name, sym, cb_data, false);
+	    }
 	  break;
 
 	default:
@@ -2285,9 +2310,10 @@ iterate_over_block_local_vars (const struct block *block,
 			       iterate_over_block_arg_local_vars_cb cb,
 			       void *cb_data)
 {
+  std::unordered_set<std::string> collected_vars;
   while (block)
     {
-      iterate_over_block_locals (block, cb, cb_data);
+      iterate_over_block_locals (block, cb, cb_data, collected_vars);
       /* After handling the function's top-level block, stop.  Don't
 	 continue to its superblock, the block of per-file
 	 symbols.  */
@@ -2315,7 +2341,8 @@ struct print_variable_and_value_data
 static void
 do_print_variable_and_value (const char *print_name,
 			     struct symbol *sym,
-			     void *cb_data)
+			     void *cb_data,
+			     bool shadowed)
 {
   struct print_variable_and_value_data *p
     = (struct print_variable_and_value_data *) cb_data;
@@ -2335,7 +2362,8 @@ do_print_variable_and_value (const char *print_name,
       return;
     }
 
-  print_variable_and_value (print_name, sym, frame, p->stream, p->num_tabs);
+  print_variable_and_value (print_name, sym, frame, p->stream,
+			    p->num_tabs, shadowed);
 
   /* print_variable_and_value invalidates FRAME.  */
   frame = NULL;
@@ -2526,7 +2554,7 @@ iterate_over_block_arg_vars (const struct block *b,
 
 	  sym2 = lookup_symbol_search_name (sym->search_name (),
 					    b, VAR_DOMAIN).symbol;
-	  (*cb) (sym->print_name (), sym2, cb_data);
+	  (*cb) (sym->print_name (), sym2, cb_data, false);
 	}
     }
 }
diff --git a/gdb/stack.h b/gdb/stack.h
index 17d4119988..b063cb6348 100644
--- a/gdb/stack.h
+++ b/gdb/stack.h
@@ -32,7 +32,8 @@ gdb::unique_xmalloc_ptr<char> find_frame_funname (struct frame_info *frame,
 
 typedef void (*iterate_over_block_arg_local_vars_cb) (const char *print_name,
 						      struct symbol *sym,
-						      void *cb_data);
+						      void *cb_data,
+						      bool shadowed);
 
 void iterate_over_block_arg_vars (const struct block *block,
 				  iterate_over_block_arg_local_vars_cb cb,
diff --git a/gdb/testsuite/gdb.base/var-shadowing.c b/gdb/testsuite/gdb.base/var-shadowing.c
new file mode 100755
index 0000000000..6bc9272baf
--- /dev/null
+++ b/gdb/testsuite/gdb.base/var-shadowing.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2021 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/>.  */
+
+/* This is only ever run if it is compiled with a new-enough GCC, but
+   we don't want the compilation to fail if compiled by some other
+   compiler.  */
+
+#include <stdlib.h>
+
+void
+shadowing ()
+{
+  int a;
+  unsigned int val1 = 1;
+  unsigned int val2 = 2;
+  a = 101;  /* bp for locals 1 */
+  {
+    unsigned int val2 = 3;
+    unsigned int val3 = 4;
+    a = 102;  /* bp for locals 2 */
+    {
+      unsigned int val1 = 5;
+      a = 103;  /* bp for locals 3 */
+      {
+	unsigned int val1 = 6;
+	unsigned int val2 = 7;
+	unsigned int val3 = 8;
+	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 0000000000..4cb68cbd28
--- /dev/null
+++ b/gdb/testsuite/gdb.base/var-shadowing.exp
@@ -0,0 +1,79 @@
+# Copyright 2021 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}]
+
+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"  \
+    "val3 = 4"  \
+    "a = 101"   \
+    "val1 = 1"  \
+    "val2 = 2\t<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"  \
+    "val2 = 3"  \
+    "val3 = 4"  \
+    "a = 102"   \
+    "val1 = 1\t<shadowed>"  \
+    "val2 = 2\t<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 \
+    "val1 = 6"  \
+    "val2 = 7"  \
+    "val3 = 8"  \
+    "val1 = 5\t<shadowed>" \
+    "val2 = 3\t<shadowed>" \
+    "val3 = 4\t<shadowed>" \
+    "a = 103"   \
+    "val1 = 1\t<shadowed>" \
+    "val2 = 2\t<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.opt/inline-locals.exp b/gdb/testsuite/gdb.opt/inline-locals.exp
index ff9dd1b49e..b409d1cba0 100644
--- a/gdb/testsuite/gdb.opt/inline-locals.exp
+++ b/gdb/testsuite/gdb.opt/inline-locals.exp
@@ -45,7 +45,7 @@ if { ! $no_frames } {
     gdb_test "info frame" ".*inlined into frame.*" "func1 inlined 2"
     set pass_re "array = \\{0 <repeats 64 times>\\}"
     set kfail_re [multi_line $pass_re \
-		      "array = <optimized out>"]
+		      "array = <optimized out>\t<shadowed>"]
     gdb_test_multiple "info locals" "info locals above bar 2" {
 	-re -wrap $pass_re {
 	    pass $gdb_test_name
@@ -94,7 +94,7 @@ if { ! $no_frames } {
     gdb_test "info frame" ".*inlined into frame.*" "func1 inlined 3"
     set pass_re "array = {$decimal, \[^\r\n\]*}"
     set kfail_re [multi_line $pass_re \
-		      "array = <optimized out>"]
+		      "array = <optimized out>\t<shadowed>"]
     gdb_test_multiple "info locals" "info locals above bar 3" {
 	-re -wrap $pass_re {
 	    pass $gdb_test_name
@@ -134,7 +134,7 @@ proc check_scoped_locals {bp_label pass_re} {
     gdb_breakpoint $srcfile:$locals_bp
 
     gdb_continue_to_breakpoint "$bp_label" ".*$srcfile:$locals_bp.*"
-    set kfail_re [multi_line $pass_re ".*<optimized out>"]
+    set kfail_re [multi_line $pass_re ".*<optimized out>(\t<shadowed>)?"]
     gdb_test_multiple "info locals" "scoped info locals at $bp_label" {
 	-re -wrap $pass_re {
 	    pass $gdb_test_name
diff --git a/gdb/testsuite/gdb.rust/var_reuse.exp b/gdb/testsuite/gdb.rust/var_reuse.exp
new file mode 100755
index 0000000000..c535aaa759
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/var_reuse.exp
@@ -0,0 +1,33 @@
+# Copyright 2021 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
+if {[skip_rust_tests]} {
+    continue
+}
+
+standard_testfile .rs
+if {[prepare_for_testing "failed to prepare" \
+	$testfile $srcfile {debug rust}]} {
+    return -1
+}
+
+set line [gdb_get_line_number "set breakpoint here"]
+if {![runto ${srcfile}:$line]} {
+    untested "could not run to breakpoint"
+    return -1
+}
+
+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 0000000000..63d165c4aa
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/var_reuse.rs
@@ -0,0 +1,20 @@
+// Copyright (C) 2021 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 06cf9cad29..a464cf84b2 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -1059,7 +1059,8 @@ struct add_local_symbols_data
 static void
 do_collect_symbol (const char *print_name,
 		   struct symbol *sym,
-		   void *cb_data)
+		   void *cb_data,
+		   bool shadowed)
 {
   struct add_local_symbols_data *p = (struct add_local_symbols_data *) cb_data;
 
diff --git a/gdb/value.h b/gdb/value.h
index e1c6aabfa2..8307b8c333 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1104,7 +1104,8 @@ extern void print_variable_and_value (const char *name,
 				      struct symbol *var,
 				      struct frame_info *frame,
 				      struct ui_file *stream,
-				      int indent);
+				      int indent,
+				      bool shadowed);
 
 extern void typedef_print (struct type *type, struct symbol *news,
 			   struct ui_file *stream);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] gdb: add shadowed field in '-stack-list-locals/variables' mi commands
  2021-07-28 17:43 [PATCH 0/2] add annotation in 'info locals' command for variables shadowing case abdul.b.ijaz
  2021-07-28 17:43 ` [PATCH 1/2] gdb: " abdul.b.ijaz
@ 2021-07-28 17:43 ` abdul.b.ijaz
  1 sibling, 0 replies; 5+ messages in thread
From: abdul.b.ijaz @ 2021-07-28 17:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: abdul.b.ijaz, jonah, Tankut.Baris.Aktemur

For C/C++/Fortran 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 add 'shadowed' field in
'-stack-list-locals' mi command for value of super-block shadowed variable.

Suppose we have

int x = 42;
  {
    int x = 99;
    x = 99; /* break here */
  }

The "-stack-list-locals" and "-stack-list-variables" mi commands at the
"break here" line gives the following output:

(gdb)
-stack-list-locals 0
^done,locals=[name="x",name="x"]
(gdb)
-stack-list-locals 1
^done,locals=[{name="x",value="99"},{name="x",value="42"}]
(gdb)
-stack-list-locals 2
^done,locals=[{name="x",type="int",value="99"},{name="x",type="int",value="42"}]
(gdb)
-stack-list-variables 0
^done,variables=[{name="x"},{name="x"}]
(gdb)
-stack-list-variables 1
^done,variables=[{name="x",value="99"},{name="x",value="42"}]
(gdb)
-stack-list-variables 2
^done,variables=[{name="x",type="int",value="99"},{name="x",type="int",value="42"}]

So far this scenario is only known case for C/C++/Fortran language so
to tackle in this case, when iterating over the stack frame variables keep
the track of inner block variables and when same variable is found in the
outer-block then add shadowed in mi command output with only exception to
'stack-list-locals 0' case where it is not added.  Iteration of stack
frame variables always starts with inner block so gdb now print shadowed
field with value true for super-block duplicate variables like this:

(gdb)
-stack-list-locals 0
^done,locals=[name="x",name="x"]
(gdb)
-stack-list-locals 1
^done,locals=[{name="x",value="99"},{name="x",shadowed="true",value="42"}]
(gdb)
-stack-list-locals 2
^done,locals=[{name="x",type="int",value="99"},{name="x",shadowed="true",type="int",value="42"}]
(gdb)
-stack-list-variables 0
^done,variables=[{name="x"},{name="x",shadowed="true"}]
(gdb)
-stack-list-variables 1
^done,variables=[{name="x",value="99"},{name="x",shadowed="true",value="42"}]
(gdb)
-stack-list-variables 2
^done,variables=[{name="x",type="int",value="99"},{name="x",shadowed="true",type="int",value="42"}]

In case of rust language it is possible to declare variable with same name
many times so in this case just print only first instance of variable.

gdb/ChangeLog:
2021-07-28  Abdul Basit Ijaz  <abdul.b.ijaz@intel.com>

	* mi/mi-cmd-stack.c (list_arg_or_local): Print shadowed field
	with value true after the value of super-block variable in
	case of variable shadowing.
	(list_args_or_locals): Declare unordered_set type object and
	pass it to function 'list_arg_or_local'.

gdb/testsuite/ChangeLog:
2021-07-28  Abdul Basit Ijaz  <abdul.b.ijaz@intel.com>

	* gdb.mi/mi2-amd64-entry-value.exp: Update regex expressions for
	testing '-stack-list-variables' mi command output to handle shadowed
	field.
	* gdb.trace/entry-values.exp: Ditto.
	* gdb.mi/mi-var-shadowing.c: New file.
	* gdb.mi/mi-var-shadowing.exp: New file.

2021-07-28 Abdul Basit Ijaz <abdul.b.ijaz@intel.com>
---
 gdb/mi/mi-cmd-stack.c                         |  33 ++++-
 gdb/testsuite/gdb.mi/mi-var-shadowing.c       |  48 +++++++
 gdb/testsuite/gdb.mi/mi-var-shadowing.exp     | 132 ++++++++++++++++++
 .../gdb.mi/mi2-amd64-entry-value.exp          |  18 +--
 gdb/testsuite/gdb.trace/entry-values.exp      |   2 +-
 5 files changed, 220 insertions(+), 13 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-var-shadowing.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-var-shadowing.exp

diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
index 9bc9010239..673d3e3e3e 100644
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -36,6 +36,7 @@
 #include "mi-parse.h"
 #include "gdbsupport/gdb_optional.h"
 #include "safe-ctype.h"
+#include <unordered_set>
 
 enum what_to_list { locals, arguments, all };
 
@@ -484,7 +485,8 @@ mi_cmd_stack_list_variables (const char *command, char **argv, int argc)
 
 static void
 list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
-		   enum print_values values, int skip_unavailable)
+		   enum print_values values, int skip_unavailable,
+		   std::unordered_set<std::string> &collected_vars)
 {
   struct ui_out *uiout = current_uiout;
 
@@ -514,6 +516,15 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
     tuple_emitter.emplace (uiout, nullptr);
 
   string_file stb;
+  bool already_collected
+    = collected_vars.find (arg->sym->print_name ()) != collected_vars.end ();
+
+  /* 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.  */
+  if (current_language->la_language == language_rust && already_collected)
+    return;
 
   stb.puts (arg->sym->print_name ());
   if (arg->entry_kind == print_entry_values_only)
@@ -523,6 +534,19 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
   if (what == all && SYMBOL_IS_ARGUMENT (arg->sym))
     uiout->field_signed ("arg", 1);
 
+  /* Only for C/C++/Fortran languages, in case of variables shadowing
+     print shadowed field after the superblock variable.  Iteration of
+     block starts from inner block so collected_vars variable keeps
+     track of the variables in the innerblock.  */
+  if ((current_language->la_language == language_c
+	|| current_language->la_language == language_cplus
+	|| current_language->la_language == language_fortran)
+	&& !(values == PRINT_NO_VALUES && what == locals)
+	&& already_collected)
+    uiout->field_string ("shadowed", "true");
+  else
+    collected_vars.insert (arg->sym->print_name ());
+
   if (values == PRINT_SIMPLE_VALUES)
     {
       check_typedef (arg->sym->type);
@@ -572,6 +596,7 @@ list_args_or_locals (const frame_print_options &fp_opts,
   struct type *type;
   const char *name_of_result;
   struct ui_out *uiout = current_uiout;
+  std::unordered_set<std::string> collected_vars;
 
   block = get_frame_block (fi, 0);
 
@@ -663,9 +688,11 @@ list_args_or_locals (const frame_print_options &fp_opts,
 		}
 
 	      if (arg.entry_kind != print_entry_values_only)
-		list_arg_or_local (&arg, what, values, skip_unavailable);
+		list_arg_or_local (&arg, what, values,
+				   skip_unavailable, collected_vars);
 	      if (entryarg.entry_kind != print_entry_values_no)
-		list_arg_or_local (&entryarg, what, values, skip_unavailable);
+		list_arg_or_local (&entryarg, what, values,
+				   skip_unavailable, collected_vars);
 	    }
 	}
 
diff --git a/gdb/testsuite/gdb.mi/mi-var-shadowing.c b/gdb/testsuite/gdb.mi/mi-var-shadowing.c
new file mode 100644
index 0000000000..5e72754a53
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-shadowing.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 2021 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 ()
+{
+  int a;
+  unsigned int val1 = 1;
+  unsigned int val2 = 2;
+  a = 101;  /* bp for locals 1 */
+  {
+    unsigned int val2 = 3;
+    unsigned int val3 = 4;
+    a = 102;  /* bp for locals 2 */
+    {
+      unsigned int val1 = 5;
+      a = 103;  /* bp for locals 3 */
+      {
+	unsigned int val1 = 6;
+	unsigned int val2 = 7;
+	unsigned int val3 = 8;
+	a = 104;  /* bp for locals 4 */
+      }
+    }
+  }
+  a = 105; /* bp for locals 5 */
+}
+
+int
+main (void)
+{
+  shadowing ();
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-var-shadowing.exp b/gdb/testsuite/gdb.mi/mi-var-shadowing.exp
new file mode 100644
index 0000000000..2965202093
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-shadowing.exp
@@ -0,0 +1,132 @@
+# Copyright 2021 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 mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if [mi_gdb_start] {
+    continue
+}
+
+standard_testfile
+
+set opts {debug}
+if [build_executable ${testfile}.exp ${testfile} ${srcfile} $opts] {
+    return -1
+}
+
+mi_clean_restart $binfile
+
+if {[mi_runto_main] < 0} {
+    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 stack_test1_regx "\\^done,(locals|variables)=\\\[\{name=\"a\",type=\"int\",value=\"$decimal\"\},\{name=\"val1\",type=\"unsigned int\",value=\"1\"\},{name=\"val2\",type=\"unsigned int\",value=\"2\"\}\\\]"
+set stack_test2_regx "\\^done,(locals|variables)=\\\[\{name=\"val2\",type=\"unsigned int\",value=\"3\"\},\{name=\"val3\",type=\"unsigned int\",value=\"4\"\},\{name=\"a\",type=\"int\",value=\"101\"\},\{name=\"val1\",type=\"unsigned int\",value=\"1\"\},\{name=\"val2\",shadowed=\"true\",type=\"unsigned int\",value=\"2\"\}\\\]"
+set stack_test3_regx "\\^done,(locals|variables)=\\\[\{name=\"val1\",type=\"unsigned int\",value=\"5\"},{name=\"val2\",type=\"unsigned int\",value=\"3\"\},\{name=\"val3\",type=\"unsigned int\",value=\"4\"\},\{name=\"a\",type=\"int\",value=\"102\"\},\{name=\"val1\",shadowed=\"true\",type=\"unsigned int\",value=\"1\"\},\{name=\"val2\",shadowed=\"true\",type=\"unsigned int\",value=\"2\"\}\\\]"
+set stack_test4_regx "\\^done,(locals|variables)=\\\[\{name=\"val1\",type=\"unsigned int\",value=\"6\"\},\{name=\"val2\",type=\"unsigned int\",value=\"7\"\},\{name=\"val3\",type=\"unsigned int\",value=\"8\"\},\{name=\"val1\",shadowed=\"true\",type=\"unsigned int\",value=\"5\"\},\{name=\"val2\",shadowed=\"true\",type=\"unsigned int\",value=\"3\"\},\{name=\"val3\",shadowed=\"true\",type=\"unsigned int\",value=\"4\"\},\{name=\"a\",type=\"int\",value=\"103\"\},\{name=\"val1\",shadowed=\"true\",type=\"unsigned int\",value=\"1\"\},\{name=\"val2\",shadowed=\"true\",type=\"unsigned int\",value=\"2\"\}\\\]"
+set stack_test5_regx "\\^done,(locals|variables)=\\\[\{name=\"a\",type=\"int\",value=\"104\"\},\{name=\"val1\",type=\"unsigned int\",value=\"1\"\},\{name=\"val2\",type=\"unsigned int\",value=\"2\"\}\\\]"
+
+mi_gdb_test \
+    "-break-insert --source ${srcfile} --line ${bp_line1}"  \
+    "\\^done.*source ${srcfile} \\-line ${bp_line1}.*"  \
+    "bp at outermost level"
+mi_execute_to "exec-continue" "breakpoint-hit" ".*" ".*" ".*" "${bp_line1}"  \
+    { "" "disp=\"keep\"" } "continue to outermost level"
+mi_gdb_test "-stack-list-locals 0" \
+    "\\^done,locals=\\\[name=\"a\",name=\"val1\",name=\"val2\"\\\]" \
+    "-stack-list-locals 0 at outermost level"
+mi_gdb_test "-stack-list-variables 0" \
+    "\\^done,variables=\\\[{name=\"a\"},{name=\"val1\"},{name=\"val2\"}\\\]" \
+    "-stack-list-variables 0 at outermost level"
+mi_gdb_test "-stack-list-locals 2" "${stack_test1_regx}"  \
+    "-stack-list-locals 2 at outermost level"
+mi_gdb_test "-stack-list-variables 2" "${stack_test1_regx}"  \
+    "-stack-list-variables 2 at outermost level"
+
+mi_gdb_test  \
+    "-break-insert --source ${srcfile} --line ${bp_line2}"  \
+    "\\^done.*source ${srcfile} \\-line ${bp_line2}.*"  \
+    "bp at first level"
+mi_execute_to "exec-continue" "breakpoint-hit" ".*" ".*" ".*" "${bp_line2}"  \
+    { "" "disp=\"keep\"" } "continue to first level"
+mi_gdb_test "-stack-list-locals 0"  \
+    "\\^done,locals=\\\[name=\"val2\",name=\"val3\",name=\"a\",name=\"val1\",name=\"val2\"\\\]"  \
+    "-stack-list-locals 0 at first level"
+mi_gdb_test "-stack-list-variables 0" \
+    "\\^done,variables=\\\[{name=\"val2\"},{name=\"val3\"},{name=\"a\"},{name=\"val1\"},{name=\"val2\",shadowed=\"true\"}\\\]"  \
+    "-stack-list-variables 0 at first level"
+mi_gdb_test "-stack-list-locals 2" "${stack_test2_regx}"  \
+    "-stack-list-locals 2 at first level"
+mi_gdb_test "-stack-list-variables 2" "${stack_test2_regx}"  \
+    "-stack-list-variables 2 at first level"
+
+mi_gdb_test  \
+    "-break-insert --source ${srcfile} --line ${bp_line3}"  \
+    "\\^done.*source ${srcfile} \\-line ${bp_line3}.*"  \
+    "bp at second level"
+mi_execute_to "exec-continue" "breakpoint-hit" ".*" ".*" ".*" "${bp_line3}"  \
+    { "" "disp=\"keep\"" } "continue to second level"
+mi_gdb_test "-stack-list-locals 0"  \
+     "\\^done,locals=\\\[name=\"val1\",name=\"val2\",name=\"val3\",name=\"a\",name=\"val1\",name=\"val2\"\\\]"  \
+    "-stack-list-locals 0 at second level"
+mi_gdb_test "-stack-list-variables 0"  \
+     "\\^done,variables=\\\[{name=\"val1\"},{name=\"val2\"},{name=\"val3\"},{name=\"a\"},{name=\"val1\",shadowed=\"true\"},{name=\"val2\",shadowed=\"true\"}\\\]"  \
+    "-stack-list-variables 0 at second level"
+mi_gdb_test "-stack-list-locals 2" "${stack_test3_regx}"  \
+     "-stack-list-locals 2 at second level"
+mi_gdb_test "-stack-list-variables 2" "${stack_test3_regx}"  \
+     "-stack-list-variables 2 at second level"
+
+mi_gdb_test  \
+    "-break-insert --source ${srcfile} --line ${bp_line4}"  \
+    "\\^done.*source ${srcfile} \\-line ${bp_line4}.*"  \
+    "bp at third level"
+mi_execute_to "exec-continue" "breakpoint-hit" ".*" ".*" ".*" "${bp_line4}"  \
+    { "" "disp=\"keep\"" } "continue to third level"
+mi_gdb_test "-stack-list-locals 0"  \
+    "\\^done,locals=\\\[name=\"val1\",name=\"val2\",name=\"val3\",name=\"val1\",name=\"val2\",name=\"val3\",name=\"a\",name=\"val1\",name=\"val2\"\\\]"  \
+    "-stack-list-locals 0 at third level"
+mi_gdb_test "-stack-list-variables 0" \
+    "\\^done,variables=\\\[{name=\"val1\"},{name=\"val2\"},{name=\"val3\"},{name=\"val1\",shadowed=\"true\"},{name=\"val2\",shadowed=\"true\"},{name=\"val3\",shadowed=\"true\"},{name=\"a\"},{name=\"val1\",shadowed=\"true\"},{name=\"val2\",shadowed=\"true\"}\\\]"  \
+    "-stack-list-variables 0 at third level"
+mi_gdb_test "-stack-list-locals 2" "${stack_test4_regx}"  \
+    "-stack-list-locals 2 at third level"
+mi_gdb_test "-stack-list-variables 2" "${stack_test4_regx}"  \
+    "-stack-list-variables 2 at third level"
+
+mi_gdb_test  \
+    "-break-insert --source ${srcfile} --line ${bp_line5}"  \
+    "\\^done.*source ${srcfile} \\-line ${bp_line5}.*"  \
+    "bp at outermost level last"
+mi_execute_to "exec-continue" "breakpoint-hit" ".*" ".*" ".*" "${bp_line5}"  \
+    { "" "disp=\"keep\"" } "continue to outermost level last"
+mi_gdb_test "-stack-list-locals 0"  \
+    "\\^done,locals=\\\[name=\"a\",name=\"val1\",name=\"val2\"\\\]"  \
+    "-stack-list-locals 0 at outermost level last"
+mi_gdb_test "-stack-list-variables 0"  \
+    "\\^done,variables=\\\[{name=\"a\"},{name=\"val1\"},{name=\"val2\"}\\\]"  \
+    "-stack-list-variables at outermost level last"
+mi_gdb_test "-stack-list-locals 2" "${stack_test5_regx}"  \
+    "-stack-list-locals 2 at outermost level last"
+mi_gdb_test "-stack-list-variables 2" "${stack_test5_regx}"  \
+    "-stack-list-variables 2 at outermost level last"
diff --git a/gdb/testsuite/gdb.mi/mi2-amd64-entry-value.exp b/gdb/testsuite/gdb.mi/mi2-amd64-entry-value.exp
index 4505bfada6..0bbe04fb6d 100644
--- a/gdb/testsuite/gdb.mi/mi2-amd64-entry-value.exp
+++ b/gdb/testsuite/gdb.mi/mi2-amd64-entry-value.exp
@@ -123,16 +123,16 @@ if {[mi_runto_main] == -1} {
 mi_gdb_test "-gdb-set print entry-values both" {\^done} "both: set print entry-values"
 mi_send_resuming_command "exec-continue" "both: entry_equal: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="val",value="5"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "both: entry_equal: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",value="5"}\]} "both: entry_equal: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",shadowed="true",value="5"}\]} "both: entry_equal: -stack-list-variables"
 mi_send_resuming_command "exec-continue" "both: entry_different: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="val",value="6"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "both: entry_different: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",value="5"}\]} "both: entry_different: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",shadowed="true",value="5"}\]} "both: entry_different: -stack-list-variables"
 mi_send_resuming_command "exec-continue" "both: validity: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="lost",value="<optimized out>"},{name="lost@entry",value="5"},{name="born",value="10"},{name="born@entry",value="<optimized out>"}} .* .* {.* disp="keep"} "both: validity: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost",arg="1",value="<optimized out>"},{name="lost@entry",arg="1",value="5"},{name="born",arg="1",value="10"},{name="born@entry",arg="1",value="<optimized out>"}\]} "both: validity: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost",arg="1",value="<optimized out>"},{name="lost@entry",arg="1",shadowed="true",value="5"},{name="born",arg="1",value="10"},{name="born@entry",arg="1",shadowed="true",value="<optimized out>"}\]} "both: validity: -stack-list-variables"
 mi_send_resuming_command "exec-continue" "both: invalid: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="inv",value="<optimized out>"},{name="inv@entry",value="<optimized out>"}} .* .* {.* disp="keep"} "both: invalid: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv",arg="1",value="<optimized out>"},{name="inv@entry",arg="1",value="<optimized out>"}\]} "both: invalid: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv",arg="1",value="<optimized out>"},{name="inv@entry",arg="1",shadowed="true",value="<optimized out>"}\]} "both: invalid: -stack-list-variables"
 
 if {[mi_runto_main] == -1} {
     return -1
@@ -140,10 +140,10 @@ if {[mi_runto_main] == -1} {
 mi_gdb_test "-gdb-set print entry-values compact" {\^done} "compact: set print entry-values"
 mi_send_resuming_command "exec-continue" "compact: entry_equal: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="val",value="5"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "compact: entry_equal: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",value="5"}\]} "compact: entry_equal: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",shadowed="true",value="5"}\]} "compact: entry_equal: -stack-list-variables"
 mi_send_resuming_command "exec-continue" "compact: entry_different: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="val",value="6"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "compact: entry_different: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",value="5"}\]} "compact: entry_different: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",shadowed="true",value="5"}\]} "compact: entry_different: -stack-list-variables"
 mi_send_resuming_command "exec-continue" "compact: validity: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="lost@entry",value="5"},{name="born",value="10"}} .* .* {.* disp="keep"} "compact: validity: stop"
 mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost@entry",arg="1",value="5"},{name="born",arg="1",value="10"}\]} "compact: validity: -stack-list-variables"
@@ -157,13 +157,13 @@ if {[mi_runto_main] == -1} {
 mi_gdb_test "-gdb-set print entry-values default" {\^done} "default: set print entry-values"
 mi_send_resuming_command "exec-continue" "default: entry_equal: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="val",value="5"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "default: entry_equal: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",value="5"}\]} "default: entry_equal: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",shadowed="true",value="5"}\]} "default: entry_equal: -stack-list-variables"
 mi_send_resuming_command "exec-continue" "default: entry_different: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="val",value="6"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "default: entry_different: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",value="5"}\]} "default: entry_different: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",shadowed="true",value="5"}\]} "default: entry_different: -stack-list-variables"
 mi_send_resuming_command "exec-continue" "default: validity: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="lost",value="<optimized out>"},{name="lost@entry",value="5"},{name="born",value="10"}} .* .* {.* disp="keep"} "default: validity: stop"
-mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost",arg="1",value="<optimized out>"},{name="lost@entry",arg="1",value="5"},{name="born",arg="1",value="10"}\]} "default: validity: -stack-list-variables"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost",arg="1",value="<optimized out>"},{name="lost@entry",arg="1",shadowed="true",value="5"},{name="born",arg="1",value="10"}\]} "default: validity: -stack-list-variables"
 mi_send_resuming_command "exec-continue" "default: invalid: continue"
 mi_expect_stop "breakpoint-hit" .* {{name="inv",value="<optimized out>"}} .* .* {.* disp="keep"} "default: invalid: stop"
 mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv",arg="1",value="<optimized out>"}\]} "default: invalid: -stack-list-variables"
diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp
index 3695a1ee11..487d496098 100644
--- a/gdb/testsuite/gdb.trace/entry-values.exp
+++ b/gdb/testsuite/gdb.trace/entry-values.exp
@@ -241,6 +241,6 @@ gdb_test "bt 1" "#0 .* foo \\(i=\[-\]?$decimal, i@entry=2, j=\[-\]?$decimal, j@e
 # Test that unavailable "j@entry" is not shown when command option
 # --skip-unavailable is used.
 gdb_test "interpreter-exec mi \"-stack-list-arguments --skip-unavailable --simple-values\"" \
-    "\r\n\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"i\",type=\"int\",value=\".*\"},{name=\"i@entry\",type=\"int\",value=\"2\"},{name=\"j\",type=\"int\",value=\".*\"}\\\]},frame=.*\\\].*"
+    "\r\n\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"i\",type=\"int\",value=\".*\"},{name=\"i@entry\",shadowed=\"true\",type=\"int\",value=\"2\"},{name=\"j\",type=\"int\",value=\".*\"}\\\]},frame=.*\\\].*"
 
 gdb_test "tfind" "Target failed to find requested trace frame\..*"
-- 
2.31.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] gdb: add annotation in 'info locals' command for variables shadowing case
  2021-07-28 17:43 ` [PATCH 1/2] gdb: " abdul.b.ijaz
@ 2021-07-31 10:43   ` Philippe Waroquiers
  2021-08-23  9:03     ` Ijaz, Abdul B
  0 siblings, 1 reply; 5+ messages in thread
From: Philippe Waroquiers @ 2021-07-31 10:43 UTC (permalink / raw)
  To: abdul.b.ijaz, gdb-patches; +Cc: abdul.b.ijaz

On Wed, 2021-07-28 at 19:43 +0200, abdul.b.ijaz via Gdb-patches wrote:
> 
> (gdb) info locals
> x = 99
> x = 42
> 
> So far this scenario is only known case for C/C++/Fortran language so
> to tackle in this case, when iterating over the stack frame variables keep
> the track of inner block variables and when same variable is found in the
> outer-block then print <shadowed> after its value.  Iteration of stack frame
> variables always starts with inner block so gdb now print <shadowed> for
> super-block duplicate variables like this:
> 
> (gdb) info locals
> x = 99
> x = 42	<shadowed>

Effectively, it is nice to better handle shadowed variables.
Note however that we can have several levels of inner blocks,
and then the <shadowed> indication might not clearly indicate which variable it is.
E.g.:
  (gdb) info locals
  x = 111
  x = 11
  x = 1
  (gdb)

Maybe "info locals" could rather output the location of the variables,
either automatically when there is some shadowing and/or with an optional argument,
e.g.
   info locals [-q] [-location] [-t TYPEREGEXP] [NAMEREGEXP]
   ....
   The location of a variable is output if -location is provided or when
   a variable shadows another variable.
   ...

Philippe



^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH 1/2] gdb: add annotation in 'info locals' command for variables shadowing case
  2021-07-31 10:43   ` Philippe Waroquiers
@ 2021-08-23  9:03     ` Ijaz, Abdul B
  0 siblings, 0 replies; 5+ messages in thread
From: Ijaz, Abdul B @ 2021-08-23  9:03 UTC (permalink / raw)
  To: Philippe Waroquiers, abdul.b.ijaz, gdb-patches, simon.marchi, tom

On Wed, 2021-07-28 at 19:43 +0200, abdul.b.ijaz via Gdb-patches wrote:
> (gdb) info locals
> x = 99
> x = 42
> 
> So far this scenario is only known case for C/C++/Fortran language so 
> to tackle in this case, when iterating over the stack frame variables 
> keep the track of inner block variables and when same variable is 
> found in the outer-block then print <shadowed> after its value.  
> Iteration of stack frame variables always starts with inner block so 
> gdb now print <shadowed> for super-block duplicate variables like this:
> 
> (gdb) info locals
> x = 99
> x = 42	<shadowed>

Effectively, it is nice to better handle shadowed variables.
Note however that we can have several levels of inner blocks, and then the <shadowed> indication might not clearly indicate which variable it is.
E.g.:
  (gdb) info locals
  x = 111
  x = 11
  x = 1
  (gdb)

Maybe "info locals" could rather output the location of the variables, either automatically when there is some shadowing and/or with an optional argument, e.g.
   info locals [-q] [-location] [-t TYPEREGEXP] [NAMEREGEXP]
   ....
   The location of a variable is output if -location is provided or when
   a variable shadows another variable.
   ...


>> Thanks Philippe for the feedback. I understand your concern that adding shadowed to several level inner blocks will still not indicate clearly which variable but only for the intermediate blocks although it will still indicate the innermost block variable like below and also test is added for multiple inner levels.  
  (gdb) info locals
  x = 111 
  x = 11 <shadowed>
  x = 1 <shadowed>
So based on your feedback in my opinion adding variable location to output could be good option by default for variable shadowing case instead of optional argument. So please confirm shall I update it accordingly. It was updated like this based on the feedback on following request so adding Tom, Simon and Baris in case they have any further feedback on this:
https://sourceware.org/pipermail/gdb-patches/2021-June/180478.html 

Best Regards
Abdul Basit


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

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-08-23  9:04 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-28 17:43 [PATCH 0/2] add annotation in 'info locals' command for variables shadowing case abdul.b.ijaz
2021-07-28 17:43 ` [PATCH 1/2] gdb: " abdul.b.ijaz
2021-07-31 10:43   ` Philippe Waroquiers
2021-08-23  9:03     ` Ijaz, Abdul B
2021-07-28 17:43 ` [PATCH 2/2] gdb: add shadowed field in '-stack-list-locals/variables' mi commands abdul.b.ijaz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).