This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Extend "set cwd" to work on gdbserver


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=bc3b087de2401c65c02730d346e8bea4dc0504ae

commit bc3b087de2401c65c02730d346e8bea4dc0504ae
Author: Sergio Durigan Junior <sergiodj@redhat.com>
Date:   Wed Sep 20 19:15:40 2017 -0400

    Extend "set cwd" to work on gdbserver
    
    This is the "natural" extension necessary for the "set cwd" command
    (and the whole "set the inferior's cwd" logic) to work on gdbserver.
    
    The idea here is to have a new remote packet, QSetWorkingDir (name
    adopted from LLDB's extension to the RSP, as can be seen at
    <https://raw.githubusercontent.com/llvm-mirror/lldb/master/docs/lldb-gdb-remote.txt>),
    which sends an hex-encoded string representing the working directory
    that the remote inferior will use.  There is a slight difference from
    the packet proposed by LLDB: GDB's version will accept empty
    arguments, meaning that the user wants to clear the previously set
    working directory for the inferior (i.e., "set cwd" without arguments
    on GDB).
    
    For UNIX-like targets this feature is already implemented on
    nat/fork-inferior.c, and all gdbserver has to do is to basically
    implement "set_inferior_cwd" and call it whenever such packet arrives.
    For other targets, like Windows, it is possible to use the existing
    "get_inferior_cwd" function and do the necessary steps to make sure
    that the inferior will use the specified working directory.
    
    Aside from that, the patch consists basically of updates to the
    testcase (making it available on remote targets) and the
    documentation.
    
    No regressions found.
    
    gdb/ChangeLog:
    2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
    
    	* 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) <QSetWorkingDir>: 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.
    
    gdb/gdbserver/ChangeLog:
    2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
    
    	* 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.
    
    gdb/testsuite/ChangeLog:
    2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
    
    	* gdb.base/set-cwd.exp: Make it available on
    	native-extended-gdbserver.
    
    gdb/doc/ChangeLog:
    2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
    
    	* gdb.texinfo (Starting your Program) <The working directory.>:
    	Mention remote debugging.
    	(Working Directory) <Your Program's Working Directory>:
    	Likewise.
    	(Connecting) <Remote Packet>: Add "set-working-dir"
    	and "QSetWorkingDir" to the table.
    	(Remote Protocol) <QSetWorkingDir>: New item, explaining the
    	packet.

Diff:
---
 gdb/ChangeLog                      | 17 ++++++++++++++
 gdb/NEWS                           | 10 ++++++++
 gdb/common/common-inferior.h       |  4 ++++
 gdb/doc/ChangeLog                  | 11 +++++++++
 gdb/doc/gdb.texinfo                | 36 ++++++++++++++++++++++++++---
 gdb/gdbserver/ChangeLog            |  8 +++++++
 gdb/gdbserver/inferiors.c          | 12 ++++++++++
 gdb/gdbserver/server.c             | 32 +++++++++++++++++++++++++-
 gdb/gdbserver/win32-low.c          | 22 +++++++++++++++---
 gdb/infcmd.c                       |  8 +++----
 gdb/remote.c                       | 47 ++++++++++++++++++++++++++++++++++++++
 gdb/testsuite/ChangeLog            |  5 ++++
 gdb/testsuite/gdb.base/set-cwd.exp |  4 ++--
 13 files changed, 203 insertions(+), 13 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ea4fc62..e113e2f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,22 @@
 2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
 
+	* 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) <QSetWorkingDir>: 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  <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.
diff --git a/gdb/NEWS b/gdb/NEWS
index fcf4548..2bad096 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 515a8c0..3dcfda3 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 4ded14a..e3ea4ec 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,6 +1,17 @@
 2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* gdb.texinfo (Starting your Program) <The working directory.>:
+	Mention remote debugging.
+	(Working Directory) <Your Program's Working Directory>:
+	Likewise.
+	(Connecting) <Remote Packet>: Add "set-working-dir"
+	and "QSetWorkingDir" to the table.
+	(Remote Protocol) <QSetWorkingDir>: New item, explaining the
+	packet.
+
+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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a68107d..bfeb7a9 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 25d527b..0bdeaba 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,13 @@
 2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
 
+	* 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  <sergiodj@redhat.com>
+
 	* inferiors.c (current_inferior_cwd): New global variable.
 	(get_inferior_cwd): New function.
 	* inferiors.h (struct process_info) <cwd>: New field.
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 57d9956..154c167 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 c4f1e8d..a959735 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 cc84d15..c11926f 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -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
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index dbdf273..187c71f 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 54d810f..8c47d06 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 b72788b..2a580f4 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,10 @@
 2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
 
+	* gdb.base/set-cwd.exp: Make it available on
+	native-extended-gdbserver.
+
+2017-10-04  Sergio Durigan Junior  <sergiodj@redhat.com>
+
 	* gdb.base/set-cwd.c: New file.
 	* gdb.base/set-cwd.exp: Likewise.
 
diff --git a/gdb/testsuite/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index 0d53648..6b81fbc 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 <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
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]