@@ -26,6 +26,12 @@
* New features in the GDB remote stub, GDBserver
+ ** GDBserver is now able to start inferior processes with a
+ specified initial working directory.
+
+ The user can set the desired working directory to be used from
+ GDB using the new "set cwd" command.
+
** New "--selftest" command line option runs some GDBserver self
tests. These self tests are disabled in releases.
@@ -59,6 +65,10 @@ QEnvironmentReset
QStartupWithShell
Indicates whether the inferior must be started with a shell or not.
+QSetWorkingDir
+ Tell GDBserver that the inferior to be started should use a specific
+ working directory.
+
* The "maintenance print c-tdesc" command now takes an optional
argument which is the file name of XML target description.
@@ -34,4 +34,8 @@ extern char *get_exec_file (int err);
been set, then return NULL. */
extern const char *get_inferior_cwd ();
+/* Set the inferior current working directory. If CWD is NULL, unset
+ the directory. */
+extern void set_inferior_cwd (const char *cwd);
+
#endif /* ! COMMON_INFERIOR_H */
@@ -2059,8 +2059,10 @@ your program. @xref{Environment, ,Your Program's Environment}.
@item The @emph{working directory.}
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}.
+command, your program will inherit @value{GDBN}'s working directory if
+native debugging, or the remote server's working directory if remote
+debugging. @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
@@ -2439,7 +2441,9 @@ 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.
+directory as its working directory if native debugging, or it will
+inherit the remote server's current working directory if remote
+debugging.
You can also change @value{GDBN}'s current working directory by using
the @code{cd} command.
@@ -20999,6 +21003,10 @@ are:
@tab @code{QEnvironmentReset}
@tab @code{Reset the inferior environment (i.e., unset user-set variables)}
+@item @code{set-working-dir}
+@tab @code{QSetWorkingDir}
+@tab @code{set cwd}
+
@item @code{conditional-breakpoints-packet}
@tab @code{Z0 and Z1}
@tab @code{Support for target-side breakpoint condition evaluation}
@@ -36856,6 +36864,28 @@ by supplying an appropriate @samp{qSupported} response
actually support passing environment variables to the starting
inferior.
+@item QSetWorkingDir:@r{[}@var{directory}@r{]}
+@anchor{QSetWorkingDir packet}
+@cindex set working directory, remote request
+@cindex @samp{QSetWorkingDir} packet
+This packet is used to inform the remote server of the intended
+current working directory for programs that are going to be executed.
+
+The packet is composed by @var{directory}, an hex encoded
+representation of the directory that the remote inferior will use as
+its current working directory. If @var{directory} is an empty string,
+the remote server should reset the inferior's current working
+directory to its original, empty value.
+
+This packet is only available in extended mode (@pxref{extended
+mode}).
+
+Reply:
+@table @samp
+@item OK
+The request succeeded.
+@end table
+
@item qfThreadInfo
@itemx qsThreadInfo
@cindex list active threads, remote request
@@ -456,3 +456,15 @@ get_inferior_cwd ()
{
return current_inferior_cwd;
}
+
+/* See common/common-inferior.h. */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+ xfree ((void *) current_inferior_cwd);
+ if (cwd != NULL)
+ current_inferior_cwd = xstrdup (cwd);
+ else
+ current_inferior_cwd = NULL;
+}
@@ -869,6 +869,35 @@ handle_general_set (char *own_buf)
return;
}
+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+
+ if (*p != '\0')
+ {
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Set the inferior's current directory to %s]\n"),
+ path.c_str ());
+ }
+ else
+ {
+ /* An empty argument means that we should clear out any
+ previously set cwd for the inferior. */
+ set_inferior_cwd (NULL);
+
+ if (remote_debug)
+ debug_printf (_("\
+[Unset the inferior's current directory; will use gdbserver's cwd]\n"));
+ }
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -2351,7 +2380,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);
if (target_supports_catch_syscall ())
@@ -32,6 +32,7 @@
#include <tlhelp32.h>
#include <psapi.h>
#include <process.h>
+#include "gdb_tilde_expand.h"
#ifndef USE_WIN32API
#include <sys/cygwin.h>
@@ -562,10 +563,12 @@ static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
+ std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd);
BOOL ret;
#ifdef _WIN32_WCE
- wchar_t *p, *wprogram, *wargs;
+ wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
size_t argslen;
wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
@@ -579,6 +582,19 @@ create_process (const char *program, char *args,
wargs = alloca ((argslen + 1) * sizeof (wchar_t));
mbstowcs (wargs, args, argslen + 1);
+ if (inferior_cwd != NULL)
+ {
+ std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
+ '/', '\\');
+ wcwd = alloca ((expanded_infcwd.size () + 1) * sizeof (wchar_t));
+ if (mbstowcs (wcwd, expanded_infcwd.c_str (),
+ expanded_infcwd.size () + 1) == NULL)
+ {
+ error (_("\
+Could not convert the expanded inferior cwd to wide-char."));
+ }
+ }
+
ret = CreateProcessW (wprogram, /* image name */
wargs, /* command line */
NULL, /* security, not supported */
@@ -586,7 +602,7 @@ create_process (const char *program, char *args,
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ wcwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
@@ -599,7 +615,7 @@ create_process (const char *program, char *args,
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ expanded_infcwd.c_str (), /* current directory */
&si, /* start info */
pi); /* proc info */
#endif
@@ -242,10 +242,9 @@ 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. If CWD is NULL, unset
- the directory. */
+/* See common/common-inferior.h. */
-static void
+void
set_inferior_cwd (const char *cwd)
{
struct inferior *inf = current_inferior ();
@@ -289,7 +288,8 @@ show_cwd_command (struct ui_file *file, int from_tty,
fprintf_filtered (gdb_stdout,
_("\
You have not set the inferior's current working directory.\n\
-The inferior will inherit GDB's cwd.\n"));
+The inferior will inherit GDB's cwd if native debugging, or the remote\n\
+server's cwd if remote debugging.\n"));
else
fprintf_filtered (gdb_stdout,
_("Current working directory that will be used "
@@ -1430,6 +1430,7 @@ enum {
PACKET_QPassSignals,
PACKET_QCatchSyscalls,
PACKET_QProgramSignals,
+ PACKET_QSetWorkingDir,
PACKET_QStartupWithShell,
PACKET_QEnvironmentHexEncoded,
PACKET_QEnvironmentReset,
@@ -4662,6 +4663,8 @@ static const struct protocol_feature remote_protocol_features[] = {
PACKET_QCatchSyscalls },
{ "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QProgramSignals },
+ { "QSetWorkingDir", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QSetWorkingDir },
{ "QStartupWithShell", PACKET_DISABLE, remote_supported_packet,
PACKET_QStartupWithShell },
{ "QEnvironmentHexEncoded", PACKET_DISABLE, remote_supported_packet,
@@ -9641,6 +9644,45 @@ extended_remote_environment_support (struct remote_state *rs)
send_environment_packet (rs, "unset", "QEnvironmentUnset", el.c_str ());
}
+/* Helper function to set the current working directory for the
+ inferior in the remote. */
+
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ }
+ else
+ {
+ /* An empty inferior_cwd means that the user wants us to
+ reset the remote server's inferior's cwd. */
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:");
+ }
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_QSetWorkingDir])
+ != PACKET_OK)
+ error (_("\
+Remote replied unexpectedly while setting the inferior's working\n\
+directory: %s"),
+ rs->buf);
+
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
@@ -9683,6 +9725,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
extended_remote_environment_support (rs);
+ extended_remote_set_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
@@ -14190,6 +14234,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
"QStartupWithShell", "startup-with-shell", 0);
@@ -15,8 +15,8 @@
# 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"
+if { [use_gdb_stub] } {
+ untested "skipping tests due to use_gdb_stub"
return
}