]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Implement local-environment commands
authorTom Tromey <tromey@adacore.com>
Wed, 11 Dec 2024 18:33:12 +0000 (11:33 -0700)
committerTom Tromey <tromey@adacore.com>
Tue, 9 Dec 2025 18:48:45 +0000 (11:48 -0700)
A user noted that "set environment" does not affect things like
"shell" or "pipe".  This makes some sense, because the environment is
per-inferior, and also in the general case it may be affecting a
remote machine -- i.e., the settings may not be locally appropriate.

This patch adds a new set of "local-environment" commands (set, show,
and unset) that affect gdb's own environment.

Approved-By: Andrew Burgess <aburgess@redhat.com>
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-by: Kévin Le Gouguec <legouguec@adacore.com>
gdb/NEWS
gdb/doc/gdb.texinfo
gdb/infcmd.c
gdb/testsuite/gdb.base/local-env.exp [new file with mode: 0644]

index 91fae409aba307877cc607d47850adc59ec05752..381536cc5f97eb8478ee632633e1abbc35c67b77 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -58,6 +58,13 @@ GNU/Linux/MicroBlaze (gdbserver) microblazeel-*linux*
 
 * New commands
 
+set local-environment
+show local-environment
+unset local-environment
+  Analogs of the existing "environment" commands that affect GDB's own
+  environment.  The local environment is used by "shell", "pipe", and
+  other commands that launch a subprocess other than an inferior.
+
 maintenance test-remote-args ARGS
   Test splitting and joining of inferior arguments ARGS as they would
   be split and joined when being passed to a remote target.
index e4469227a9ed57860efe8ebdbd42033795c5b21e..bd5d0250483515aa56d27744a955c0cedcb0d4eb 100644 (file)
@@ -29585,6 +29585,32 @@ Continuing.
 
 Suppressing CLI notifications may be useful in scripts to obtain a
 reduced output from a list of commands.
+
+@kindex show local-environment
+@item show local-environment @r{[}@var{varname}@r{]}
+Print the value of the local environment variable @var{varname}.  If
+you do not supply @var{varname}, print the names and values of all
+local environment variables.  A local environment variable is used
+when @value{GDBN} executes a local command, such as by the
+@code{shell} command.
+
+@kindex set local-environment
+@anchor{set local-environment}
+@item set local-environment @var{varname} @r{[}=@var{value}@r{]}
+Set environment variable @var{varname} to @var{value}.  The value
+changes for @value{GDBN} itself.  The @var{value} may be any string;
+the values of environment variables are just strings, and any
+interpretation is supplied by your program itself.  The @var{value}
+parameter is optional; if it is eliminated, the variable is set to a
+null value.
+
+@kindex unset local-environment
+@anchor{unset local-environment}
+@item unset local-environment @var{varname}
+Remove variable @var{varname} from the local environment.  This is
+different from @samp{set local-environment @var{varname} =};
+@code{unset local-environment} removes the variable from the
+environment, rather than assigning it an empty value.
 @end table
 
 @kindex show suppress-cli-notifications
index d8a62d0bffc777f983a733465a02c1f85a6bd93b..3ba286738a00b012079012074917bd51c0178afa 100644 (file)
@@ -2045,6 +2045,12 @@ environment_info (const char *var, int from_tty)
   display_environment (&current_inferior ()->environment, var);
 }
 
+static void
+local_environment_info (const char *var, int from_tty)
+{
+  display_environment (nullptr, var);
+}
+
 /* A helper to set an environment variable.  ARG is the string passed
    to 'set environment', i.e., the variable and value to use.  ENV is
    the environment in which the variable will be set.  */
@@ -2125,6 +2131,12 @@ set_environment_command (const char *arg, int from_tty)
   set_var_in_environment (&current_inferior ()->environment, arg);
 }
 
