@@ -61,6 +61,9 @@ QStartupWithShell
* New commands
+set|show cwd
+ Set and show the current working directory for the inferior.
+
set|show compile-gcc
Set and show compilation command used for compiling and injecting code
with the 'compile' commands.
@@ -1716,9 +1716,9 @@ The commands below can be used to select other frames by number or address."),
Print working directory. This is used for your program as well."));
c = add_cmd ("cd", class_files, cd_command, _("\
-Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started."), &cmdlist);
+Set working directory to DIR for debugger.\n\
+In order to change the inferior's current working directory, the recommended\n\
+way is to use the \"set cwd\" command."), &cmdlist);
set_cmd_completer (c, filename_completer);
add_com ("echo", class_support, echo_command, _("\
@@ -30,4 +30,8 @@ extern const char *get_exec_wrapper ();
otherwise return 0 in that case. */
extern char *get_exec_file (int err);
+/* Return the inferior's current working directory. If nothing has
+ been set, then return NULL. */
+extern const char *get_inferior_cwd ();
+
#endif /* ! COMMON_INFERIOR_H */
@@ -2057,10 +2057,11 @@ environment} to change parts of the environment that affect
your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
-Your program inherits its working directory from @value{GDBN}. You can set
-the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}.
+Your program inherits its working directory from @value{GDBN}. This
+can be changed by using the @code{set cwd} command in @value{GDBN}.
@xref{Working Directory, ,Your Program's Working Directory}.
+
@item The @emph{standard input and output.}
Your program normally uses the same device for standard input and
standard output as @value{GDBN} is using. You can redirect input and output
@@ -2427,14 +2428,30 @@ variables to files that are only run when you sign on, such as
Each time you start your program with @code{run}, it inherits its
working directory from the current working directory of @value{GDBN}.
The @value{GDBN} working directory is initially whatever it inherited
-from its parent process (typically the shell), but you can specify a new
-working directory in @value{GDBN} with the @code{cd} command.
+from its parent process (typically the shell), but you can specify a
+new working directory in @value{GDBN} with the @code{cd} command. You
+can specify a working directory especifically for the inferior with
+the @code{set cwd} command.
The @value{GDBN} working directory also serves as a default for the commands
that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to
Specify Files}.
@table @code
+@kindex set cwd
+@cindex change inferior's working directory
+@item set cwd @r{[}@var{directory}@r{]}
+Set the inferior's working directory to @var{directory}. If not
+given, @var{directory} uses @file{'~'}. This has no effect on
+@value{GDBN}'s working directory.
+
+@kindex show cwd
+@cindex show inferior's working directory
+@item show cwd
+Show the inferior's working directory. If no directory has been
+specified by @code{set cwd}, then the default inferior's working
+directory is the same as @value{GDBN}'s working directory.
+
@kindex cd
@cindex change working directory
@item cd @r{[}@var{directory}@r{]}
@@ -29,6 +29,9 @@ struct thread_info *current_thread;
#define get_thread(inf) ((struct thread_info *)(inf))
+/* The current working directory used to start the inferior. */
+static const char *current_inferior_cwd = NULL;
+
void
add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior)
@@ -471,3 +474,11 @@ switch_to_thread (ptid_t ptid)
if (!ptid_equal (ptid, minus_one_ptid))
current_thread = find_thread_ptid (ptid);
}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior_cwd;
+}
@@ -59,6 +59,8 @@
#include "top.h"
#include "interps.h"
#include "common/gdb_optional.h"
+#include "gdb_chdir.h"
+#include "readline/tilde.h"
/* Local functions: */
@@ -111,6 +113,10 @@ static void run_command (char *, int);
static char *inferior_args_scratch;
+/* Scratch area where the new cwd will be stored by 'set cwd'. */
+
+static char *inferior_cwd_scratch;
+
/* Scratch area where 'set inferior-tty' will store user-provided value.
We'll immediate copy it into per-inferior storage. */
@@ -246,6 +252,56 @@ show_args_command (struct ui_file *file, int from_tty,
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}
+/* Set the inferior current working directory. This directory will be
+ entered by GDB before executing the inferior. */
+
+static void
+set_inferior_cwd (const char *cwd)
+{
+ struct inferior *inf = current_inferior ();
+
+ gdb_assert (inf != NULL);
+ xfree ((void *) inf->cwd);
+ inf->cwd = tilde_expand (*cwd != '\0' ? cwd : "~");
+}
+
+/* See inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior ()->cwd;
+}
+
+/* Handle the 'set cwd' command. */
+
+static void
+set_cwd_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ set_inferior_cwd (inferior_cwd_scratch);
+}
+
+/* Handle the 'show cwd' command. */
+
+static void
+show_cwd_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd == NULL)
+ {
+ /* To maintain backwards compatibility, we use
+ 'current_directory' here, which is set by the "cd"
+ command. */
+ cwd = current_directory;
+ }
+
+ fprintf_filtered (gdb_stdout,
+ _("Current working directory that will be used "
+ "when starting the inferior is \"%s\".\n"), cwd);
+}
+
/* Compute command-line string given argument vector. This does the
same shell processing as fork_inferior. */
@@ -3214,6 +3270,25 @@ Follow this command with any number of args, to be passed to the program."),
gdb_assert (c != NULL);
set_cmd_completer (c, filename_completer);
+ cmd_name = "cwd";
+ add_setshow_string_noescape_cmd (cmd_name, class_run,
+ &inferior_cwd_scratch, _("\
+Set the current working directory to be used when the inferior is started.\n\
+Changing this setting does not have any effect on inferiors that are\n\
+already running."),
+ _("\
+Show the current working directory that is used when the inferior is started."),
+ _("\
+Use this command to change the current working directory that will be used\n\
+when the inferior is started. This setting does not affect GDB's current\n\
+working directory."),
+ set_cwd_command,
+ show_cwd_command,
+ &setlist, &showlist);
+ c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+ gdb_assert (c != NULL);
+ set_cmd_completer (c, filename_completer);
+
c = add_cmd ("environment", no_class, environment_info, _("\
The environment to give the program, or one variable's value.\n\
With an argument VAR, prints the value of environment variable VAR to\n\
@@ -355,6 +355,10 @@ public:
should never be freed. */
char **argv = NULL;
+ /* The current working directory that will be used when starting
+ this inferior. */
+ const char *cwd = NULL;
+
/* The name of terminal device to use for I/O. */
char *terminal = NULL;
@@ -25,6 +25,7 @@
#include "common-inferior.h"
#include "common-gdbthread.h"
#include "signals-state-save-restore.h"
+#include "gdb_chdir.h"
#include <vector>
extern char **environ;
@@ -376,6 +377,22 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
UIs. */
close_most_fds ();
+ const char *cwd = get_inferior_cwd ();
+
+ if (cwd != NULL)
+ {
+ TRY
+ {
+ gdb_chdir (cwd);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ warning ("%s", ex.message);
+ _exit (0177);
+ }
+ END_CATCH
+ }
+
if (debug_fork)
sleep (debug_fork);
new file mode 100644
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 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 <stdio.h>
+#include <unistd.h>
+
+int
+main (int argc, char *argv[])
+{
+ char dir[BUFSIZ];
+
+ getcwd (dir, BUFSIZ);
+
+ return 0; /* break-here */
+}
new file mode 100644
@@ -0,0 +1,90 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 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/>.
+
+if { ![isnative] || [is_remote target] || [is_remote host]
+ || [target_info gdb_protocol] == "extended-remote" } then {
+ untested "not implemented on gdbserver"
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc test_tilde_expansion { } {
+ if { [info exists ::env(HOME)] } {
+ with_test_prefix "test tilde expansion" {
+ set home $::env(HOME)
+
+ gdb_test_no_output "set cwd ~/test" "set cwd to ~/test dir"
+
+ gdb_test "show cwd" \
+ "Current working directory that will be used when starting the inferior is \"${home}/test\"\." \
+ "show cwd shows expanded tilde"
+ }
+ }
+}
+
+# Test that when we "set cwd" the inferior will be started under the
+# correct working directory and GDB will not be affected by this.
+
+proc test_cd_into_dir { } {
+ global decimal gdb_prompt
+
+ with_test_prefix "test cd into temp dir" {
+ gdb_test_multiple "pwd" "pwd before run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ }
+ }
+
+ set tmpdir [standard_output_file ""]
+
+ gdb_test_no_output "set cwd $tmpdir" "set cwd to temp dir"
+
+ if { ![runto_main] } {
+ untested "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break-here"]
+ gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+ gdb_test "print dir" "\\\$$decimal = \"$tmpdir\", .*" \
+ "inferior cwd is correctly set"
+
+ gdb_test_multiple "pwd" "pwd after run" {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ }
+ }
+
+ set test "GDB cwd is unchanged after running inferior"
+ if { [string equal $gdb_cwd_before_run $gdb_cwd_after_run] } {
+ pass $test
+ } else {
+ fail $test
+ }
+ }
+}
+
+test_cd_into_dir
+test_tilde_expansion