commands that we, as developers, believe would be close to a minimal
set of commands for a new user of GDB.
+info locals
+ GDB now shows the "shadowed" annotation and the location information
+ for variables that are shadowed, or which are shadowing.
+
* Removed commands
target ctf
if (sym->loc_class () == LOC_TYPEDEF)
c_print_type (sym->type (), "", stream, -1, 0, language, flags);
else
- print_variable_value (sym, {}, stream, 0, language_def (language));
+ print_variable_value (sym, {}, stream, 0, language_def (language),
+ var_shadowing::NONE);
}
gdb_puts (_("] "), stream);
printing header information and messages explaining why no local variables
have been printed.
+@smallexample
+@group
+1: int x = 3;
+2: @{
+3: int x = 4;
+4: int y = 52;
+5: x = 99; // breakpoint-line
+6: @}
+@end group
+@group
+(gdb) info locals
+x = 4 <file.c:3>
+y = 52
+x = 3 <file.c:1, shadowed>
+@end group
+@end smallexample
+
+@anchor{shadowed variables}
+@cindex shadowed variables
+A variable is @dfn{shadowed} when there's another variable with the
+same name which is declared within an inner scope (decision block,
+method, or inner class). When shadowing is detected, location
+information is added to all instances of the shadowed variable name.
+The outermost instances are additionally followed by @samp{shadowed}
+to indicate that they are not the active variable.
+
@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).
return sym;
}
+/* See language.h. */
+
+lang_vars_shadowing get_lang_vars_shadowing_option (enum language lang)
+{
+ switch (lang)
+ {
+ case language_c:
+ case language_cplus:
+ case language_fortran:
+ case language_ada:
+ return lang_vars_shadowing::PRINT;
+
+ case language_rust:
+ return lang_vars_shadowing::HIDE;
+
+ default:
+ return lang_vars_shadowing::NONE;
+ }
+}
+
/* Initialize the language routines. */
INIT_GDB_FILE (language)
macro_expansion_no, macro_expansion_c
};
+/* How should shadowed, or shadowing, variables be printed. */
+
+enum class lang_vars_shadowing
+ {
+ /* Adds shadowed information for such variables. */
+ PRINT,
+
+ /* Does not print shadowed variables. */
+ HIDE,
+
+ /* Print variables without shadow information. */
+ NONE,
+ };
+
\f
/* Per architecture (OS/ABI) language information. */
symbol_name_matcher_ftype *get_symbol_name_matcher
(const language_defn *lang, const lookup_name_info &lookup_name);
+/* Returns the shadowing option supported for the input language. */
+
+extern lang_vars_shadowing get_lang_vars_shadowing_option (enum language lang);
+
/* Save the current language and restore it upon destruction. */
class scoped_restore_current_language
void
print_variable_value (symbol *var, const frame_info_ptr &frame,
ui_file *stream, int indent,
- const language_defn *language)
+ const language_defn *language,
+ var_shadowing shadow_status)
{
try
{
get_user_print_options (&opts);
opts.deref_ref = true;
common_val_print_checked (val, stream, indent, &opts, language);
+
+ /* Print <%line, shadowed> after the variable value only when it is
+ variable shadowing case. */
+ if (shadow_status != var_shadowing::NONE)
+ {
+ /* Use lbasename instead of symtab_to_filename_for_display as the
+ latter defaults to relative path while basename is preferred
+ here. */
+ const char *file_name = (var->symtab () != nullptr
+ && var->symtab ()->filename () != nullptr)
+ ? lbasename (var->symtab ()->filename ())
+ : "??";
+ bool printed = (shadow_status == var_shadowing::SHADOWED);
+ string_file out (current_uiout->can_emit_style_escape ());
+
+ gdb_printf (&out, "\t<%ps:",
+ styled_string (file_name_style.style (), file_name));
+
+ if (var->line () > 0)
+ gdb_printf (&out, "%ps",
+ styled_string (line_number_style.style (),
+ pulongest (var->line ())));
+ else
+ gdb_puts ("No line number information available", &out);
+
+ if (printed)
+ {
+ gdb_puts (", ", &out);
+ fputs_styled ("shadowed", metadata_style.style (), &out);
+ }
+
+ gdb_puts (">", &out);
+
+ gdb_puts (out.c_str (), stream);
+ }
}
catch (const gdb_exception_error &except)
{
void
print_variable_and_value (const char *name, symbol *var,
const frame_info_ptr &frame,
- ui_file *stream, int indent)
+ ui_file *stream, int indent,
+ var_shadowing shadow_status)
{
if (name == nullptr)
name = var->print_name ();
gdb_printf (stream, "%*s%ps = ", 2 * indent, "",
styled_string (variable_name_style.style (), name));
- print_variable_value (var, frame, stream, indent, current_language);
+ print_variable_value (var, frame, stream, indent, current_language,
+ shadow_status);
gdb_printf (stream, "\n");
}
#include "cli/cli-option.h"
#include "cli/cli-style.h"
#include "gdbsupport/buildargv.h"
+#include "gdbsupport/unordered_set.h"
/* The possible choices of "set print frame-arguments", and the value
of this setting. */
/* Iterate over the local variables of a block B, calling CB. */
static void
-iterate_over_block_locals (const struct block *b,
- iterate_over_block_arg_local_vars_cb cb)
+iterate_over_block_locals
+ (const struct block *b,
+ gdb::function_view <void (const char *, struct symbol *)> cb)
{
for (struct symbol *sym : block_iterator_range (b))
{
}
}
+/* See stack.h. */
+
+void
+iterate_over_block_local_vars_printing
+ (const struct block *block,
+ iterate_over_block_arg_local_vars_cb_printing cb)
+{
+ gdb::unordered_set<std::string> collected_vars, shadowed_vars, printed_vars;
+
+ /* Phase one: iterate over all locals within the block, and every parent
+ block up to the enclosing function block. Record all of the locals
+ seen, this allows us to know which locals are shadowing locals from a
+ more outer scope. */
+ iterate_over_block_local_vars
+ (block, [&] (const char *print_name, struct symbol *sym)
+ {
+ if (!sym->is_argument ())
+ {
+ if (!collected_vars.insert (print_name).second)
+ shadowed_vars.insert (print_name);
+ }
+ });
+
+ /* Phase two: iterate over all locals within the block, and every parent
+ block up to the enclosing function block. Print all the locals seen
+ by calling CB. Depending on the current language we vary the
+ arguments to CB to indicate shadowing. Or in some cases, we don't
+ print the local at all. */
+ iterate_over_block_local_vars
+ (block, [&] (const char *print_name, struct symbol *sym)
+ {
+ bool already_printed = !printed_vars.insert (print_name).second;
+ bool shadowed = shadowed_vars.find (print_name) != shadowed_vars.end ();
+
+ enum var_shadowing shadowing_status;
+ if (already_printed && shadowed)
+ shadowing_status = var_shadowing::SHADOWED;
+ else if (!already_printed && shadowed)
+ shadowing_status = var_shadowing::SHADOWING;
+ else
+ shadowing_status = var_shadowing::NONE;
+
+ /* 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 (get_lang_vars_shadowing_option (current_language->la_language)
+ == lang_vars_shadowing::PRINT
+ && shadowing_status != var_shadowing::NONE)
+ cb (print_name, sym, shadowing_status);
+ /* In case of Rust language it is possible to declare variable with
+ same name multiple times and only innermost instance of variable
+ is accessible. So print only the innermost instance and there is
+ no need of printing duplicates. */
+ else if (get_lang_vars_shadowing_option (current_language->la_language)
+ == lang_vars_shadowing::HIDE
+ && shadowing_status == var_shadowing::SHADOWED)
+ {
+ /* Nothing. */
+ }
+ else
+ cb (print_name, sym, var_shadowing::NONE);
+ });
+}
+
/* Data to be passed around in the calls to the locals and args
iterators. */
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,
+ var_shadowing shadow_status);
};
/* 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,
+ var_shadowing shadow_status)
{
frame_info_ptr frame;
return;
}
- print_variable_and_value (print_name, sym, frame, stream, num_tabs);
+ print_variable_and_value (print_name, sym, frame, stream, num_tabs,
+ shadow_status);
values_printed = 1;
}
scoped_restore_selected_frame restore_selected_frame;
select_frame (frame);
- iterate_over_block_local_vars (block, cb_data);
+ iterate_over_block_local_vars_printing (block, cb_data);
if (!cb_data.values_printed && !quiet)
{
}
}
+/* See stack.h. */
+
+void
+iterate_over_block_arg_vars_printing
+ (const struct block *b,
+ iterate_over_block_arg_local_vars_cb_printing cb)
+{
+ for (struct symbol *sym : block_iterator_range (b))
+ {
+ /* Don't worry about things which aren't arguments. */
+ if (sym->is_argument ())
+ {
+ /* We have to look up the symbol because arguments can have
+ two entries (one a parameter, one a local) and the one we
+ want is the local, which lookup_symbol will find for us.
+ This includes gcc1 (not gcc2) on the sparc when passing a
+ small structure and gcc2 when the argument type is float
+ and it is passed as a double and converted to float by
+ the prologue (in the latter case the type of the LOC_ARG
+ symbol is double and the type of the LOC_LOCAL symbol is
+ float). There are also LOC_ARG/LOC_REGISTER pairs which
+ are not combined in symbol-reading. */
+
+ struct symbol *sym2
+ = lookup_symbol_search_name (sym->search_name (),
+ b, SEARCH_VAR_DOMAIN).symbol;
+ cb (sym->print_name (), sym2, var_shadowing::NONE);
+ }
+ }
+}
+
/* Print all argument variables of the function of FRAME.
Print them with values to STREAM.
If REGEXP is not NULL, only print argument variables whose name
cb_data.stream = stream;
cb_data.values_printed = 0;
- iterate_over_block_arg_vars (func->value_block (), cb_data);
+ iterate_over_block_arg_vars_printing (func->value_block (), cb_data);
if (!cb_data.values_printed && !quiet)
{
#ifndef GDB_STACK_H
#define GDB_STACK_H
+enum class var_shadowing;
+
gdb::unique_xmalloc_ptr<char> find_frame_funname (const frame_info_ptr &frame,
enum language *funlang,
struct symbol **funcp);
using iterate_over_block_arg_local_vars_cb
= gdb::function_view<void (const char *print_name, struct symbol *sym)>;
+using iterate_over_block_arg_local_vars_cb_printing
+ = gdb::function_view<void (const char *print_name, struct symbol *sym,
+ var_shadowing shadow_status)>;
+
void iterate_over_block_arg_vars (const struct block *block,
iterate_over_block_arg_local_vars_cb cb);
void iterate_over_block_local_vars (const struct block *block,
iterate_over_block_arg_local_vars_cb cb);
+/* Iterate over all the argument variables in block B, call CB for
+ each variable with its print name, symbol, and shadowing status. */
+
+void iterate_over_block_arg_vars_printing
+ (const struct block *block,
+ iterate_over_block_arg_local_vars_cb_printing cb);
+
+/* Iterate over all the local variables in block B, including all its
+ superblocks, stopping when the top-level block is reached. Call CB
+ for each variable with its print name, symbol, and shadowing status
+ relative to inner blocks already visited. */
+
+void iterate_over_block_local_vars_printing
+ (const struct block *block,
+ iterate_over_block_arg_local_vars_cb_printing cb);
+
/* Initialize *WHAT to be a copy of the user desired print what frame info.
If !WHAT.has_value (), the printing function chooses a default set of
information to print, otherwise the printing function should print
--- /dev/null
+# 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 "ada.exp"
+
+require allow_ada_tests
+
+standard_ada_testfile var_shadowing
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" \
+ executable [list debug]] != "" } {
+ return
+}
+
+clean_restart ${testfile}
+
+set i_level1 [gdb_get_line_number "I-Level1"]
+set i_level2 [gdb_get_line_number "I-Level2"]
+set i_level3 [gdb_get_line_number "I-Level3"]
+set bp_location [gdb_get_line_number "BREAK"]
+runto "var_shadowing.adb:$bp_location"
+
+gdb_test "info locals" [multi_line \
+ "i = 111\t<$testfile.adb:$i_level3>" \
+ "i = 11\t<$testfile.adb:$i_level2, shadowed>" \
+ "i = 1\t<$testfile.adb:$i_level1, shadowed>" \
+] "info locals at innermost level"
--- /dev/null
+-- 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/>.
+
+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;
--- /dev/null
+/* 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 = 100; /* bp for entry */
+ unsigned int val1 = 1; /* val1-d1 */
+ unsigned int val2 = 2; /* val2-d1 */
+ a = 101; /* bp for locals 1 */
+ {
+ unsigned int val2 = 3; /* val2-d2 */
+ unsigned int val3 = 4; /* val3-d1 */
+ a = 102; /* bp for locals 2 */
+ {
+ unsigned int val1 = 5; /* val1-d2 */
+ a = 103; /* bp for locals 3 */
+ {
+ #include "var-shadowing2.c"
+ unsigned int val1 = 6; /* val1-d3 */
+ unsigned int val2 = 7; /* val2-d3 */
+ unsigned int val3 = 8; /* val3-d2 */
+ a = 104; /* bp for locals 4 */
+ }
+ }
+ }
+ a = 105;
+
+ return 0; /* bp for locals 5 */
+}
+
+int
+main (void)
+{
+ shadowing ();
+ return 0;
+}
--- /dev/null
+# 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/>.
+
+standard_testfile
+if [prepare_for_testing "failed to prepare" $testfile $srcfile] {
+ return
+}
+
+if ![runto_main] {
+ return
+}
+
+set bp_line1 [gdb_get_line_number "bp for locals 1"]
+set bp_line2 [gdb_get_line_number "bp for locals 2"]
+set bp_line3 [gdb_get_line_number "bp for locals 3"]
+set bp_line4 [gdb_get_line_number "bp for locals 4"]
+set bp_line5 [gdb_get_line_number "bp for locals 5"]
+
+set val1_d1 [gdb_get_line_number "val1-d1"]
+set val1_d2 [gdb_get_line_number "val1-d2"]
+set val1_d3 [gdb_get_line_number "val1-d3"]
+set val2_d1 [gdb_get_line_number "val2-d1"]
+set val2_d2 [gdb_get_line_number "val2-d2"]
+set val2_d3 [gdb_get_line_number "val2-d3"]
+set val3_d1 [gdb_get_line_number "val3-d1"]
+set val3_d2 [gdb_get_line_number "val3-d2"]
+set a_line [gdb_get_line_number "bp for entry"]
+
+gdb_breakpoint $srcfile:$bp_line1
+gdb_continue_to_breakpoint "continue to outermost level" \
+ ".*$srcfile:$bp_line1.*"
+gdb_test "info locals" [multi_line \
+ "val1 = 1" \
+ "val2 = 2" \
+ ] "info locals at outermost level"
+
+gdb_breakpoint $srcfile:$bp_line2
+gdb_continue_to_breakpoint "continue to first level" ".*$srcfile:$bp_line2.*"
+gdb_test "info locals" [multi_line \
+ "val2 = 3\t<$srcfile:$val2_d2>" \
+ "val3 = 4" \
+ "a = 101" \
+ "val1 = 1" \
+ "val2 = 2\t<$srcfile:$val2_d1, shadowed>" \
+ ] "info locals first level"
+
+gdb_breakpoint $srcfile:$bp_line3
+gdb_continue_to_breakpoint "continue to second level" ".*$srcfile:$bp_line3.*"
+gdb_test "info locals" [multi_line \
+ "val1 = 5\t<$srcfile:$val1_d2>" \
+ "val2 = 3\t<$srcfile:$val2_d2>" \
+ "val3 = 4" \
+ "a = 102" \
+ "val1 = 1\t<$srcfile:$val1_d1, shadowed>" \
+ "val2 = 2\t<$srcfile:$val2_d1, shadowed>" \
+ ] "info locals second level"
+
+gdb_breakpoint $srcfile:$bp_line4
+gdb_continue_to_breakpoint "continue to innermost level" ".*$srcfile:$bp_line4.*"
+gdb_test "info locals" [multi_line \
+ "a = 999\t<${testfile}2.c:16>" \
+ "val1 = 6\t<$srcfile:$val1_d3>" \
+ "val2 = 7\t<$srcfile:$val2_d3>" \
+ "val3 = 8\t<$srcfile:$val3_d2>" \
+ "val1 = 5\t<$srcfile:$val1_d2, shadowed>" \
+ "val2 = 3\t<$srcfile:$val2_d2, shadowed>" \
+ "val3 = 4\t<$srcfile:$val3_d1, shadowed>" \
+ "a = 103\t<$srcfile:$a_line, shadowed>" \
+ "val1 = 1\t<$srcfile:$val1_d1, shadowed>" \
+ "val2 = 2\t<$srcfile:$val2_d1, shadowed>" \
+ ] "info locals at innermost level"
+
+gdb_breakpoint $srcfile:$bp_line5
+gdb_continue_to_breakpoint "continue to outermost level last" \
+ ".*$srcfile:$bp_line5.*"
+gdb_test "info locals" [multi_line \
+ "a = 105" \
+ "val1 = 1" \
+ "val2 = 2" \
+ ] "info locals at outermost level last"
--- /dev/null
+/* 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/>. */
+
+int a = 999;
"backtrace from bar 2"
gdb_test "up" "#1 .*func1 .* at .*" "up from bar 2"
gdb_test "info frame" ".*inlined into frame.*" "func1 inlined 2"
- set pass_re "array = \\{0 <repeats 64 times>\\}"
+ set shadowed_pass_re "\t<$srcfile:$decimal>"
+ set shadowed_fail_re "\t<$srcfile:$decimal, shadowed>"
+ set pass_re "array = \\{0 <repeats 64 times>\\}($shadowed_pass_re)?"
set kfail_re [multi_line $pass_re \
- "array = <optimized out>"]
+ "array = <optimized out>$shadowed_fail_re"]
gdb_test_multiple "info locals" "info locals above bar 2" {
-re -wrap $pass_re {
pass $gdb_test_name
"backtrace from bar 3"
gdb_test "up" "#1 .*func1 .* at .*" "up from bar 3"
gdb_test "info frame" ".*inlined into frame.*" "func1 inlined 3"
- set pass_re "array = {$decimal, \[^\r\n\]*}"
+ set pass_re "array = {$decimal, \[^\r\n\]*}($shadowed_pass_re)?"
set kfail_re [multi_line $pass_re \
- "array = <optimized out>"]
+ "array = <optimized out>$shadowed_fail_re"]
gdb_test_multiple "info locals" "info locals above bar 3" {
-re -wrap $pass_re {
pass $gdb_test_name
gdb_breakpoint $srcfile:$locals_bp
gdb_continue_to_breakpoint "$bp_label" ".*$srcfile:$locals_bp.*"
- set kfail_re [multi_line $pass_re ".*<optimized out>"]
+ set kfail_re [multi_line $pass_re \
+ ".*<optimized out>(.*<$srcfile:$::decimal, shadowed>)?"]
gdb_test_multiple "info locals" "scoped info locals at $bp_label" {
-re -wrap $pass_re {
pass $gdb_test_name
}
if {! $no_frames } {
- check_scoped_locals "bp for locals 1" "loc2 = 20\r\nloc1 = 10"
- check_scoped_locals "bp for locals 2" "loc3 = 30\r\nloc2 = 20\r\nloc1 = 10"
- check_scoped_locals "bp for locals 3" "loc1 = 10"
+ check_scoped_locals "bp for locals 1" \
+ "loc2 = 20(\t<$srcfile:$decimal>)?\r\nloc1 = 10(\t<$srcfile:$decimal>)?"
+ check_scoped_locals "bp for locals 2" \
+ "loc3 = 30(\t<$srcfile:$decimal>)?\r\nloc2 = 20(\t<$srcfile:$decimal>)?\r\nloc1 = 10(\t<$srcfile:$decimal>)?"
+ check_scoped_locals "bp for locals 3" "loc1 = 10(\t<$srcfile:$decimal>)?"
}
--- /dev/null
+# 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 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
+}
+
+set line [gdb_get_line_number "set breakpoint here"]
+if {![runto ${srcfile}:$line]} {
+ untested "could not run to breakpoint"
+ return
+}
+
+# Wrong local values are shown for rustc version >= 1.73.
+if {[rust_at_least 1.73]} {
+ setup_xfail "*-*-*" "gdb/31079"
+}
+gdb_test "info local _x" "_x = 12" "print local _x variable"
--- /dev/null
+// 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/>.
+
+fn main() {
+ let _x = 5;
+ let _x = _x + 7;
+ let _y = 8; // set breakpoint here
+}
struct ui_file *stream,
const struct value_print_options *options);
+/* Track the shadowing status of a variable. */
+enum class var_shadowing
+{
+ /* This variable is not shadowed, and not shadowing. */
+ NONE,
+
+ /* This variable is shadowed by a later one. */
+ SHADOWED,
+
+ /* This variable is shadowing an earlier one, and is not itself
+ shadowed. */
+ SHADOWING
+};
+
/* Print the value in stack frame FRAME of a variable specified by a
struct symbol. STREAM is the ui_file on which to print the value.
INDENT specifies the number of indent levels to print before
printing the variable name. LANGUAGE is the language to use for
- printing. */
+ printing. SHADOW_STATUS specifies the variable shadowing
+ information. */
extern void print_variable_value (symbol *var,
const frame_info_ptr &frame,
ui_file *stream, int indent,
- const language_defn *language);
+ const language_defn *language,
+ var_shadowing shadow_status);
/* Print the value in stack frame FRAME of a variable specified by a
struct symbol. NAME is the name to print; if NULL then VAR's print
name will be used. STREAM is the ui_file on which to print the
value. INDENT specifies the number of indent levels to print
- before printing the variable name. */
+ before printing the variable name. SHADOW_STATUS specifies the
+ variable shadowing information. */
extern void print_variable_and_value (const char *name,
symbol *var,
const frame_info_ptr &frame,
ui_file *stream,
- int indent);
+ int indent,
+ var_shadowing shadow_status);
extern void typedef_print (struct type *type, struct symbol *news,
struct ui_file *stream);