[binutils-gdb] gdb: add shadowed field in '-stack-list-locals/variables' mi commands

Abdul Basit Ijaz via Gdb-cvs <[email protected]> Fri, 17 Jul 2026 17:39:36 +0000 (GMT)
Newsgroups gmane.comp.gdb.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D6972c12631dc=
51de151b04fc31b0eaa91d3ccc05

commit 6972c12631dc51de151b04fc31b0eaa91d3ccc05
Author: Ijaz, Abdul B <[email protected]>
Date:   Fri Sep 15 15:18:07 2023 +0200

    gdb: add shadowed field in '-stack-list-locals/variables' mi commands
   =20
    For C/C++/Fortran languages GDB prints same name variable multiple time=
s in
    case of variable shadowing and it is confusing for user to identify whi=
ch
    variable belongs to the current scope.  So GDB now prints location info=
rmation
    for shadowed variables and add 'shadowed' field also in '-stack-list-lo=
cals'
    and '-stack-list-variables' mi commands for super-block shadowed variab=
le.
   =20
    Suppose we have test.c file
   =20
    1:int x =3D 3;
    2:  {
    3:    int x =3D 4;
    4:    int y =3D 5;
    5:    x =3D 99; /* break here */
    6:  }
   =20
    The "-stack-list-locals" and "-stack-list-variables" mi commands at the
    "break here" line gives the following output:
   =20
    Before the change:
   =20
    ~~~
    (gdb)
    -stack-list-locals 0
    ^done,locals=3D[name=3D"x",name=3D"y",name=3D"x"]
    (gdb)
    -stack-list-locals 1
    ^done,locals=3D[{name=3D"x",value=3D"4"},{name=3D"y",value=3D"5"},{name=
=3D"x",value=3D"3"}]
    (gdb)
    -stack-list-locals 2
    ^done,locals=3D[{name=3D"x",type=3D"int",value=3D"4"},{name=3D"y",type=
=3D"int",value=3D"5"},{name=3D"x",type=3D"int",value=3D"3"}]
    (gdb)
    -stack-list-variables 0
    ^done,variables=3D[{name=3D"x"},{name=3D"y"},{name=3D"x"}]
    (gdb)
    -stack-list-variables 1
    ^done,variables=3D[{name=3D"x",value=3D"4"},{name=3D"y",value=3D"5"},{n=
ame=3D"x",value=3D"3"}]
    (gdb)
    -stack-list-variables 2
    ^done,variables=3D[{name=3D"x",type=3D"int",value=3D"4"},{name=3D"y",ty=
pe=3D"int",value=3D"5"},{name=3D"x",type=3D"int",value=3D"3"}]
    ~~~
   =20
    With this patch we obtain:
   =20
    ~~~
    (gdb)
    -stack-list-locals 0
    ^done,locals=3D[name=3D"x",name=3D"y",name=3D"x"]
    (gdb)
    -stack-list-locals 1
    ^done,locals=3D[{name=3D"x",value=3D"4",filename=3D"../test.c",fullname=
=3D"/home/src/test.c",line=3D"3"},{name=3D"y",value=3D"5"},{name=3D"x",valu=
e=3D"3",filename=3D"../test.c",fullname=3D"/home/src/test.c",line=3D"1",sha=
dowed=3D"true"}]
    (gdb)
    -stack-list-locals 2
    ^done,locals=3D[{name=3D"x",type=3D"int",value=3D"4",filename=3D"../tes=
t.c",fullname=3D"/home/src/test.c",line=3D"3"},{name=3D"y",type=3D"int",val=
ue=3D"5"},{name=3D"x",type=3D"int",value=3D"3",filename=3D"../test.c",fulln=
ame=3D"/home/src/test.c",line=3D"1",shadowed=3D"true"}]
    (gdb)
    -stack-list-variables 0
    ^done,variables=3D[{name=3D"x",filename=3D"../test.c",fullname=3D"/home=
/src/test.c",line=3D"3"},{name=3D"y"},{name=3D"x",filename=3D"../test.c",fu=
llname=3D"/home/src/test.c",line=3D"1",shadowed=3D"true"}]
    (gdb)
    -stack-list-variables 1
    ^done,variables=3D[{name=3D"x",value=3D"4",filename=3D"../test.c",fulln=
ame=3D"/home/src/test.c",line=3D"3"},{name=3D"y",value=3D"5"},{name=3D"x",v=
alue=3D"3",filename=3D"../test.c",fullname=3D"/home/src/test.c",line=3D"1",=
shadowed=3D"true"}]
    (gdb)
    -stack-list-variables 2
    ^done,variables=3D[{name=3D"x",type=3D"int",value=3D"4",filename=3D"../=
test.c",fullname=3D"/home/src/test.c",line=3D"3"},{name=3D"y",type=3D"int",=
value=3D"5"},{name=3D"x",type=3D"int",value=3D"3",filename=3D"../test.c",fu=
llname=3D"/home/src/test.c",line=3D"1",shadowed=3D"true"}]
    ~~~
   =20
    Reviewed-By: Guinevere Larsen <[email protected]>
    Approved-By: Andrew Burgess <[email protected]>

