@@ -8833,6 +8833,21 @@ 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
+
+A variable is shadowed when there's another variable by the same
+name which is declared within an inner scope (decision block,
+method, or inner class). For such cases, its location for the
+outermost scope is followed by @samp{shadowed}.
+
@item info locals [-q] [-t @var{type_regexp}] [@var{regexp}]
Like @kbd{info locals}, but only print the local variables selected
with the provided regexp(s).
@@ -56,6 +56,7 @@
#include "gdbsupport/gdb-safe-ctype.h"
#include "gdbsupport/rsp-low.h"
#include "inferior.h"
+#include "include/libiberty.h"
/* Chain containing all defined memory-tag subcommands. */
@@ -2331,7 +2332,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)
@@ -2344,6 +2346,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
@@ -2353,6 +2356,12 @@ print_variable_and_value (const char *name, struct symbol *var,
get_user_print_options (&opts);
opts.deref_ref = true;
common_val_print_checked (val, stream, indent, &opts, current_language);
+
+ if (shadowed)
+ /* Print location and shadowed variable information. */
+ fprintf_styled (stream, metadata_style.style (),
+ _("\t<%s:%d%s>"), file_name,
+ var->line (), printed ? ", shadowed" : "");
}
catch (const gdb_exception_error &except)
{
@@ -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;
@@ -2476,7 +2526,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);
}
}
}
@@ -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,
new file mode 100644
@@ -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"
new file mode 100644
@@ -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;
new file mode 100755
@@ -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;
+}
new file mode 100755
@@ -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"
new file mode 100644
@@ -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;
new file mode 100755
@@ -0,0 +1,34 @@
+# 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
+}
+
+# Wrong local values are shown for rustc version >= 1.73.
+setup_xfail "*-*-*" "gdb/31079"
+gdb_test "info local _x" "_x = 12" "print local _x variable"
new file mode 100755
@@ -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
+}
@@ -1047,7 +1047,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);
@@ -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);