+static void
+set_local_environment_command (const char *arg, int from_tty)
+{
+  set_var_in_environment (nullptr, arg);
+}
+
 /* A helper to unset an environment variable.  ENV is the environment
    in which the variable will be unset.  VAR is the name of the
    variable, or NULL meaning unset all variables.  */
@@ -2159,6 +2171,12 @@ unset_environment_command (const char *var, int from_tty)
   unset_var_in_environment (&current_inferior ()->environment, var, from_tty);
 }
 
+static void
+unset_local_environment_command (const char *var, int from_tty)
+{
+  unset_var_in_environment (nullptr, var, from_tty);
+}
+
 /* Handle the execution path (PATH variable).  */
 
 static const char path_var_name[] = "PATH";
@@ -3184,6 +3202,14 @@ give the program being debugged.  With no arguments, prints the entire\n\
 environment to be given to the program."), &showlist);
   set_cmd_completer (c, noop_completer);
 
+  c = add_cmd ("local-environment", no_class, local_environment_info, _("\
+The local environment, or one variable's value.\n\
+With an argument VAR, prints the value of environment variable VAR to\n\
+use locally.  With no arguments, prints the entire local environment.\n\
+The local environment by commands that run a process locally, for\n\
+example \"shell\"."), &showlist);
+  set_cmd_completer (c, noop_completer);
+
   add_basic_prefix_cmd ("unset", no_class,
                        _("Complement to certain \"set\" commands."),
                        &unsetlist, 0, &cmdlist);
@@ -3194,6 +3220,12 @@ This does not affect the program until the next \"run\" command."),
               &unsetlist);
   set_cmd_completer (c, noop_completer);
 
+  c = add_cmd ("local-environment", class_run,
+              unset_local_environment_command, _("\
+Cancel local environment variable VAR."),
+              &unsetlist);
+  set_cmd_completer (c, noop_completer);
+
   c = add_cmd ("environment", class_run, set_environment_command, _("\
 Set environment variable value to give the program.\n\
 Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\
@@ -3202,6 +3234,16 @@ This does not affect the program until the next \"run\" command."),
               &setlist);
   set_cmd_completer (c, noop_completer);
 