Diff:
---
 gdb/NEWS                                  |   4 +
 gdb/doc/gdb.texinfo                       |  22 +++++
 gdb/mi/mi-cmd-stack.c                     | 142 +++++++++++++++++++++-----=
---
 gdb/testsuite/gdb.mi/mi-var-shadowing.c   |  50 +++++++++++
 gdb/testsuite/gdb.mi/mi-var-shadowing.exp | 144 ++++++++++++++++++++++++++=
++++
 5 files changed, 325 insertions(+), 37 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 5410acc8303..8f40ca5cb11 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -593,6 +593,10 @@ multi-wp-addr in qSupported
    multiple times, and the same mapping was being reused.  In all
    other cases, this field will have the value 'false'.
=20
+** GDB now shows the "shadowed", "filename", "fullname" and "line"
+   fields in the output of '-stack-list-locals/variables' mi
+   commands for variables that are shadowed, or which are shadowing.
+
 * Support for stabs debugging format and the a.out/dbx object format is
   deprecated, and will be removed in GDB 18.
=20
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index d2fbe61d8fc..0030698dcee 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -35585,6 +35585,28 @@ If the @code{--skip-unavailable} option is specifi=
ed, local variables
 and arguments that are not available are not listed.  Partially
 available arguments and local variables are still displayed, however.
=20
+@smallexample
+@group
+1: int x =3D 3;
+2: @{
+3:       int x =3D 4;
+4:       int y =3D 5;
+5:       x =3D 99; // breakpoint-line
+6: @}
+@end group
+@group
+(gdb) -stack-list-variables 2
+^done,variables=3D[@{name=3D"x",type=3D"int",value=3D"4",
+filename=3D"name.c",fullname=3D"/home/src/name.c",line=3D"3"@},
+@{name=3D"y",type=3D"int",value=3D"5"@},@{name=3D"x",type=3D"int",
+value=3D"3",filename=3D"name.c",fullname=3D"/home/src/name.c",
+line=3D"1",shadowed=3D"true"@}]
+@end group
+@end smallexample
+
+The location information and @samp{shadowed} attributes are only added
+when variable shadowing is detected (@pxref{shadowed variables}).
+
 @subsubheading Example
=20
 @smallexample
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
index 280a08d121e..37a470701af 100644
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -32,6 +32,8 @@
 #include "mi-parse.h"
 #include <optional>
 #include "inferior.h"
+#include "source.h"
+#include "gdbsupport/unordered_map.h"
=20
 enum what_to_list { locals, arguments, all };
=20
@@ -490,7 +492,9 @@ mi_cmd_stack_list_variables (const char *command, const=
 char *const *argv,
 static void
 list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
 		   enum print_values values, int skip_unavailable,
-		   const frame_print_options &fp_opts)
+		   const frame_print_options &fp_opts,
+		   const gdb::unordered_set<std::string> *shadowed_vars,
+		   gdb::unordered_set<std::string> &printed_vars)
 {
   struct ui_out *uiout =3D current_uiout;
=20
@@ -514,12 +518,25 @@ list_arg_or_local (const struct frame_arg *arg, enum =
what_to_list what,
 					     arg->val->type ()->length ()))))
     return;
=20
+  string_file stb;
+  const char *name =3D arg->sym->print_name ();
+  /* To distinguish innermost variable from the rest in the shadowed_vars
+     this boolean is needed.  */
+  bool already_printed =3D !printed_vars.insert (name).second;
+  bool shadowed =3D shadowed_vars->find (name) !=3D shadowed_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 (get_lang_vars_shadowing_option (current_language->la_language)
+      =3D=3D lang_vars_shadowing::HIDE && shadowed && already_printed)
+    return;
+
   std::optional<ui_out_emit_tuple> tuple_emitter;
   if (values !=3D PRINT_NO_VALUES || what =3D=3D all)
     tuple_emitter.emplace (uiout, nullptr);
