2017-10-04 Sergio Durigan Junior <sergiodj@redhat.com>
+ * NEWS (New commands): Mention "set/show cwd".
+ * cli/cli-cmds.c (_initialize_cli_cmds): Mention "set cwd" on
+ "cd" command's help text.
+ * common/common-inferior.h (get_inferior_cwd): New prototype.
+ * infcmd.c (inferior_cwd_scratch): New global variable.
+ (set_inferior_cwd): New function.
+ (get_inferior_cwd): Likewise.
+ (set_cwd_command): Likewise.
+ (show_cwd_command): Likewise.
+ (_initialize_infcmd): Add "set/show cwd" commands.
+ * inferior.h (class inferior) <cwd>: New field.
+ * nat/fork-inferior.c: Include "gdb_tilde_expand.h".
+ (fork_inferior): Change inferior's cwd before its execution.
+ * windows-nat.c (windows_create_inferior): Pass inferior's cwd
+ to CreateProcess.
+
+2017-10-04 Sergio Durigan Junior <sergiodj@redhat.com>
+
* Makefile.in (SFILES): Add gdb_tilde_expand.c.
(HFILES_NO_SRCDIR): Add gdb_tilde_expand.h.
(COMMON_OBS): Add gdb_tilde_expand.o.
* 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.
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\
+The debugger's current working directory specifies where scripts and other\n\
+files that can be loaded by GDB are located.\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, _("\
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 */
+2017-10-04 Sergio Durigan Junior <sergiodj@redhat.com>
+
+ * gdb.texinfo (Starting your Program) <The working directory.>:
+ Mention new "set cwd" command.
+ (Working Directory) <Your Program's Working Directory>:
+ Rephrase to explain that "set cwd" exists and is the default
+ way to change the inferior's cwd.
+
2017-09-25 Andreas Arnez <arnez@linux.vnet.ibm.com>
* gdb.texinfo (S/390 and System z Features): Document the new
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}.
+You can set your program's working directory with the command
+@kbd{set cwd}. If you do not set any working directory with this
+command, your program will inherit @value{GDBN}'s working directory.
@xref{Working Directory, ,Your Program's Working Directory}.
@item The @emph{standard input and output.}
@section Your Program's Working Directory
@cindex working directory (of your program)
-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.
-
-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}.
+Each time you start your program with @code{run}, the inferior will be
+initialized with the current working directory specified by the
+@kbd{set cwd} command. If no directory has been specified by this
+command, then the inferior will inherit @value{GDBN}'s current working
+directory as its working directory.
+
+@table @code
+@kindex set cwd
+@cindex change inferior's working directory
+@anchor{set cwd command}
+@item set cwd @r{[}@var{directory}@r{]}
+Set the inferior's working directory to @var{directory}, which will be
+@code{glob}-expanded in order to resolve tildes (@file{~}). If no
+argument has been specified, the command clears the setting and resets
+it to an empty state. This setting has no effect on @value{GDBN}'s
+working directory, and it only takes effect the next time you start
+the inferior. The @file{~} in @var{directory} is a short for the
+@dfn{home directory}, usually pointed to by the @env{HOME} environment
+variable. On MS-Windows, if @env{HOME} is not defined, @value{GDBN}
+uses the concatenation of @env{HOMEDRIVE} and @env{HOMEPATH} as
+fallback.
+
+You can also change @value{GDBN}'s current working directory by using
+the @code{cd} command.
+@xref{cd command}
+
+@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 @kbd{set cwd}, then the default inferior's working
+directory is the same as @value{GDBN}'s working directory.
-@table @code
@kindex cd
-@cindex change working directory
+@cindex change @value{GDBN}'s working directory
+@anchor{cd command}
@item cd @r{[}@var{directory}@r{]}
Set the @value{GDBN} working directory to @var{directory}. If not
given, @var{directory} uses @file{'~'}.
+The @value{GDBN} working directory serves as a default for the
+commands that specify files for @value{GDBN} to operate on.
+@xref{Files, ,Commands to Specify Files}.
+@xref{set cwd command}
+
@kindex pwd
@item pwd
Print the @value{GDBN} working directory.
2017-10-04 Sergio Durigan Junior <sergiodj@redhat.com>
+ * inferiors.c (current_inferior_cwd): New global variable.
+ (get_inferior_cwd): New function.
+ * inferiors.h (struct process_info) <cwd>: New field.
+
+2017-10-04 Sergio Durigan Junior <sergiodj@redhat.com>
+
* Makefile.in (SFILES): Add $(srcdir)/common/gdb_tilde_expand.c.
(OBS): Add gdb_tilde_expand.o.
#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)
gdb_assert (ptid != minus_one_ptid);
current_thread = find_thread_ptid (ptid);
}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior_cwd;
+}
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. */
deprecated_show_value_hack (file, from_tty, c, get_inferior_args ());
}
+/* Set the inferior current working directory. If CWD is NULL, unset
+ the directory. */
+
+static void
+set_inferior_cwd (const char *cwd)
+{
+ struct inferior *inf = current_inferior ();
+
+ gdb_assert (inf != NULL);
+
+ if (cwd == NULL)
+ inf->cwd.reset ();
+ else
+ inf->cwd.reset (xstrdup (cwd));
+}
+
+/* See common/common-inferior.h. */
+
+const char *
+get_inferior_cwd ()
+{
+ return current_inferior ()->cwd.get ();
+}
+
+/* Handle the 'set cwd' command. */
+
+static void
+set_cwd_command (char *args, int from_tty, struct cmd_list_element *c)
+{
+ if (*inferior_cwd_scratch == '\0')
+ set_inferior_cwd (NULL);
+ else
+ 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)
+ fprintf_filtered (gdb_stdout,
+ _("\
+You have not set the inferior's current working directory.\n\
+The inferior will inherit GDB's cwd.\n"));
+ else
+ fprintf_filtered (gdb_stdout,
+ _("Current working directory that will be used "
+ "when starting the inferior is \"%s\".\n"), cwd);
+}
+
\f
/* Compute command-line string given argument vector. This does the
same shell processing as fork_inferior. */
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\
should never be freed. */
char **argv = NULL;
+ /* The current working directory that will be used when starting
+ this inferior. */
+ gdb::unique_xmalloc_ptr<char> cwd;
+
/* The name of terminal device to use for I/O. */
char *terminal = NULL;
#include "common-inferior.h"
#include "common-gdbthread.h"
#include "signals-state-save-restore.h"
+#include "gdb_tilde_expand.h"
#include <vector>
extern char **environ;
char **save_our_env;
int i;
int save_errno;
+ const char *inferior_cwd;
+ std::string expanded_inferior_cwd;
/* If no exec file handed to us, get it from the exec-file command
-- with a good, common error message if none is specified. */
the parent and child flushing the same data after the fork. */
gdb_flush_out_err ();
+ /* Check if the user wants to set a different working directory for
+ the inferior. */
+ inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ /* Expand before forking because between fork and exec, the child
+ process may only execute async-signal-safe operations. */
+ expanded_inferior_cwd = gdb_tilde_expand (inferior_cwd);
+ inferior_cwd = expanded_inferior_cwd.c_str ();
+ }
+
/* If there's any initialization of the target layers that must
happen to prepare to handle the child we're about fork, do it
now... */
UIs. */
close_most_fds ();
+ /* Change to the requested working directory if the user
+ requested it. */
+ if (inferior_cwd != NULL)
+ {
+ if (chdir (inferior_cwd) < 0)
+ trace_start_error_with_name (inferior_cwd);
+ }
+
if (debug_fork)
sleep (debug_fork);
+2017-10-04 Sergio Durigan Junior <sergiodj@redhat.com>
+
+ * gdb.base/set-cwd.c: New file.
+ * gdb.base/set-cwd.exp: Likewise.
+
2017-10-02 Tom Tromey <tom@tromey.com>
PR rust/22236:
--- /dev/null
+/* 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 <stdlib.h>
+#include <unistd.h>
+
+static char dir[4096];
+
+int
+main (int argc, char *argv[])
+{
+ const char *home = getenv ("HOME");
+
+ getcwd (dir, 4096);
+
+ return 0; /* break-here */
+}
--- /dev/null
+# 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 { [use_gdb_stub] || [target_info gdb_protocol] == "extended-remote" } {
+ untested "not implemented on remote servers"
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ return -1
+}
+
+# Test that tilde expansion works fine.
+
+proc_with_prefix test_tilde_expansion { } {
+ global decimal gdb_prompt hex
+
+ gdb_test_no_output "set cwd ~/" "set inferior cwd to ~/ 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 .*"
+
+ set home ""
+ set test "print home var"
+ gdb_test_multiple "print home" $test {
+ -re "\\\$$decimal = $hex \"\(.+\)\"\r\n$gdb_prompt $" {
+ set home $expect_out(1,string)
+ pass $test
+ }
+ }
+
+ if { $home == "" } {
+ untested "could not retrieve home var"
+ return
+ }
+
+ set curdir ""
+ set test "print dir var"
+ gdb_test_multiple "print dir" $test {
+ -re "\\\$$decimal = \"\(.+\)\"\(, .*repeats.*\)?\r\n$gdb_prompt $" {
+ set curdir $expect_out(1,string)
+ pass $test
+ }
+ }
+
+ if { $curdir == "" } {
+ untested "could not retrieve dir var"
+ return
+ }
+
+ gdb_assert [string equal $curdir $home] \
+ "successfully chdir'd into home"
+}
+
+# The temporary directory that we will use to start the inferior.
+set tmpdir [standard_output_file ""]
+
+# 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_with_prefix test_cd_into_dir { } {
+ global decimal gdb_prompt tmpdir
+
+ set gdb_cwd_before_run ""
+ set test "pwd before run"
+ gdb_test_multiple "pwd" $test {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_before_run $expect_out(1,string)
+ pass $test
+ }
+ }
+
+ if { $gdb_cwd_before_run == "" } {
+ untested "could not obtain GDB cwd before run"
+ return
+ }
+
+ # This test only makes sense if $tmpdir != $gdb_cwd_before_run
+ if { ![gdb_assert ![string equal $tmpdir $gdb_cwd_before_run] \
+ "make sure that tmpdir and GDB's cwd are different"] } {
+ return -1
+ }
+
+ gdb_test_no_output "set cwd $tmpdir" "set inferior 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"
+
+ set gdb_cwd_after_run ""
+ set test "pwd after run"
+ gdb_test_multiple "pwd" $test {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd_after_run $expect_out(1,string)
+ pass $test
+ }
+ }
+
+ if { $gdb_cwd_after_run == "" } {
+ untested "could not obtain GDB cwd after run"
+ return
+ }
+
+ gdb_assert [string equal $gdb_cwd_before_run $gdb_cwd_after_run] \
+ "GDB cwd is unchanged after running inferior"
+}
+
+# Test that executing "set cwd" without arguments will reset the
+# inferior's cwd setting to its previous state.
+
+proc_with_prefix test_cwd_reset { } {
+ global decimal gdb_prompt tmpdir
+
+ set gdb_cwd ""
+ set test "GDB cwd"
+ gdb_test_multiple "pwd" $test {
+ -re "Working directory \(.*\)\.\r\n$gdb_prompt $" {
+ set gdb_cwd $expect_out(1,string)
+ }
+ }
+
+ if { $gdb_cwd == "" } {
+ untested "could not obtain GDB cwd"
+ return
+ }
+
+ # This test only makes sense if $tmpdir != $gdb_cwd.
+ if { ![gdb_assert ![string equal $tmpdir $gdb_cwd] \
+ "make sure that tmpdir and GDB's cwd are different"] } {
+ return -1
+ }
+
+ gdb_test_no_output "set cwd $tmpdir" "set inferior cwd to temp dir"
+
+ with_test_prefix "running with set cwd" {
+ 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"
+
+ # Reset the inferior's cwd.
+ gdb_test_no_output "set cwd" "resetting inferior cwd"
+
+ with_test_prefix "running without set cwd" {
+ 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 = \"$gdb_cwd\", .*" \
+ "inferior cwd got reset correctly"
+}
+
+test_cd_into_dir
+clean_restart $binfile
+test_tilde_expansion
+clean_restart $binfile
+test_cwd_reset
#include "x86-nat.h"
#include "complaints.h"
#include "inf-child.h"
+#include "gdb_tilde_expand.h"
#define AdjustTokenPrivileges dyn_AdjustTokenPrivileges
#define DebugActiveProcessStop dyn_DebugActiveProcessStop
#ifdef __CYGWIN__
cygwin_buf_t real_path[__PMAX];
cygwin_buf_t shell[__PMAX]; /* Path to shell */
+ cygwin_buf_t infcwd[__PMAX];
const char *sh;
cygwin_buf_t *toexec;
cygwin_buf_t *cygallargs;
if (!exec_file)
error (_("No executable specified, use `target exec'."));
+ const char *inferior_cwd = get_inferior_cwd ();
+ std::string expanded_infcwd;
+ if (inferior_cwd != NULL)
+ {
+ expanded_infcwd = gdb_tilde_expand (inferior_cwd);
+ /* Mirror slashes on inferior's cwd. */
+ std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
+ '/', '\\');
+ inferior_cwd = expanded_infcwd.c_str ();
+ }
+
memset (&si, 0, sizeof (si));
si.cb = sizeof (si);
flags |= DEBUG_PROCESS;
}
+ if (inferior_cwd != NULL
+ && cygwin_conv_path (CCP_POSIX_TO_WIN_W, inferior_cwd,
+ infcwd, strlen (inferior_cwd)) < 0)
+ error (_("Error converting inferior cwd: %d"), errno);
+
#ifdef __USEWIDE
args = (cygwin_buf_t *) alloca ((wcslen (toexec) + wcslen (cygallargs) + 2)
* sizeof (wchar_t));
TRUE, /* inherit handles */
flags, /* start flags */
w32_env, /* environment */
- NULL, /* current directory */
+ inferior_cwd != NULL ? infcwd : NULL, /* current
+ directory */
&si,
&pi);
if (w32_env)
TRUE, /* inherit handles */
flags, /* start flags */
w32env, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si,
&pi);
if (tty != INVALID_HANDLE_VALUE)