diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ea4fc621b02..e113e2ff664 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +2017-10-04 Sergio Durigan Junior + + * NEWS (Changes since GDB 8.0): Add entry about new + 'set-cwd-on-gdbserver' feature. + (New remote packets): Add entry for QSetWorkingDir. + * common/common-inferior.h (set_inferior_cwd): New prototype. + * infcmd.c (set_inferior_cwd): Remove "static". + (show_cwd_command): Expand text to include remote debugging. + * remote.c: Add PACKET_QSetWorkingDir. + (remote_protocol_features) : New entry for + PACKET_QSetWorkingDir. + (extended_remote_set_inferior_cwd): New function. + (extended_remote_create_inferior): Call + "extended_remote_set_inferior_cwd". + (_initialize_remote): Call "add_packet_config_cmd" for + QSetWorkingDir. + 2017-10-04 Sergio Durigan Junior * NEWS (New commands): Mention "set/show cwd". diff --git a/gdb/NEWS b/gdb/NEWS index fcf454833fa..2bad096a86e 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -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. diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h index 515a8c0f4e0..3dcfda3e7b5 100644 --- a/gdb/common/common-inferior.h +++ b/gdb/common/common-inferior.h @@ -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 */ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 4ded14ae2a0..e3ea4ec614e 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,14 @@ +2017-10-04 Sergio Durigan Junior + + * gdb.texinfo (Starting your Program) : + Mention remote debugging. + (Working Directory) : + Likewise. + (Connecting) : Add "set-working-dir" + and "QSetWorkingDir" to the table. + (Remote Protocol) : New item, explaining the + packet. + 2017-10-04 Sergio Durigan Junior * gdb.texinfo (Starting your Program) : diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index a68107dddb0..bfeb7a9a35d 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -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. @table @code @kindex set cwd @@ -21003,6 +21007,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} @@ -36860,6 +36868,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 diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 25d527b924a..0bdeabaa9b1 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,11 @@ +2017-10-04 Sergio Durigan Junior + + * inferiors.c (set_inferior_cwd): New function. + * server.c (handle_general_set): Handle QSetWorkingDir packet. + (handle_query): Inform that QSetWorkingDir is supported. + * win32-low.c (create_process): Pass the inferior's cwd to + CreateProcess. + 2017-10-04 Sergio Durigan Junior * inferiors.c (current_inferior_cwd): New global variable. diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 57d9956ebb2..154c167f4ca 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -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; +} diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index c4f1e8dde63..a95973547ce 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -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 ()) diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index cc84d15c2f5..c11926f7c6c 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -32,6 +32,7 @@ #include #include #include +#include "gdb_tilde_expand.h" #ifndef USE_WIN32API #include @@ -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 diff --git a/gdb/infcmd.c b/gdb/infcmd.c index dbdf273ca5c..187c71f3446 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -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 " diff --git a/gdb/remote.c b/gdb/remote.c index 54d810f0543..8c47d0662cd 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -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 target. */ + +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); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index b72788ba91c..2a580f4cb11 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-10-04 Sergio Durigan Junior + + * gdb.base/set-cwd.exp: Make it available on + native-extended-gdbserver. + 2017-10-04 Sergio Durigan Junior * gdb.base/set-cwd.c: New file. diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp index 0d536488e4b..6b81fbc0b58 100644 --- a/gdb/testsuite/gdb.base/set-cwd.exp +++ b/gdb/testsuite/gdb.base/set-cwd.exp @@ -15,8 +15,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -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 }