=20
-  string_file stb;
-
   stb.puts (arg->sym->print_name ());
   if (arg->entry_kind =3D=3D print_entry_values_only)
     stb.puts ("@entry");
@@ -560,6 +577,67 @@ list_arg_or_local (const struct frame_arg *arg, enum w=
hat_to_list what,
 	}
       uiout->field_stream ("value", stb);
     }
+
+  /* Only for C/C++/Fortran/Ada languages, in case of variables shadowing
+     print shadowed field after the superblock variable and only location
+     of the variables in the innerblock.  */
+  if (get_lang_vars_shadowing_option (current_language->la_language)
+      =3D=3D lang_vars_shadowing::PRINT && shadowed
+      && !(values =3D=3D PRINT_NO_VALUES && what =3D=3D locals))
+    {
+      if (arg->sym->symtab () !=3D nullptr)
+	{
+	  symtab *symtab =3D arg->sym->symtab ();
+
+	  uiout->field_string ("filename",
+			       symtab_to_filename_for_display (symtab));
+	  uiout->field_string ("fullname", symtab_to_fullname (symtab));
+	  uiout->field_unsigned ("line", arg->sym->line ());
+	}
+
+      if (already_printed)
+	uiout->field_string ("shadowed", "true");
+    }
+}
+
+/* Returns true if address_class can be printed, otherwise returns false. =
 */
+
+static bool
+can_print_aclass (struct symbol *sym, enum what_to_list what)
+{
+  bool print_me =3D false;
+
+  switch (sym->loc_class ())
+    {
+    default:
+    case LOC_UNDEF:     /* catches errors        */
+    case LOC_CONST:     /* constant              */
+    case LOC_TYPEDEF:   /* local typedef         */
+    case LOC_LABEL:     /* local label           */
+    case LOC_BLOCK:     /* local function        */
+    case LOC_CONST_BYTES:       /* loc. byte seq.        */
+    case LOC_UNRESOLVED:        /* unresolved static     */
+    case LOC_OPTIMIZED_OUT:     /* optimized out         */
+      print_me =3D false;
+      break;
+
+    case LOC_ARG:       /* argument              */
+    case LOC_REF_ARG:   /* reference arg         */
+    case LOC_REGPARM_ADDR:      /* indirect register arg */
+    case LOC_LOCAL:     /* stack local           */
+    case LOC_STATIC:    /* static                */
+    case LOC_REGISTER:  /* register              */
+    case LOC_COMPUTED:  /* computed location     */
+      if (what =3D=3D all)
+	print_me =3D true;
+      else if (what =3D=3D locals)
+	print_me =3D !sym->is_argument ();
+      else
+	print_me =3D sym->is_argument ();
+      break;
+    }
+
+  return print_me;
 }