+  c = add_cmd ("local-environment", class_run,
+              set_local_environment_command, _("\
+Set local environment variable value.\n\
+Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\
+VALUES of environment variables are uninterpreted strings.\n\
+The local environment by commands that run a process locally, for\n\
+example \"shell\"."),
+              &setlist);
+  set_cmd_completer (c, noop_completer);
+
   c = add_com ("path", class_files, path_command, _("\
 Add directory DIR(s) to beginning of search path for object files.\n\
 $cwd in the path means the current working directory.\n\
diff --git a/gdb/testsuite/gdb.base/local-env.exp b/gdb/testsuite/gdb.base/local-env.exp
new file mode 100644 (file)
index 0000000..fedcf9b
--- /dev/null
@@ -0,0 +1,133 @@
+# Copyright 1997-2025 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/>.  */
+
+# Test the "local-environment" commands.
+
+save_vars { env(GDB_TEST_ENV_VAR) } {
+    setenv GDB_TEST_ENV_VAR abc
+    gdb_start
+}
+
+proc test_set_show_env_var { name value test_name } {
+    gdb_test_no_output "set local-environment $name $value" "$test_name"
+    gdb_test "show local-environment $name" "$name = $value" \
+       "confirm $test_name"
+}
+
+proc test_set_show_env_var_equal { name value test_name } {
+    gdb_test_no_output "set local-environment $name = $value" "$test_name"
+    gdb_test "show local-environment $name" "$name = $value" \
+       "confirm $test_name"
+}
+
+# Verify that we can show all currently-set environment variables.
+# It's hard to do this verification since we can't really compare each
+# entry with the current environment.  So we just check to see if
+# there is anything that looks like an environment variable being
+# printed.
+set saw_env 0
+gdb_test_multiple "show environment" "show environment works" -lbl {
+    -re "\r\nGDB_TEST_ENV_VAR=abc" {
+       incr saw_env 1
+       exp_continue
+    }
+
+    -re "\r\n$gdb_prompt $" {
+    }
+}
+
+gdb_assert {$saw_env == 1} "show environment displayed variable"
+
+# Verify that we can unset a specific environment variable.
+gdb_test_no_output "unset local-environment EDITOR" \
+    "unset environment variable"
+
+gdb_test "show local-environment EDITOR" \
+    "Environment variable \"EDITOR\" not defined\." \
+    "confirm unset environment variable worked"
+
+# Verify that we can unset all environment variables.
+gdb_test "unset local-environment" "" "unset all environment variables" \
+    "Delete all environment variables. .y or n. $" \
+    "y"
+
+gdb_test_no_output "show local-environment" \
+    "all environment variables have been unset"
+
+# Verify that we can set a specific environment variable.
+test_set_show_env_var "EDITOR" "emacs" "set environment variable"
+
+# Verify that GDB responds gracefully to a request to set environment,
+# with no variable name.
+gdb_test "set local-environment" \
+    "Argument required \\\(environment variable and value\\\)\." \
+    "set environment without arguments"
+
+# I'm not sure just what GDB has in mind in explicitly checking
+# for this variant, but since GDB handles it, test it.
+gdb_test "set local-environment =" \
+    "Argument required \\\(environment variable to set\\\)\." \
+    "set environment without variable name"
+
+# Setting an environment variable without a value sets it to a NULL
+# value.
+gdb_test "set local-environment EDITOR" \
+    "Setting environment variable \"EDITOR\" to null value\." \
+    "set environment variable to null value"
+gdb_test "show local-environment EDITOR" "EDITOR = " \
+    "show null environment variable"
+
+# Verify that GDB responds gracefully to an attempt to show a
+# non-existent environment variable.  (We hope this variable is
+# undefined!)
+gdb_test "show local-environment FOOBARBAZGRUNGESPAZBALL" \
+    "Environment variable \"FOOBARBAZGRUNGESPAZBALL\" not defined\." \
+    "show non-existent environment variable"
+
+# Verify that GDB can set an environment variable hitherto undefined.
+test_set_show_env_var "FOOBARBAZGRUNGESPAZBALL" "t" \
+    "set environment variable previously undefined"
+
+# Verify that GDB can also set an environment variable using the "="
+# syntax.
+test_set_show_env_var_equal "FOOBARBAZGRUNGESPAZBALL" "y" \
+    "set environment variable using = syntax"
+
+# Verify that GDB can set an environment variable to a value that has
+# an embedded (trailing, in this case) equals.
+test_set_show_env_var_equal "FOOBARBAZGRUNGESPAZBALL" "t=" \
+    "set environment variable with trailing equals"
+
+# Verify that GDB can set an environment variable to a value preceded
+# by whitespace, and that such whitespace is ignored (not included
+# in the set value).
+gdb_test_no_output \
+    "set local-environment FOOBARBAZGRUNGESPAZBALL =        foo" \
+    "set environment variable with trailing whitespace"
+gdb_test "show local-environment FOOBARBAZGRUNGESPAZBALL" \
+    "FOOBARBAZGRUNGESPAZBALL = foo" \
+    "confirm set environment variable with trailing whitespace"
+
+# Verify that the setting affects the "pipe" command.
+gdb_test "pipe print 23 | printenv | grep FOOBARBAZGRUNGESPAZBALL" \
+    "FOOBARBAZGRUNGESPAZBALL=foo" \
+    "set local-environment affects pipe"
+
+# Verify that the setting affects "shell".
+gdb_test "shell printenv | grep FOOBARBAZGRUNGESPAZBALL" \
+    "FOOBARBAZGRUNGESPAZBALL=foo" \
+    "set local-environment affects shell"
+
+gdb_exit