=20
 /* Print a list of the objects for the frame FI in a certain form,
@@ -573,9 +651,10 @@ list_args_or_locals (const frame_print_options &fp_opt=
s,
 		     enum what_to_list what, enum print_values values,
 		     const frame_info_ptr &fi, int skip_unavailable)
 {
-  const struct block *block;
+  const struct block *block, *orig_block;
   const char *name_of_result;
   struct ui_out *uiout =3D current_uiout;
+  gdb::unordered_set<std::string> collected_vars, shadowed_vars, printed_v=
ars;
=20
   block =3D get_frame_block (fi, 0);
=20
@@ -596,42 +675,31 @@ list_args_or_locals (const frame_print_options &fp_op=
ts,
=20
   ui_out_emit_list list_emitter (uiout, name_of_result);
=20
-  while (block !=3D 0)
+  orig_block =3D block;
+  /* Stored list of shadowed variables later help in identifying them
+     from the rest.  */
+  while (block !=3D nullptr)
     {
       for (struct symbol *sym : block_iterator_range (block))
 	{
-	  int print_me =3D 0;
-
-	  switch (sym->loc_class ())
+	  if (can_print_aclass (sym, what))
 	    {
-	    default:
-	    case LOC_UNDEF:	/* catches errors        */
-	    case LOC_CONST:	/* constant              */
-	    case LOC_TYPEDEF:	/* local typedef         */
-	    case LOC_LABEL:	/* local label           */
-	    case LOC_BLOCK:	/* local function        */
-	    case LOC_CONST_BYTES:	/* loc. byte seq.        */
-	    case LOC_UNRESOLVED:	/* unresolved static     */
-	    case LOC_OPTIMIZED_OUT:	/* optimized out         */
-	      print_me =3D 0;
-	      break;
-
-	    case LOC_ARG:	/* argument              */
-	    case LOC_REF_ARG:	/* reference arg         */
-	    case LOC_REGPARM_ADDR:	/* indirect register arg */
-	    case LOC_LOCAL:	/* stack local           */
-	    case LOC_STATIC:	/* static                */
-	    case LOC_REGISTER:	/* register              */
-	    case LOC_COMPUTED:	/* computed location     */
-	      if (what =3D=3D all)
-		print_me =3D 1;
-	      else if (what =3D=3D locals)
-		print_me =3D !sym->is_argument ();
-	      else
-		print_me =3D sym->is_argument ();
-	      break;
+	      const char *name =3D sym->print_name ();
+	      if (!collected_vars.insert (name).second)
+		shadowed_vars.insert (name);
 	    }
-	  if (print_me)
+	}
+      if (block->function ())
+	break;
+      block =3D block->superblock ();
+    }
+
+  block =3D orig_block;
+  while (block !=3D 0)
+    {
+      for (struct symbol *sym : block_iterator_range (block))
+	{
+	  if (can_print_aclass (sym, what))
 	    {
 	      struct frame_arg arg, entryarg;
=20
@@ -657,10 +725,10 @@ list_args_or_locals (const frame_print_options &fp_op=
ts,
=20
 	      if (arg.entry_kind !=3D print_entry_values_only)
 		list_arg_or_local (&arg, what, values, skip_unavailable,
-				   fp_opts);
+				   fp_opts, &shadowed_vars, printed_vars);
 	      if (entryarg.entry_kind !=3D print_entry_values_no)
 		list_arg_or_local (&entryarg, what, values, skip_unavailable,
-				   fp_opts);
+				   fp_opts, &shadowed_vars, printed_vars);
 	    }
 	}
=20
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 00000000000..875e753b485
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-shadowing.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 2023-2026 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>
+
+int
+shadowing (void)
+{
+  int a =3D 100;	/* entry bp */
+  unsigned int val1 =3D 1;		/* val1-d1 */
+  unsigned int val2 =3D 2;		/* val2-d1 */
+  a =3D 101;  /* bp for locals 1 */
+  {
+    unsigned int val2 =3D 3;		/* val2-d2 */
+    unsigned int val3 =3D 4;		/* val3-d1 */
+    a =3D 102;  /* bp for locals 2 */
+    {
+      unsigned int val1 =3D 5;		/* val1-d2 */
+      a =3D 103;  /* bp for locals 3 */
+      {
+	unsigned int val1 =3D 6;		/* val1-d3 */
+	unsigned int val2 =3D 7;		/* val2-d3 */
+	unsigned int val3 =3D 8;		/* val3-d2 */
+	a =3D 104;  /* bp for locals 4 */
+      }
+    }
+  }
+  a =3D 105;
+
+  return 0; /* 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 00000000000..3c0dbc2884c
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-shadowing.exp
@@ -0,0 +1,144 @@
+# Copyright 2023-2026 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=3Dmi"
+
+gdb_exit
+if [mi_gdb_start] {
+    continue
+}
+
+standard_testfile
+
+set opts {debug}
+if [build_executable ${testfile}.exp ${testfile} ${srcfile} $opts] {
+    return
+}
+
+mi_delete_breakpoints
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load ${binfile}
+mi_runto main
+
+set bp_line1 [gdb_get_line_number "bp for locals 1"]
+set bp_line2 [gdb_get_line_number "bp for locals 2"]
+set bp_line3 [gdb_get_line_number "bp for locals 3"]
+set bp_line4 [gdb_get_line_number "bp for locals 4"]
+set bp_line5 [gdb_get_line_number "bp for locals 5"]
+
+set val1_d1 [gdb_get_line_number "val1-d1"]
+set val1_d2 [gdb_get_line_number "val1-d2"]
+set val1_d3 [gdb_get_line_number "val1-d3"]
+set val2_d1 [gdb_get_line_number "val2-d1"]
+set val2_d2 [gdb_get_line_number "val2-d2"]
+set val2_d3 [gdb_get_line_number "val2-d3"]
+set val3_d1 [gdb_get_line_number "val3-d1"]
+set val3_d2 [gdb_get_line_number "val3-d2"]
+set a_line [gdb_get_line_number "entry bp"]
+
+set fullname "${fullname_syntax}$srcfile"
+set filename "\[^\r\n\]+$srcfile"
+
+set stack_test1_regx "\\^done,(locals|variables)=3D\\\[\{name=3D\"a\",type=
=3D\"int\",value=3D\"$decimal\"\},\{name=3D\"val1\",type=3D\"unsigned int\"=
,value=3D\"1\"\},{name=3D\"val2\",type=3D\"unsigned int\",value=3D\"2\"\}\\=
\]"
+set stack_test2_regx "\\^done,(locals|variables)=3D\\\[\{name=3D\"val2\",t=
ype=3D\"unsigned int\",value=3D\"3\",filename=3D\"$filename\",fullname=3D\"=
$fullname\",line=3D\"$val2_d2\"\},\{name=3D\"val3\",type=3D\"unsigned int\"=
,value=3D\"4\"\},\{name=3D\"a\",type=3D\"int\",value=3D\"101\"\},\{name=3D\=
"val1\",type=3D\"unsigned int\",value=3D\"1\"\},\{name=3D\"val2\",type=3D\"=
unsigned int\",value=3D\"2\",filename=3D\"$filename\",fullname=3D\"$fullnam=
e\",line=3D\"$val2_d1\",shadowed=3D\"true\"\}\\\]"
+set stack_test3_regx "\\^done,(locals|variables)=3D\\\[\{name=3D\"val1\",t=
ype=3D\"unsigned int\",value=3D\"5\",filename=3D\"$filename\",fullname=3D\"=
$fullname\",line=3D\"$val1_d2\"\},\{name=3D\"val2\",type=3D\"unsigned int\"=
,value=3D\"3\",filename=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$=
val2_d2\"\},\{name=3D\"val3\",type=3D\"unsigned int\",value=3D\"4\"\},\{nam=
e=3D\"a\",type=3D\"int\",value=3D\"102\"\},\{name=3D\"val1\",type=3D\"unsig=
ned int\",value=3D\"1\",filename=3D\"$filename\",fullname=3D\"$fullname\",l=
ine=3D\"$val1_d1\",shadowed=3D\"true\"\},\{name=3D\"val2\",type=3D\"unsigne=
d int\",value=3D\"2\",filename=3D\"$filename\",fullname=3D\"$fullname\",lin=
e=3D\"$val2_d1\",shadowed=3D\"true\"\}\\\]"
+set stack_test4_regx "\\^done,(locals|variables)=3D\\\[\{name=3D\"val1\",t=
ype=3D\"unsigned int\",value=3D\"6\",filename=3D\"$filename\",fullname=3D\"=
$fullname\",line=3D\"$val1_d3\"\},\{name=3D\"val2\",type=3D\"unsigned int\"=
,value=3D\"7\",filename=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$=
val2_d3\"\},\{name=3D\"val3\",type=3D\"unsigned int\",value=3D\"8\",filenam=
e=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$val3_d2\"\},\{name=3D\=
"val1\",type=3D\"unsigned int\",value=3D\"5\",filename=3D\"$filename\",full=
name=3D\"$fullname\",line=3D\"$val1_d2\",shadowed=3D\"true\"\},\{name=3D\"v=
al2\",type=3D\"unsigned int\",value=3D\"3\",filename=3D\"$filename\",fullna=
me=3D\"$fullname\",line=3D\"$val2_d2\",shadowed=3D\"true\"\},\{name=3D\"val=
3\",type=3D\"unsigned int\",value=3D\"4\",filename=3D\"$filename\",fullname=
=3D\"$fullname\",line=3D\"$val3_d1\",shadowed=3D\"true\"\},\{name=3D\"a\",t=
ype=3D\"int\",value=3D\"103\"\},\{name=3D\"val1\",type=3D\"unsigned int\",v=
alue=3D\"1\",filename=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$va=
l1_d1\",shadowed=3D\"true\"\},\{name=3D\"val2\",type=3D\"unsigned int\",val=
ue=3D\"2\",filename=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$val2=
_d1\",shadowed=3D\"true\"\}\\\]"
+set stack_test5_regx "\\^done,(locals|variables)=3D\\\[\{name=3D\"a\",type=
=3D\"int\",value=3D\"105\"\},\{name=3D\"val1\",type=3D\"unsigned int\",valu=
e=3D\"1\"\},\{name=3D\"val2\",type=3D\"unsigned int\",value=3D\"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=3D\"keep\"" } "continue to outermost level"
+mi_gdb_test "-stack-list-locals 0" \
+    "\\^done,locals=3D\\\[name=3D\"a\",name=3D\"val1\",name=3D\"val2\"\\\]=
" \
+    "-stack-list-locals 0 at outermost level"
+mi_gdb_test "-stack-list-variables 0" \
+    "\\^done,variables=3D\\\[{name=3D\"a\"},{name=3D\"val1\"},{name=3D\"va=
l2\"}\\\]" \
+    "-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=3D\"keep\"" } "continue to first level"
+mi_gdb_test "-stack-list-locals 0"  \
+    "\\^done,locals=3D\\\[name=3D\"val2\",name=3D\"val3\",name=3D\"a\",nam=
e=3D\"val1\",name=3D\"val2\"\\\]"  \
+    "-stack-list-locals 0 at first level"
+mi_gdb_test "-stack-list-variables 0" \
+    "\\^done,variables=3D\\\[{name=3D\"val2\",filename=3D\"$filename\",ful=
lname=3D\"$fullname\",line=3D\"$val2_d2\"},{name=3D\"val3\"},{name=3D\"a\"}=
,{name=3D\"val1\"},{name=3D\"val2\",filename=3D\"$filename\",fullname=3D\"$=
fullname\",line=3D\"$val2_d1\",shadowed=3D\"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=3D\"keep\"" } "continue to second level"
+mi_gdb_test "-stack-list-locals 0"  \
+     "\\^done,locals=3D\\\[name=3D\"val1\",name=3D\"val2\",name=3D\"val3\"=
,name=3D\"a\",name=3D\"val1\",name=3D\"val2\"\\\]"  \
+    "-stack-list-locals 0 at second level"
+mi_gdb_test "-stack-list-variables 0"  \
+     "\\^done,variables=3D\\\[{name=3D\"val1\",filename=3D\"$filename\",fu=
llname=3D\"$fullname\",line=3D\"$val1_d2\"},{name=3D\"val2\",filename=3D\"$=
filename\",fullname=3D\"$fullname\",line=3D\"$val2_d2\"},{name=3D\"val3\"},=
{name=3D\"a\"},{name=3D\"val1\",filename=3D\"$filename\",fullname=3D\"$full=
name\",line=3D\"$val1_d1\",shadowed=3D\"true\"\},{name=3D\"val2\",filename=
=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$val2_d1\",shadowed=3D\"=
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=3D\"keep\"" } "continue to third level"
+mi_gdb_test "-stack-list-locals 0"  \
+    "\\^done,locals=3D\\\[name=3D\"val1\",name=3D\"val2\",name=3D\"val3\",=
name=3D\"val1\",name=3D\"val2\",name=3D\"val3\",name=3D\"a\",name=3D\"val1\=
",name=3D\"val2\"\\\]"  \
+    "-stack-list-locals 0 at third level"
+mi_gdb_test "-stack-list-variables 0" \
+    "\\^done,variables=3D\\\[{name=3D\"val1\",filename=3D\"$filename\",ful=
lname=3D\"$fullname\",line=3D\"$val1_d3\"},{name=3D\"val2\",filename=3D\"$f=
ilename\",fullname=3D\"$fullname\",line=3D\"$val2_d3\"},{name=3D\"val3\",fi=
lename=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$val3_d2\"},{name=
=3D\"val1\",filename=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$val=
1_d2\",shadowed=3D\"true\"\},\{name=3D\"val2\",filename=3D\"$filename\",ful=
lname=3D\"$fullname\",line=3D\"$val2_d2\",shadowed=3D\"true\"\},\{name=3D\"=
val3\",filename=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$val3_d1\=
",shadowed=3D\"true\"\},{name=3D\"a\"},{name=3D\"val1\",filename=3D\"$filen=
ame\",fullname=3D\"$fullname\",line=3D\"$val1_d1\",shadowed=3D\"true\"\},{n=
ame=3D\"val2\",filename=3D\"$filename\",fullname=3D\"$fullname\",line=3D\"$=
val2_d1\",shadowed=3D\"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=3D\"keep\"" } "continue to outermost level last"
+mi_gdb_test "-stack-list-locals 0"  \
+    "\\^done,locals=3D\\\[name=3D\"a\",name=3D\"val1\",name=3D\"val2\"\\\]=
"  \
+    "-stack-list-locals 0 at outermost level last"
+mi_gdb_test "-stack-list-variables 0"  \
+    "\\^done,variables=3D\\\[{name=3D\"a\"},{name=3D\"val1\"},{name=3D\"va=
l2\"}\\\]"  \
+    "-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"